[Pkg-electronics-commits] [pcb-rnd] 04/05: New upstream version 1.2.1

Bdale Garbee bdale at moszumanska.debian.org
Wed Feb 15 17:08:04 UTC 2017


This is an automated email from the git hooks/post-receive script.

bdale pushed a commit to branch master
in repository pcb-rnd.

commit 08bfa789ca64507c2a05fb429800adc262f996b9
Author: Bdale Garbee <bdale at gag.com>
Date:   Wed Feb 15 10:07:08 2017 -0700

    New upstream version 1.2.1
---
 Changelog                                          |  129 +
 Makefile                                           |    1 -
 Makefile.conf.in                                   |    1 +
 Release_notes                                      |   41 +-
 config.h.in                                        |   24 +-
 doc/TODO                                           |   67 +-
 doc/datasheet.html                                 |   79 +
 doc/developer/bridges/Makefile                     |    2 +
 doc/developer/bridges/bridges.dot                  |   52 +
 doc/developer/bridges/bridges.png                  |  Bin 0 -> 228238 bytes
 doc/developer/hid_gtk3/Makefile                    |    5 +
 doc/developer/hid_gtk3/default.css                 |  358 +
 .../img_route_style/gtk2-edit_route_styles_001.png |  Bin 0 -> 27853 bytes
 .../hid_gtk3/img_route_style/gtk2-pcb-rnd_001.png  |  Bin 0 -> 96687 bytes
 doc/developer/hid_gtk3/index.adoc                  |    9 +
 doc/developer/hid_gtk3/index.html                  |   36 +
 doc/developer/hid_gtk3/route_style.adoc            |  198 +
 doc/developer/hid_gtk3/route_style.html            |  354 +
 doc/developer/hid_remote/proto_high.html           |   44 +-
 doc/developer/mods3/after.png                      |  Bin 0 -> 1783 bytes
 doc/developer/mods3/export.png                     |  Bin 4799 -> 4808 bytes
 doc/developer/mods3/feature.png                    |  Bin 6453 -> 6901 bytes
 doc/developer/mods3/gen.sh                         |    2 +-
 doc/developer/mods3/hid.png                        |  Bin 2140 -> 2432 bytes
 doc/developer/mods3/import.png                     |  Bin 2510 -> 3048 bytes
 doc/developer/mods3/index.html                     |   98 +-
 doc/developer/mods3/io.png                         |  Bin 2051 -> 2040 bytes
 doc/developer/mods3/lib.png                        |  Bin 1487 -> 1701 bytes
 doc/developer/mods3/mods.png                       |  Bin 2714 -> 2616 bytes
 doc/developer/renames                              |    2 +-
 doc/devlog/20170205_schimp.html                    |   35 +
 doc/devlog/20170212_ecosys.html                    |  154 +
 doc/devlog/20170213_edacore1.html                  |  198 +
 doc/devlog/20170213_edacore2.html                  |   57 +
 doc/features/debian.html                           |   16 +-
 doc/help.html                                      |    1 +
 doc/index.html                                     |    5 +-
 doc/license.html                                   |   55 +
 doc/man/Makefile                                   |   38 +-
 doc/man/fp2anim.1.html                             |   22 +-
 doc/man/index.html                                 |    5 +-
 doc/man/pcb-prj2lht.1.html                         |   22 +-
 doc/man/pcb-rnd.1.html                             |   22 +-
 doc/man/pcb-strip.1.html                           |   22 +-
 doc/resources/logo32.xpm                           |  295 +
 doc/resources/logo64.xpm                           |  618 ++
 doc/user/01_intro/history.html                     |   22 +-
 doc/user/01_intro/index.html                       |    6 +-
 doc/user/02_model/index.html                       |   80 +-
 doc/user/04_invoc/index.html                       |    7 +-
 doc/user/05_ui/01_gtk/index.html                   |   23 +-
 doc/user/05_ui/02_cli/index.html                   |    7 +-
 doc/user/05_ui/index.html                          |   15 +-
 doc/user/06_feature/gpmi/index.html                |    5 +
 doc/user/06_feature/gpmi/packages/layout_ref.html  |    5 -
 doc/user/06_feature/gpmi/scripting_intro.html      |   21 +-
 doc/user/08_util/01_gsch2pcb-rnd.htm               |    4 +
 doc/user/08_util/install_cgi.html                  |    5 +
 pcblib/Makefile                                    |    4 +-
 scconfig/Makefile                                  |    9 +-
 scconfig/Rev.h                                     |    2 +-
 scconfig/Rev.tab                                   |   11 +
 scconfig/hooks.c                                   |   44 +-
 scconfig/plugins.h                                 |   16 +-
 scconfig/src/default/find_cc.c                     |    7 +-
 scconfig/src/default/find_libs.c                   |    2 +-
 scconfig/src/default/lib_pkg_config.c              |   69 +-
 scconfig/src/default/lib_try.c                     |    6 +-
 scconfig/src/default/libs.h                        |   60 +-
 scconfig/src/gui/Makefile.plugin                   |    5 +
 scconfig/src/gui/find_cairo.c                      |   70 +
 scconfig/src/gui/find_cairo.h                      |    2 +
 scconfig/src/gui/find_gtk2.c                       |   20 +-
 scconfig/src/gui/find_gtk2.h                       |    2 +-
 scconfig/src/gui/find_gtk3.c                       |   88 +
 scconfig/src/gui/find_gtk3.h                       |    2 +
 scconfig/src/gui/gui.c                             |    5 +
 scconfig/src/util/Makefile                         |    7 +
 scconfig/src/util/sccbox.c                         |  645 ++
 scconfig/template/debug.tmpasm                     |    2 +-
 src/Makefile.dep                                   | 2796 ++++---
 src/Makefile.in                                    |   81 +-
 src/action_helper.c                                |    4 +-
 src/attrib.c                                       |    3 +
 src/board.c                                        |   49 +-
 src/board.h                                        |    8 +-
 src/buffer.c                                       |   38 +-
 src/build_run.c                                    |  141 +-
 src/build_run.h                                    |   10 +-
 src/change_act.c                                   |    1 +
 src/check_icon.data                                |    4 -
 src/compat_dl.c                                    |    3 +-
 src/crosshair.c                                    |  357 +-
 src/data.c                                         |   12 +-
 src/data.h                                         |    8 +-
 src/defpcb_internal.c                              |   51 +
 src/draw.c                                         |  180 +-
 src/draw.h                                         |   13 +
 src/file_act.c                                     |    2 +-
 src/find.c                                         |    4 +-
 src/find_lookup.c                                  |  449 +-
 src/find_misc.c                                    |   12 +-
 src/find_print.c                                   |    2 +-
 src/font.c                                         |   42 +-
 src/font_internal.c                                |  818 ++
 src/global_typedefs.h                              |    2 +-
 src/globalconst.h                                  |   22 +-
 src/gui_act.c                                      |   87 +
 src/hid.h                                          |   44 +-
 src/hid_actions.c                                  |    2 +-
 src/hid_draw_helpers.c                             |   24 +-
 src/hid_extents.c                                  |   10 +-
 src/hid_extents.h                                  |    2 +-
 src/hid_flags.c                                    |    4 +-
 src/hid_helper.c                                   |   31 +-
 src/hid_nogui.c                                    |   12 +-
 src/layer.c                                        |  583 +-
 src/layer.h                                        |  186 +-
 src/layer_grp.c                                    |  622 ++
 src/layer_grp.h                                    |  155 +
 src/layer_it.h                                     |  120 +
 src/layer_vis.c                                    |   38 +-
 src/main.c                                         |   15 +-
 src/math_helper.h                                  |    1 +
 src/obj_arc.c                                      |   62 +-
 src/obj_arc.h                                      |   13 +-
 src/obj_arc_op.h                                   |    1 +
 src/obj_elem.c                                     |   43 +-
 src/obj_elem.h                                     |    3 +
 src/obj_line.c                                     |    5 +-
 src/obj_line.h                                     |   11 +-
 src/obj_line_drcenf.c                              |   19 +-
 src/obj_pad.c                                      |    5 +-
 src/obj_pinvia.c                                   |    6 +-
 src/obj_pinvia_therm.c                             |   24 +-
 src/obj_poly.h                                     |   11 +-
 src/obj_text.c                                     |   11 +-
 src/obj_text.h                                     |    4 +-
 src/object_act.c                                   |    7 +-
 src/pcb-menu-gtk.lht                               |   35 +-
 src/pcb-menu-lesstif.lht                           |   21 +-
 src/pcb-menu-mkey.lht                              |   35 +-
 src/plug_footprint.c                               |    2 +-
 src/plug_io.c                                      |    3 +-
 src/plug_io.h                                      |    3 +-
 src/polygon.c                                      |  134 +-
 src/polygon.h                                      |    2 +-
 src/rats.c                                         |   11 +-
 src/rats.h                                         |    1 +
 src/remove.c                                       |    2 +-
 src/search.c                                       |   13 +-
 src/search.h                                       |    5 +-
 src/select.c                                       |    8 +-
 src/stub_draw_csect.c                              |   54 +
 src/stub_draw_csect.h                              |   33 +
 src_3rd/gensexpr/gensexpr_impl.c                   |    1 +
 src_3rd/gensexpr/gsx_parse.c                       |   13 +
 src_3rd/gensexpr/gsx_parse.h                       |    6 +-
 src_3rd/gts/Makefile.dep                           |   36 -
 src_3rd/gts/Makefile.in                            |   74 -
 src_3rd/gts/bbtree.c                               | 1289 ---
 src_3rd/gts/boolean.c                              | 2048 -----
 src_3rd/gts/cdt.c                                  | 1173 ---
 src_3rd/gts/container.c                            |  493 --
 src_3rd/gts/curvature.c                            |  621 --
 src_3rd/gts/edge.c                                 |  582 --
 src_3rd/gts/eheap.c                                |  461 --
 src_3rd/gts/face.c                                 |  297 -
 src_3rd/gts/fifo.c                                 |  192 -
 src_3rd/gts/graph.c                                | 1776 -----
 src_3rd/gts/gts-private.h                          |   37 -
 src_3rd/gts/gts.h                                  | 2577 ------
 src_3rd/gts/heap.c                                 |  258 -
 src_3rd/gts/hsurface.c                             |  405 -
 src_3rd/gts/iso.c                                  |  455 --
 src_3rd/gts/isotetra.c                             |  840 --
 src_3rd/gts/kdtree.c                               |  152 -
 src_3rd/gts/matrix.c                               |  725 --
 src_3rd/gts/misc.c                                 |  692 --
 src_3rd/gts/named.c                                |  188 -
 src_3rd/gts/object.c                               |  345 -
 src_3rd/gts/oocs.c                                 |  387 -
 src_3rd/gts/partition.c                            | 1219 ---
 src_3rd/gts/pgraph.c                               |  584 --
 src_3rd/gts/point.c                                |  986 ---
 src_3rd/gts/predicates.c                           | 2742 -------
 src_3rd/gts/predicates.h                           |   41 -
 src_3rd/gts/psurface.c                             |  471 --
 src_3rd/gts/refine.c                               |  418 -
 src_3rd/gts/rounding.h                             |   85 -
 src_3rd/gts/segment.c                              |  233 -
 src_3rd/gts/split.c                                | 1840 -----
 src_3rd/gts/stripe.c                               |  766 --
 src_3rd/gts/surface.c                              | 2743 -------
 src_3rd/gts/triangle.c                             | 1094 ---
 src_3rd/gts/tribox3.c                              |  192 -
 src_3rd/gts/vertex.c                               |  780 --
 src_3rd/gts/vopt.c                                 |  521 --
 src_3rd/liblihata/parser.c                         |    3 +-
 src_3rd/liblihata/regression/ref/text.dref         |    1 +
 src_3rd/liblihata/regression/ref/text.eref         |    1 +
 src_3rd/liblihata/regression/text.lht              |    1 +
 src_3rd/qparse/example.c                           |    2 +-
 src_3rd/qparse/qparse.c                            |   42 +-
 src_3rd/qparse/qparse.h                            |    9 +
 src_plugins/Common_enabled.tmpasm                  |    4 +-
 src_plugins/Plugin.tmpasm                          |    2 +-
 src_plugins/autoplace/autoplace.c                  |    8 +-
 src_plugins/autoroute/autoroute.c                  |   86 +-
 src_plugins/boardflip/boardflip.c                  |    2 +-
 src_plugins/diag/diag.c                            |   12 +-
 src_plugins/djopt/djopt.c                          |   49 +-
 src_plugins/draw_csect/Makefile                    |    6 +
 src_plugins/draw_csect/Plug.tmpasm                 |   10 +
 src_plugins/draw_csect/README                      |    5 +
 src_plugins/draw_csect/draw_csect.c                |  709 ++
 src_plugins/draw_fab/draw_fab.c                    |   14 +-
 src_plugins/export_bboard/bboard.c                 |   26 +-
 src_plugins/export_dsn/README                      |    4 +-
 src_plugins/export_dsn/dsn.c                       |   40 +-
 src_plugins/export_dxf/dxf.c                       |   25 +-
 src_plugins/export_fidocadj/Makefile               |    5 +
 src_plugins/export_fidocadj/Plug.tmpasm            |   16 +
 src_plugins/export_fidocadj/README                 |    5 +
 src_plugins/export_fidocadj/fidocadj.c             |  337 +
 src_plugins/export_gcode/gcode.c                   |   20 +-
 src_plugins/export_gerber/gerber.c                 |  106 +-
 src_plugins/export_ipcd356/ipcd356.c               |    8 +-
 src_plugins/export_nelma/nelma.c                   |   22 +-
 src_plugins/export_openscad/scad.c                 |   73 +-
 src_plugins/export_png/png.c                       |  124 +-
 src_plugins/export_ps/eps.c                        |   45 +-
 src_plugins/export_ps/ps.c                         |   25 +-
 src_plugins/export_stat/stat.c                     |  106 +-
 src_plugins/export_svg/svg.c                       |   21 +-
 src_plugins/fontmode/fontmode.c                    |    8 +-
 src_plugins/fp_wget/tester.c                       |    6 +-
 .../gpmi_plugin/gpmi_pkg/hid/hid_callbacks.c       |   14 +-
 .../pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layers.c  |    8 +-
 .../pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layout.h  |    3 -
 src_plugins/hid_batch/batch.c                      |    7 +-
 src_plugins/hid_gtk/Plug.tmpasm                    |   23 +-
 src_plugins/hid_gtk/colors.c                       |   64 +
 src_plugins/hid_gtk/colors.h                       |    4 +
 .../hid_gtk/ghid-cell-renderer-visibility.c        |  257 -
 .../hid_gtk/ghid-cell-renderer-visibility.h        |   21 -
 src_plugins/hid_gtk/ghid-coord-entry.c             |  291 -
 src_plugins/hid_gtk/ghid-coord-entry.h             |   34 -
 src_plugins/hid_gtk/ghid-layer-selector.c          |  807 --
 src_plugins/hid_gtk/ghid-layer-selector.h          |   38 -
 src_plugins/hid_gtk/ghid-main-menu.c               |  163 +-
 src_plugins/hid_gtk/ghid-main-menu.h               |   18 +-
 src_plugins/hid_gtk/ghid-propedit.c                |  561 --
 src_plugins/hid_gtk/ghid-propedit.h                |   44 -
 src_plugins/hid_gtk/ghid-route-style-selector.c    |  868 ---
 src_plugins/hid_gtk/ghid-route-style-selector.h    |   35 -
 src_plugins/hid_gtk/ghid-search.c                  |  857 --
 src_plugins/hid_gtk/ghid-search.h                  |   26 -
 src_plugins/hid_gtk/gtkhid-gdk.c                   |  335 +-
 src_plugins/hid_gtk/gtkhid-gl.c                    |  231 +-
 src_plugins/hid_gtk/gtkhid-main.c                  | 1591 +---
 src_plugins/hid_gtk/gtkhid-main.h                  |   14 +
 src_plugins/hid_gtk/gtkhid.h                       |   14 -
 src_plugins/hid_gtk/gui-command-window.c           |   10 +-
 src_plugins/hid_gtk/gui-config.c                   | 1052 ++-
 src_plugins/hid_gtk/gui-dialog-print.c             |  409 -
 src_plugins/hid_gtk/gui-dialog.c                   |  650 --
 src_plugins/hid_gtk/gui-drc-window.c               |    3 +-
 src_plugins/hid_gtk/gui-icons-misc.data            |   83 +-
 src_plugins/hid_gtk/gui-keyref-window.c            |  353 -
 src_plugins/hid_gtk/gui-library-window.c           |   11 +-
 src_plugins/hid_gtk/gui-log-window.c               |    5 +-
 src_plugins/hid_gtk/gui-misc.c                     |  419 -
 src_plugins/hid_gtk/gui-netlist-window.c           |   12 +-
 src_plugins/hid_gtk/gui-output-events.c            |  291 +-
 src_plugins/hid_gtk/gui-pinout-preview.c           |  295 -
 src_plugins/hid_gtk/gui-pinout-preview.h           |   61 -
 src_plugins/hid_gtk/gui-pinout-window.c            |   87 -
 src_plugins/hid_gtk/gui-top-window.c               |  249 +-
 src_plugins/hid_gtk/gui-utils.c                    |  745 --
 src_plugins/hid_gtk/gui.h                          |  227 +-
 src_plugins/hid_gtk/win_place.c                    |  114 -
 src_plugins/hid_gtk/win_place.h                    |   22 -
 src_plugins/hid_gtk3/README                        |    5 +
 src_plugins/hid_gtk3/colors.c                      |   75 +
 src_plugins/hid_gtk3/colors.h                      |    4 +
 src_plugins/hid_lesstif/dialogs.c                  |  284 +-
 src_plugins/hid_lesstif/dlg_preview.c              |  257 +
 src_plugins/hid_lesstif/main.c                     |  258 +-
 src_plugins/hid_lesstif/menu.c                     |   22 +-
 src_plugins/hid_remote/proto.c                     |   40 +-
 src_plugins/hid_remote/proto.h                     |    8 +-
 src_plugins/hid_remote/proto_lowsend.h             |    2 +-
 src_plugins/hid_remote/remote.c                    |   57 +-
 src_plugins/import_dsn/README                      |    4 +-
 src_plugins/import_dsn/dsn.c                       |  318 +-
 src_plugins/import_hyp/hacking.txt                 |   16 +
 src_plugins/import_hyp/import_hyp.c                |   17 +-
 src_plugins/import_hyp/parser.c                    | 2114 ++++-
 src_plugins/import_hyp/parser.h                    |  412 +-
 src_plugins/import_hyp/tests/gensamp               |  143 +
 src_plugins/import_hyp/tests/samp.hyp              |  134 +
 src_plugins/import_ltspice/Makefile                |    5 +
 src_plugins/import_ltspice/Plug.tmpasm             |    8 +
 src_plugins/import_ltspice/README                  |    5 +
 src_plugins/import_ltspice/ltspice.c               |  323 +
 src_plugins/import_mucs/Makefile                   |    5 +
 src_plugins/import_mucs/Plug.tmpasm                |    8 +
 src_plugins/import_mucs/README                     |    5 +
 src_plugins/import_mucs/mucs.c                     |  160 +
 src_plugins/import_tinycad/Makefile                |    5 +
 src_plugins/import_tinycad/Plug.tmpasm             |    8 +
 src_plugins/import_tinycad/README                  |    5 +
 src_plugins/import_tinycad/tinycad.c               |  207 +
 src_plugins/io_kicad/read.c                        |  210 +-
 src_plugins/io_kicad/write.c                       |    6 +-
 src_plugins/io_kicad_legacy/write.c                |    2 +-
 src_plugins/io_lihata/read.c                       |   71 +-
 src_plugins/io_lihata/write.c                      |   44 +-
 src_plugins/io_lihata/write_style.c                |  179 +-
 src_plugins/io_pcb/attribs.c                       |    2 +
 src_plugins/io_pcb/file.c                          |   45 +-
 src_plugins/io_pcb/parse_y.c                       |   10 +-
 src_plugins/io_pcb/parse_y.y                       |   10 +-
 src_plugins/lib_gtk_common/HACKING                 |   11 +
 src_plugins/lib_gtk_common/Makefile                |    5 +
 src_plugins/lib_gtk_common/Plug.tmpasm             |   67 +
 src_plugins/lib_gtk_common/README                  |    6 +
 src_plugins/lib_gtk_common/act_fileio.c            |  258 +
 src_plugins/lib_gtk_common/act_fileio.h            |   12 +
 src_plugins/lib_gtk_common/act_print.c             |   99 +
 src_plugins/lib_gtk_common/act_print.h             |    9 +
 src_plugins/lib_gtk_common/bu_box.c                |  140 +
 src_plugins/lib_gtk_common/bu_box.h                |   23 +
 src_plugins/lib_gtk_common/bu_check_button.c       |   57 +
 src_plugins/lib_gtk_common/bu_check_button.h       |   10 +
 src_plugins/lib_gtk_common/bu_cursor_pos.c         |  147 +
 src_plugins/lib_gtk_common/bu_cursor_pos.h         |   14 +
 src_plugins/lib_gtk_common/bu_dwg_tooltip.c        |  149 +
 src_plugins/lib_gtk_common/bu_dwg_tooltip.h        |    5 +
 src_plugins/lib_gtk_common/bu_entry.c              |  115 +
 src_plugins/lib_gtk_common/bu_entry.h              |   16 +
 src_plugins/lib_gtk_common/bu_notebook.c           |   56 +
 src_plugins/lib_gtk_common/bu_notebook.h           |    8 +
 src_plugins/lib_gtk_common/bu_spin_button.c        |  123 +
 src_plugins/lib_gtk_common/bu_spin_button.h        |   14 +
 src_plugins/lib_gtk_common/bu_status_line.c        |   69 +
 src_plugins/lib_gtk_common/bu_status_line.h        |   11 +
 src_plugins/lib_gtk_common/bu_text_view.c          |  121 +
 src_plugins/lib_gtk_common/bu_text_view.h          |    5 +
 src_plugins/lib_gtk_common/compat.h                |   53 +
 src_plugins/lib_gtk_common/dlg_about.c             |   90 +
 src_plugins/lib_gtk_common/dlg_about.h             |    4 +
 src_plugins/lib_gtk_common/dlg_attribute.c         |  497 ++
 src_plugins/lib_gtk_common/dlg_attribute.h         |   10 +
 src_plugins/lib_gtk_common/dlg_confirm.c           |  107 +
 src_plugins/lib_gtk_common/dlg_confirm.h           |    6 +
 src_plugins/lib_gtk_common/dlg_export.c            |  105 +
 src_plugins/lib_gtk_common/dlg_export.h            |    7 +
 src_plugins/lib_gtk_common/dlg_file_chooser.c      |  453 ++
 src_plugins/lib_gtk_common/dlg_file_chooser.h      |   12 +
 src_plugins/lib_gtk_common/dlg_input.c             |   81 +
 src_plugins/lib_gtk_common/dlg_input.h             |    3 +
 src_plugins/lib_gtk_common/dlg_message.c           |   58 +
 src_plugins/lib_gtk_common/dlg_message.h           |    3 +
 src_plugins/lib_gtk_common/dlg_pinout.c            |   88 +
 src_plugins/lib_gtk_common/dlg_pinout.h            |   10 +
 src_plugins/lib_gtk_common/dlg_print.c             |   81 +
 src_plugins/lib_gtk_common/dlg_print.h             |    5 +
 src_plugins/lib_gtk_common/dlg_progress.c          |  187 +
 src_plugins/lib_gtk_common/dlg_progress.h          |    3 +
 src_plugins/lib_gtk_common/dlg_propedit.c          |  564 ++
 src_plugins/lib_gtk_common/dlg_propedit.h          |   58 +
 src_plugins/lib_gtk_common/dlg_report.c            |   93 +
 src_plugins/lib_gtk_common/dlg_report.h            |    4 +
 src_plugins/lib_gtk_common/dlg_route_style.c       |  468 ++
 src_plugins/lib_gtk_common/dlg_route_style.h       |   27 +
 src_plugins/lib_gtk_common/dlg_search.c            |  881 +++
 src_plugins/lib_gtk_common/dlg_search.h            |   28 +
 .../dlg_search_tab.h}                              |    0
 src_plugins/lib_gtk_common/in_keyboard.c           |  118 +
 src_plugins/lib_gtk_common/in_keyboard.h           |   37 +
 src_plugins/lib_gtk_common/in_mouse.c              |  392 +
 src_plugins/lib_gtk_common/in_mouse.h              |   45 +
 src_plugins/lib_gtk_common/lib_gtk_common.c        |   34 +
 src_plugins/lib_gtk_common/ui_zoompan.c            |  493 ++
 src_plugins/lib_gtk_common/ui_zoompan.h            |  106 +
 src_plugins/lib_gtk_common/util_block_hook.c       |   78 +
 src_plugins/lib_gtk_common/util_block_hook.h       |    9 +
 .../util_gtk_debug.h}                              |    0
 src_plugins/lib_gtk_common/util_str.c              |   55 +
 src_plugins/lib_gtk_common/util_str.h              |   40 +
 src_plugins/lib_gtk_common/util_timer.c            |   63 +
 src_plugins/lib_gtk_common/util_timer.h            |    7 +
 src_plugins/lib_gtk_common/util_watch.c            |   96 +
 src_plugins/lib_gtk_common/util_watch.h            |   13 +
 src_plugins/lib_gtk_common/win_place.c             |  115 +
 src_plugins/lib_gtk_common/win_place.h             |   26 +
 src_plugins/lib_gtk_common/wt_coord_entry.c        |  302 +
 src_plugins/lib_gtk_common/wt_coord_entry.h        |   49 +
 src_plugins/lib_gtk_common/wt_layer_selector.c     |  704 ++
 src_plugins/lib_gtk_common/wt_layer_selector.h     |  144 +
 src_plugins/lib_gtk_common/wt_layer_selector_cr.c  |  260 +
 src_plugins/lib_gtk_common/wt_layer_selector_cr.h  |   23 +
 src_plugins/lib_gtk_common/wt_preview.c            |  566 ++
 src_plugins/lib_gtk_common/wt_preview.h            |  101 +
 src_plugins/lib_gtk_common/wt_route_style.c        |  371 +
 src_plugins/lib_gtk_common/wt_route_style.h        |  163 +
 src_plugins/plugins_feature.tmpasm                 |    3 +-
 src_plugins/plugins_io.tmpasm                      |    4 +
 src_plugins/puller/puller.c                        |   12 +-
 src_plugins/query/query_access.c                   |    2 +-
 src_plugins/rubberband_orig/rubberband.c           |  160 +-
 src_plugins/teardrops/teardrops.c                  |   12 +-
 src_plugins/toporouter/Makefile                    |    6 -
 src_plugins/toporouter/Plug.tmpasm                 |   28 -
 src_plugins/toporouter/README                      |    7 -
 src_plugins/toporouter/toporouter.c                | 8244 --------------------
 src_plugins/toporouter/toporouter.h                |  489 --
 tests/RTT/Export.sh                                |   78 +-
 tests/RTT/Makefile                                 |   20 +
 tests/RTT/Proto.pcb.text                           |    5 +
 tests/RTT/Vailidation.txt                          |   50 +-
 tests/RTT/arc_angles.pcb.text                      |   19 +
 tests/RTT/arc_f_clear.pcb.text                     |   22 +
 tests/RTT/arc_normal.pcb.text                      |   25 +
 tests/RTT/arc_offpage.pcb.text                     |    5 +
 tests/RTT/arc_sizes.pcb.text                       |   17 +
 tests/RTT/coord_rounding.pcb.text                  |    6 +
 tests/RTT/elem_pads.pcb.text                       |    9 +
 tests/RTT/elem_pads_ds.pcb                         |  332 +-
 tests/RTT/elem_pads_ds.pcb.text                    |   10 +
 tests/RTT/elem_pins.pcb.text                       |   11 +
 tests/RTT/elem_sides_smd.pcb.text                  |    7 +
 tests/RTT/elem_sides_trh.pcb.text                  |   14 +
 tests/RTT/layer_copper.pcb.text                    |    7 +
 tests/RTT/layer_outline.pcb.text                   |    4 +
 tests/RTT/layer_silk.pcb.text                      |    5 +
 tests/RTT/layer_spc.pcb.text                       |    2 +
 tests/RTT/line_f_clear.pcb.text                    |   20 +
 tests/RTT/line_normal.pcb.text                     |   13 +
 tests/RTT/line_offpage.pcb.text                    |    3 +
 tests/RTT/line_overlap1.pcb.text                   |    4 +
 tests/RTT/line_overlap2.pcb.text                   |    4 +
 tests/RTT/line_overlap3.pcb.text                   |    3 +
 tests/RTT/line_overlap4.pcb.text                   |    6 +
 tests/RTT/line_zerolen.pcb.text                    |    1 +
 tests/RTT/netlist.pcb.text                         |    8 +
 tests/RTT/netlist_ba.pcb.text                      |    8 +
 tests/RTT/poly_hole.pcb                            |  338 +-
 tests/RTT/poly_hole.pcb.text                       |   20 +
 tests/RTT/poly_rect.pcb.text                       |   17 +
 tests/RTT/poly_triangle.pcb.text                   |   31 +
 tests/RTT/ref/Proto.bbrd.png                       |  Bin 0 -> 189 bytes
 tests/RTT/ref/Proto.dsn                            |    3 -
 tests/RTT/ref/Proto.eps                            |   31 +
 tests/RTT/ref/Proto.gbr/Proto.fab.gbr              |    4 +-
 tests/RTT/ref/Proto.nelma.em                       |   51 +
 tests/RTT/ref/Proto.png                            |  Bin 163 -> 681 bytes
 tests/RTT/ref/Proto.png.text                       |    5 +
 tests/RTT/ref/Proto.ps.gz                          |  Bin 4503 -> 3760 bytes
 tests/RTT/ref/Proto.remote.gz                      |  Bin 6004 -> 6017 bytes
 tests/RTT/ref/Proto.scad                           |   83 +
 tests/RTT/ref/Proto.svg                            |   12 +-
 tests/RTT/ref/arc_angles.bbrd.png                  |  Bin 0 -> 189 bytes
 tests/RTT/ref/arc_angles.dsn                       |    3 -
 tests/RTT/ref/arc_angles.eps                       |   37 +
 tests/RTT/ref/arc_angles.gbr/arc_angles.fab.gbr    |    4 +-
 tests/RTT/ref/arc_angles.gbr/arc_angles.top.gbr    |    4 +-
 tests/RTT/ref/arc_angles.nelma.em                  |   60 +
 tests/RTT/ref/arc_angles.png                       |  Bin 1494 -> 2216 bytes
 tests/RTT/ref/arc_angles.png.text                  |   20 +-
 tests/RTT/ref/arc_angles.ps.gz                     |  Bin 4755 -> 4009 bytes
 tests/RTT/ref/arc_angles.remote.gz                 |  Bin 6327 -> 6376 bytes
 tests/RTT/ref/arc_angles.scad                      |   83 +
 tests/RTT/ref/arc_angles.svg                       |   20 +-
 tests/RTT/ref/arc_f_clear.bbrd.png                 |  Bin 0 -> 189 bytes
 tests/RTT/ref/arc_f_clear.dsn                      |    3 -
 tests/RTT/ref/arc_f_clear.eps                      |  216 +
 tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.fab.gbr  |    4 +-
 tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.top.gbr  |    4 +-
 tests/RTT/ref/arc_f_clear.nelma.em                 |   60 +
 tests/RTT/ref/arc_f_clear.png                      |  Bin 2873 -> 3528 bytes
 tests/RTT/ref/arc_f_clear.png.text                 |   33 +-
 tests/RTT/ref/arc_f_clear.ps.gz                    |  Bin 5801 -> 5050 bytes
 tests/RTT/ref/arc_f_clear.remote.gz                |  Bin 7620 -> 7671 bytes
 tests/RTT/ref/arc_f_clear.scad                     |   83 +
 tests/RTT/ref/arc_f_clear.svg                      |   20 +-
 tests/RTT/ref/arc_normal.bbrd.png                  |  Bin 0 -> 189 bytes
 tests/RTT/ref/arc_normal.dsn                       |    3 -
 tests/RTT/ref/arc_normal.eps                       |   41 +
 tests/RTT/ref/arc_normal.gbr/arc_normal.fab.gbr    |    4 +-
 tests/RTT/ref/arc_normal.gbr/arc_normal.top.gbr    |    4 +-
 tests/RTT/ref/arc_normal.nelma.em                  |   60 +
 tests/RTT/ref/arc_normal.png                       |  Bin 2475 -> 2997 bytes
 tests/RTT/ref/arc_normal.png.text                  |   21 +-
 tests/RTT/ref/arc_normal.ps.gz                     |  Bin 4867 -> 4113 bytes
 tests/RTT/ref/arc_normal.remote.gz                 |  Bin 6440 -> 6499 bytes
 tests/RTT/ref/arc_normal.scad                      |   83 +
 tests/RTT/ref/arc_normal.svg                       |   20 +-
 tests/RTT/ref/arc_offpage.bbrd.png                 |  Bin 0 -> 189 bytes
 tests/RTT/ref/arc_offpage.dsn                      |    3 -
 tests/RTT/ref/arc_offpage.eps                      |   35 +
 tests/RTT/ref/arc_offpage.gbr/arc_offpage.fab.gbr  |    4 +-
 tests/RTT/ref/arc_offpage.gbr/arc_offpage.top.gbr  |    4 +-
 tests/RTT/ref/arc_offpage.nelma.em                 |   60 +
 tests/RTT/ref/arc_offpage.png                      |  Bin 1264 -> 1810 bytes
 tests/RTT/ref/arc_offpage.png.text                 |   10 +-
 tests/RTT/ref/arc_offpage.ps.gz                    |  Bin 4783 -> 4026 bytes
 tests/RTT/ref/arc_offpage.remote.gz                |  Bin 6331 -> 6333 bytes
 tests/RTT/ref/arc_offpage.scad                     |   83 +
 tests/RTT/ref/arc_offpage.svg                      |   14 +-
 tests/RTT/ref/arc_sizes.bbrd.png                   |  Bin 0 -> 189 bytes
 tests/RTT/ref/arc_sizes.dsn                        |    3 -
 tests/RTT/ref/arc_sizes.eps                        |   37 +
 tests/RTT/ref/arc_sizes.gbr/arc_sizes.fab.gbr      |    4 +-
 tests/RTT/ref/arc_sizes.gbr/arc_sizes.top.gbr      |    4 +-
 tests/RTT/ref/arc_sizes.nelma.em                   |   60 +
 tests/RTT/ref/arc_sizes.png                        |  Bin 809 -> 1458 bytes
 tests/RTT/ref/arc_sizes.png.text                   |   15 +-
 tests/RTT/ref/arc_sizes.ps.gz                      |  Bin 4704 -> 3999 bytes
 tests/RTT/ref/arc_sizes.remote.gz                  |  Bin 6336 -> 6361 bytes
 tests/RTT/ref/arc_sizes.scad                       |   83 +
 tests/RTT/ref/arc_sizes.svg                        |   18 +-
 tests/RTT/ref/clearance.bbrd.png                   |  Bin 0 -> 238 bytes
 tests/RTT/ref/clearance.nelma.em                   |   60 +
 tests/RTT/ref/clearance.png                        |  Bin 771 -> 1511 bytes
 tests/RTT/ref/clearance.png.text                   |   12 +-
 tests/RTT/ref/clearance.ps.gz                      |  Bin 4698 -> 4039 bytes
 tests/RTT/ref/clearance.remote.gz                  |  Bin 6278 -> 6293 bytes
 tests/RTT/ref/clearance.scad                       |   68 +
 tests/RTT/ref/clearance.svg                        |   12 +-
 tests/RTT/ref/coord_rounding.bbrd.png              |  Bin 0 -> 326 bytes
 tests/RTT/ref/coord_rounding.dsn                   |    3 -
 tests/RTT/ref/coord_rounding.eps                   |   36 +
 .../ref/coord_rounding.gbr/coord_rounding.fab.gbr  |    4 +-
 .../ref/coord_rounding.gbr/coord_rounding.top.gbr  |    4 +-
 tests/RTT/ref/coord_rounding.nelma.em              |   60 +
 tests/RTT/ref/coord_rounding.png                   |  Bin 878 -> 1525 bytes
 tests/RTT/ref/coord_rounding.png.text              |    5 +-
 tests/RTT/ref/coord_rounding.ps.gz                 |  Bin 4767 -> 4057 bytes
 tests/RTT/ref/coord_rounding.remote.gz             |  Bin 6459 -> 6384 bytes
 tests/RTT/ref/coord_rounding.scad                  |   83 +
 tests/RTT/ref/coord_rounding.svg                   |   12 +-
 tests/RTT/ref/elem_pads.bbrd.png                   |  Bin 0 -> 189 bytes
 tests/RTT/ref/elem_pads.dsn                        |   11 +-
 tests/RTT/ref/elem_pads.eps                        |   71 +
 tests/RTT/ref/elem_pads.gbr/elem_pads.fab.gbr      |    4 +-
 tests/RTT/ref/elem_pads.gbr/elem_pads.top.gbr      |    4 +-
 tests/RTT/ref/elem_pads.gbr/elem_pads.topmask.gbr  |    4 +-
 tests/RTT/ref/elem_pads.gbr/elem_pads.toppaste.gbr |    4 +-
 tests/RTT/ref/elem_pads.gbr/elem_pads.topsilk.gbr  |    4 +-
 tests/RTT/ref/elem_pads.nelma.em                   |   60 +
 tests/RTT/ref/elem_pads.png                        |  Bin 1244 -> 1905 bytes
 tests/RTT/ref/elem_pads.png.text                   |   13 +
 tests/RTT/ref/elem_pads.ps.gz                      |  Bin 5014 -> 4335 bytes
 tests/RTT/ref/elem_pads.remote.gz                  |  Bin 6721 -> 6636 bytes
 tests/RTT/ref/elem_pads.scad                       |  107 +
 tests/RTT/ref/elem_pads.svg                        |   12 +-
 tests/RTT/ref/elem_pads_ds.bbrd.png                |  Bin 0 -> 189 bytes
 tests/RTT/ref/elem_pads_ds.bom                     |    2 +-
 tests/RTT/ref/elem_pads_ds.dsn                     |    9 +-
 tests/RTT/ref/elem_pads_ds.eps                     |   48 +
 .../ref/elem_pads_ds.gbr/elem_pads_ds.bottom.gbr   |    4 +-
 .../elem_pads_ds.gbr/elem_pads_ds.bottommask.gbr   |    4 +-
 .../elem_pads_ds.gbr/elem_pads_ds.bottompaste.gbr  |    8 +-
 .../RTT/ref/elem_pads_ds.gbr/elem_pads_ds.fab.gbr  |   88 +-
 .../RTT/ref/elem_pads_ds.gbr/elem_pads_ds.top.gbr  |    4 +-
 .../ref/elem_pads_ds.gbr/elem_pads_ds.topmask.gbr  |    4 +-
 .../ref/elem_pads_ds.gbr/elem_pads_ds.toppaste.gbr |    8 +-
 .../ref/elem_pads_ds.gbr/elem_pads_ds.topsilk.gbr  |   12 +-
 tests/RTT/ref/elem_pads_ds.nelma.em                |   75 +
 tests/RTT/ref/elem_pads_ds.net                     |   14 +
 tests/RTT/ref/elem_pads_ds.png                     |  Bin 1456 -> 1636 bytes
 tests/RTT/ref/elem_pads_ds.png.text                |   14 +
 tests/RTT/ref/elem_pads_ds.ps.gz                   |  Bin 4769 -> 4188 bytes
 tests/RTT/ref/elem_pads_ds.remote.gz               |  Bin 6381 -> 6368 bytes
 tests/RTT/ref/elem_pads_ds.scad                    |   91 +
 tests/RTT/ref/elem_pads_ds.svg                     |   19 +-
 tests/RTT/ref/elem_pads_ds.xy                      |    2 +-
 tests/RTT/ref/elem_pins.bbrd.png                   |  Bin 0 -> 189 bytes
 tests/RTT/ref/elem_pins.dsn                        |   11 +-
 tests/RTT/ref/elem_pins.eps                        |  176 +
 .../RTT/ref/elem_pins.gbr/elem_pins.bottommask.gbr |    4 +-
 tests/RTT/ref/elem_pins.gbr/elem_pins.fab.gbr      |  108 +-
 tests/RTT/ref/elem_pins.gbr/elem_pins.topmask.gbr  |    4 +-
 tests/RTT/ref/elem_pins.nelma.em                   |   51 +
 tests/RTT/ref/elem_pins.png                        |  Bin 3181 -> 3942 bytes
 tests/RTT/ref/elem_pins.png.text                   |   17 +
 tests/RTT/ref/elem_pins.ps.gz                      |  Bin 5488 -> 4753 bytes
 tests/RTT/ref/elem_pins.remote.gz                  |  Bin 7184 -> 7187 bytes
 tests/RTT/ref/elem_pins.scad                       |  191 +
 tests/RTT/ref/elem_pins.svg                        |   18 +-
 tests/RTT/ref/elem_sides_smd.bbrd.png              |  Bin 0 -> 189 bytes
 tests/RTT/ref/elem_sides_smd.dsn                   |   11 +-
 tests/RTT/ref/elem_sides_smd.eps                   |   55 +
 .../elem_sides_smd.gbr/elem_sides_smd.bottom.gbr   |    4 +-
 .../elem_sides_smd.bottommask.gbr                  |    4 +-
 .../elem_sides_smd.bottompaste.gbr                 |    4 +-
 .../elem_sides_smd.bottomsilk.gbr                  |    4 +-
 .../ref/elem_sides_smd.gbr/elem_sides_smd.fab.gbr  |    4 +-
 .../ref/elem_sides_smd.gbr/elem_sides_smd.top.gbr  |    4 +-
 .../elem_sides_smd.gbr/elem_sides_smd.topmask.gbr  |    4 +-
 .../elem_sides_smd.gbr/elem_sides_smd.toppaste.gbr |    4 +-
 .../elem_sides_smd.gbr/elem_sides_smd.topsilk.gbr  |    4 +-
 tests/RTT/ref/elem_sides_smd.nelma.em              |   75 +
 tests/RTT/ref/elem_sides_smd.png                   |  Bin 1704 -> 1702 bytes
 tests/RTT/ref/elem_sides_smd.png.text              |   10 +
 tests/RTT/ref/elem_sides_smd.ps.gz                 |  Bin 4993 -> 4343 bytes
 tests/RTT/ref/elem_sides_smd.remote.gz             |  Bin 6647 -> 6606 bytes
 tests/RTT/ref/elem_sides_smd.scad                  |  110 +
 tests/RTT/ref/elem_sides_smd.svg                   |   12 +-
 tests/RTT/ref/elem_sides_trh.bbrd.png              |  Bin 0 -> 189 bytes
 tests/RTT/ref/elem_sides_trh.dsn                   |   11 +-
 tests/RTT/ref/elem_sides_trh.eps                   |   95 +
 .../elem_sides_trh.bottommask.gbr                  |    4 +-
 .../ref/elem_sides_trh.gbr/elem_sides_trh.fab.gbr  |  108 +-
 .../elem_sides_trh.gbr/elem_sides_trh.topmask.gbr  |    4 +-
 tests/RTT/ref/elem_sides_trh.nelma.em              |   51 +
 tests/RTT/ref/elem_sides_trh.png                   |  Bin 2073 -> 2891 bytes
 tests/RTT/ref/elem_sides_trh.png.text              |   17 +
 tests/RTT/ref/elem_sides_trh.ps.gz                 |  Bin 5360 -> 4633 bytes
 tests/RTT/ref/elem_sides_trh.remote.gz             |  Bin 7122 -> 7119 bytes
 tests/RTT/ref/elem_sides_trh.scad                  |  191 +
 tests/RTT/ref/elem_sides_trh.svg                   |   16 +-
 tests/RTT/ref/layer_copper.bbrd.png                |  Bin 0 -> 906 bytes
 tests/RTT/ref/layer_copper.dsn                     |    3 -
 tests/RTT/ref/layer_copper.eps                     |   39 +
 .../ref/layer_copper.gbr/layer_copper.bottom.gbr   |    8 +-
 .../RTT/ref/layer_copper.gbr/layer_copper.fab.gbr  |    4 +-
 .../ref/layer_copper.gbr/layer_copper.group2.gbr   |   14 -
 .../ref/layer_copper.gbr/layer_copper.group5.gbr   |   14 +
 .../RTT/ref/layer_copper.gbr/layer_copper.top.gbr  |    4 +-
 tests/RTT/ref/layer_copper.nelma.em                |   90 +
 tests/RTT/ref/layer_copper.png                     |  Bin 2288 -> 2276 bytes
 tests/RTT/ref/layer_copper.png.text                |   11 +
 tests/RTT/ref/layer_copper.ps.gz                   |  Bin 4792 -> 4096 bytes
 tests/RTT/ref/layer_copper.remote.gz               |  Bin 6378 -> 6334 bytes
 tests/RTT/ref/layer_copper.scad                    |   83 +
 tests/RTT/ref/layer_copper.svg                     |   12 +-
 tests/RTT/ref/layer_outline.bbrd.png               |  Bin 0 -> 189 bytes
 tests/RTT/ref/layer_outline.dsn                    |    3 -
 tests/RTT/ref/layer_outline.eps                    |   38 +
 .../ref/layer_outline.gbr/layer_outline.fab.gbr    |    4 +-
 .../layer_outline.gbr/layer_outline.outline.gbr    |    4 +-
 tests/RTT/ref/layer_outline.nelma.em               |   60 +
 tests/RTT/ref/layer_outline.png                    |  Bin 1908 -> 1907 bytes
 tests/RTT/ref/layer_outline.png.text               |    6 +
 tests/RTT/ref/layer_outline.ps.gz                  |  Bin 3551 -> 2839 bytes
 tests/RTT/ref/layer_outline.remote.gz              |  Bin 4335 -> 4315 bytes
 tests/RTT/ref/layer_outline.scad                   |   83 +
 tests/RTT/ref/layer_outline.svg                    |   12 +-
 tests/RTT/ref/layer_silk.bbrd.png                  |  Bin 0 -> 189 bytes
 tests/RTT/ref/layer_silk.dsn                       |    3 -
 tests/RTT/ref/layer_silk.eps                       |   35 +
 .../ref/layer_silk.gbr/layer_silk.bottomsilk.gbr   |    4 +-
 tests/RTT/ref/layer_silk.gbr/layer_silk.fab.gbr    |    4 +-
 .../RTT/ref/layer_silk.gbr/layer_silk.topsilk.gbr  |    4 +-
 tests/RTT/ref/layer_silk.nelma.em                  |   51 +
 tests/RTT/ref/layer_silk.png                       |  Bin 722 -> 774 bytes
 tests/RTT/ref/layer_silk.png.text                  |    8 +-
 tests/RTT/ref/layer_silk.ps.gz                     |  Bin 4638 -> 3977 bytes
 tests/RTT/ref/layer_silk.remote.gz                 |  Bin 6216 -> 6172 bytes
 tests/RTT/ref/layer_silk.scad                      |   85 +
 tests/RTT/ref/layer_silk.svg                       |   12 +-
 tests/RTT/ref/layer_spc.bbrd.png                   |  Bin 0 -> 189 bytes
 tests/RTT/ref/layer_spc.eps                        |   32 +
 tests/RTT/ref/layer_spc.gbr/layer_spc.fab.gbr      |    4 +-
 tests/RTT/ref/layer_spc.nelma.em                   |   51 +
 tests/RTT/ref/layer_spc.png                        |  Bin 163 -> 163 bytes
 tests/RTT/ref/layer_spc.png.text                   |    4 +
 tests/RTT/ref/layer_spc.ps.gz                      |  Bin 4813 -> 4071 bytes
 tests/RTT/ref/layer_spc.remote.gz                  |  Bin 6505 -> 6488 bytes
 tests/RTT/ref/layer_spc.scad                       |   83 +
 tests/RTT/ref/layer_spc.svg                        |   12 +-
 tests/RTT/ref/line_f_clear.bbrd.png                |  Bin 0 -> 568 bytes
 tests/RTT/ref/line_f_clear.dsn                     |    3 -
 tests/RTT/ref/line_f_clear.eps                     |  144 +
 .../RTT/ref/line_f_clear.gbr/line_f_clear.fab.gbr  |    4 +-
 .../RTT/ref/line_f_clear.gbr/line_f_clear.top.gbr  |    4 +-
 tests/RTT/ref/line_f_clear.nelma.em                |   60 +
 tests/RTT/ref/line_f_clear.png                     |  Bin 1519 -> 2476 bytes
 tests/RTT/ref/line_f_clear.png.text                |   19 +-
 tests/RTT/ref/line_f_clear.ps.gz                   |  Bin 5278 -> 4537 bytes
 tests/RTT/ref/line_f_clear.remote.gz               |  Bin 6936 -> 6901 bytes
 tests/RTT/ref/line_f_clear.scad                    |   83 +
 tests/RTT/ref/line_f_clear.svg                     |   12 +-
 tests/RTT/ref/line_normal.bbrd.png                 |  Bin 0 -> 568 bytes
 tests/RTT/ref/line_normal.dsn                      |    3 -
 tests/RTT/ref/line_normal.eps                      |   41 +
 tests/RTT/ref/line_normal.gbr/line_normal.fab.gbr  |    4 +-
 tests/RTT/ref/line_normal.gbr/line_normal.top.gbr  |    4 +-
 tests/RTT/ref/line_normal.nelma.em                 |   60 +
 tests/RTT/ref/line_normal.png                      |  Bin 1560 -> 2170 bytes
 tests/RTT/ref/line_normal.png.text                 |   13 +
 tests/RTT/ref/line_normal.ps.gz                    |  Bin 4819 -> 4081 bytes
 tests/RTT/ref/line_normal.remote.gz                |  Bin 6429 -> 6371 bytes
 tests/RTT/ref/line_normal.scad                     |   83 +
 tests/RTT/ref/line_normal.svg                      |   12 +-
 tests/RTT/ref/line_offpage.bbrd.png                |  Bin 0 -> 227 bytes
 tests/RTT/ref/line_offpage.dsn                     |    3 -
 tests/RTT/ref/line_offpage.eps                     |   35 +
 .../RTT/ref/line_offpage.gbr/line_offpage.fab.gbr  |    4 +-
 .../RTT/ref/line_offpage.gbr/line_offpage.top.gbr  |    4 +-
 tests/RTT/ref/line_offpage.nelma.em                |   60 +
 tests/RTT/ref/line_offpage.png                     |  Bin 739 -> 1385 bytes
 tests/RTT/ref/line_offpage.png.text                |    5 +
 tests/RTT/ref/line_offpage.ps.gz                   |  Bin 4848 -> 4104 bytes
 tests/RTT/ref/line_offpage.remote.gz               |  Bin 6544 -> 6482 bytes
 tests/RTT/ref/line_offpage.scad                    |   83 +
 tests/RTT/ref/line_offpage.svg                     |   12 +-
 tests/RTT/ref/line_overlap1.bbrd.png               |  Bin 0 -> 230 bytes
 tests/RTT/ref/line_overlap1.dsn                    |    3 -
 tests/RTT/ref/line_overlap1.eps                    |   36 +
 .../ref/line_overlap1.gbr/line_overlap1.fab.gbr    |    4 +-
 .../ref/line_overlap1.gbr/line_overlap1.top.gbr    |    4 +-
 tests/RTT/ref/line_overlap1.nelma.em               |   60 +
 tests/RTT/ref/line_overlap1.png                    |  Bin 771 -> 1409 bytes
 tests/RTT/ref/line_overlap1.png.text               |    8 +
 tests/RTT/ref/line_overlap1.ps.gz                  |  Bin 4733 -> 3994 bytes
 tests/RTT/ref/line_overlap1.remote.gz              |  Bin 6354 -> 6288 bytes
 tests/RTT/ref/line_overlap1.scad                   |   83 +
 tests/RTT/ref/line_overlap1.svg                    |   12 +-
 tests/RTT/ref/line_overlap2.bbrd.png               |  Bin 0 -> 229 bytes
 tests/RTT/ref/line_overlap2.dsn                    |    3 -
 tests/RTT/ref/line_overlap2.eps                    |   36 +
 .../ref/line_overlap2.gbr/line_overlap2.fab.gbr    |    4 +-
 .../ref/line_overlap2.gbr/line_overlap2.top.gbr    |    4 +-
 tests/RTT/ref/line_overlap2.nelma.em               |   60 +
 tests/RTT/ref/line_overlap2.png                    |  Bin 765 -> 1408 bytes
 tests/RTT/ref/line_overlap2.png.text               |    6 +
 tests/RTT/ref/line_overlap2.ps.gz                  |  Bin 4794 -> 4053 bytes
 tests/RTT/ref/line_overlap2.remote.gz              |  Bin 6445 -> 6368 bytes
 tests/RTT/ref/line_overlap2.scad                   |   83 +
 tests/RTT/ref/line_overlap2.svg                    |   12 +-
 tests/RTT/ref/line_overlap3.bbrd.png               |  Bin 0 -> 228 bytes
 tests/RTT/ref/line_overlap3.dsn                    |    3 -
 tests/RTT/ref/line_overlap3.eps                    |   36 +
 .../ref/line_overlap3.gbr/line_overlap3.fab.gbr    |    4 +-
 .../ref/line_overlap3.gbr/line_overlap3.top.gbr    |    4 +-
 tests/RTT/ref/line_overlap3.nelma.em               |   60 +
 tests/RTT/ref/line_overlap3.png                    |  Bin 765 -> 1408 bytes
 tests/RTT/ref/line_overlap3.png.text               |    5 +
 tests/RTT/ref/line_overlap3.ps.gz                  |  Bin 4734 -> 3993 bytes
 tests/RTT/ref/line_overlap3.remote.gz              |  Bin 6351 -> 6281 bytes
 tests/RTT/ref/line_overlap3.scad                   |   83 +
 tests/RTT/ref/line_overlap3.svg                    |   12 +-
 tests/RTT/ref/line_overlap4.bbrd.png               |  Bin 0 -> 229 bytes
 tests/RTT/ref/line_overlap4.dsn                    |    3 -
 tests/RTT/ref/line_overlap4.eps                    |   66 +
 .../ref/line_overlap4.gbr/line_overlap4.fab.gbr    |    4 +-
 .../ref/line_overlap4.gbr/line_overlap4.top.gbr    |    4 +-
 tests/RTT/ref/line_overlap4.nelma.em               |   60 +
 tests/RTT/ref/line_overlap4.png                    |  Bin 827 -> 1514 bytes
 tests/RTT/ref/line_overlap4.png.text               |    6 +
 tests/RTT/ref/line_overlap4.ps.gz                  |  Bin 5038 -> 4301 bytes
 tests/RTT/ref/line_overlap4.remote.gz              |  Bin 6843 -> 6787 bytes
 tests/RTT/ref/line_overlap4.scad                   |   83 +
 tests/RTT/ref/line_overlap4.svg                    |   12 +-
 tests/RTT/ref/line_zerolen.bbrd.png                |  Bin 0 -> 214 bytes
 tests/RTT/ref/line_zerolen.dsn                     |    3 -
 tests/RTT/ref/line_zerolen.eps                     |   35 +
 .../RTT/ref/line_zerolen.gbr/line_zerolen.fab.gbr  |    4 +-
 .../RTT/ref/line_zerolen.gbr/line_zerolen.top.gbr  |    4 +-
 tests/RTT/ref/line_zerolen.nelma.em                |   60 +
 tests/RTT/ref/line_zerolen.png                     |  Bin 788 -> 1410 bytes
 tests/RTT/ref/line_zerolen.png.text                |    1 +
 tests/RTT/ref/line_zerolen.ps.gz                   |  Bin 4710 -> 3962 bytes
 tests/RTT/ref/line_zerolen.remote.gz               |  Bin 6261 -> 6208 bytes
 tests/RTT/ref/line_zerolen.scad                    |   83 +
 tests/RTT/ref/line_zerolen.svg                     |   12 +-
 tests/RTT/ref/netlist.bbrd.png                     |  Bin 0 -> 189 bytes
 tests/RTT/ref/netlist.dsn                          |    7 +-
 tests/RTT/ref/netlist.eps                          |   95 +
 tests/RTT/ref/netlist.gbr/netlist.bottommask.gbr   |    4 +-
 tests/RTT/ref/netlist.gbr/netlist.fab.gbr          |  108 +-
 tests/RTT/ref/netlist.gbr/netlist.topmask.gbr      |    4 +-
 tests/RTT/ref/netlist.nelma.em                     |   61 +
 tests/RTT/ref/netlist.png                          |  Bin 2179 -> 2989 bytes
 tests/RTT/ref/netlist.png.text                     |   15 +
 tests/RTT/ref/netlist.ps.gz                        |  Bin 5253 -> 4498 bytes
 tests/RTT/ref/netlist.remote.gz                    |  Bin 6880 -> 6863 bytes
 tests/RTT/ref/netlist.scad                         |  139 +
 tests/RTT/ref/netlist.svg                          |   16 +-
 tests/RTT/ref/netlist_ba.bbrd.png                  |  Bin 0 -> 189 bytes
 tests/RTT/ref/netlist_ba.dsn                       |    7 +-
 tests/RTT/ref/netlist_ba.eps                       |   95 +
 .../ref/netlist_ba.gbr/netlist_ba.bottommask.gbr   |    4 +-
 tests/RTT/ref/netlist_ba.gbr/netlist_ba.fab.gbr    |  108 +-
 .../RTT/ref/netlist_ba.gbr/netlist_ba.topmask.gbr  |    4 +-
 tests/RTT/ref/netlist_ba.nelma.em                  |   61 +
 tests/RTT/ref/netlist_ba.png                       |  Bin 2179 -> 2989 bytes
 tests/RTT/ref/netlist_ba.png.text                  |   15 +
 tests/RTT/ref/netlist_ba.ps.gz                     |  Bin 5458 -> 4702 bytes
 tests/RTT/ref/netlist_ba.remote.gz                 |  Bin 7309 -> 7282 bytes
 tests/RTT/ref/netlist_ba.scad                      |  139 +
 tests/RTT/ref/netlist_ba.svg                       |   16 +-
 tests/RTT/ref/poly_hole.bbrd.png                   |  Bin 0 -> 189 bytes
 tests/RTT/ref/poly_hole.dsn                        |    3 -
 tests/RTT/ref/poly_hole.eps                        |  112 +
 tests/RTT/ref/poly_hole.gbr/poly_hole.fab.gbr      |    4 +-
 tests/RTT/ref/poly_hole.gbr/poly_hole.top.gbr      |    4 +-
 tests/RTT/ref/poly_hole.nelma.em                   |   60 +
 tests/RTT/ref/poly_hole.png                        |  Bin 3254 -> 4129 bytes
 tests/RTT/ref/poly_hole.png.text                   |   18 +
 tests/RTT/ref/poly_hole.ps.gz                      |  Bin 4814 -> 4082 bytes
 tests/RTT/ref/poly_hole.remote.gz                  |  Bin 6497 -> 6438 bytes
 tests/RTT/ref/poly_hole.scad                       |   83 +
 tests/RTT/ref/poly_hole.svg                        |   12 +-
 tests/RTT/ref/poly_rect.bbrd.png                   |  Bin 0 -> 189 bytes
 tests/RTT/ref/poly_rect.dsn                        |    3 -
 tests/RTT/ref/poly_rect.eps                        |   54 +
 tests/RTT/ref/poly_rect.gbr/poly_rect.fab.gbr      |    4 +-
 tests/RTT/ref/poly_rect.gbr/poly_rect.top.gbr      |    4 +-
 tests/RTT/ref/poly_rect.nelma.em                   |   60 +
 tests/RTT/ref/poly_rect.png                        |  Bin 569 -> 1388 bytes
 tests/RTT/ref/poly_rect.png.text                   |   17 +
 tests/RTT/ref/poly_rect.ps.gz                      |  Bin 4775 -> 4038 bytes
 tests/RTT/ref/poly_rect.remote.gz                  |  Bin 6345 -> 6282 bytes
 tests/RTT/ref/poly_rect.scad                       |   83 +
 tests/RTT/ref/poly_rect.svg                        |   12 +-
 tests/RTT/ref/poly_triangle.bbrd.png               |  Bin 0 -> 189 bytes
 tests/RTT/ref/poly_triangle.dsn                    |    3 -
 tests/RTT/ref/poly_triangle.eps                    |   50 +
 .../ref/poly_triangle.gbr/poly_triangle.fab.gbr    |    4 +-
 .../ref/poly_triangle.gbr/poly_triangle.top.gbr    |    4 +-
 tests/RTT/ref/poly_triangle.nelma.em               |   60 +
 tests/RTT/ref/poly_triangle.png                    |  Bin 2841 -> 3751 bytes
 tests/RTT/ref/poly_triangle.png.text               |   30 +-
 tests/RTT/ref/poly_triangle.ps.gz                  |  Bin 4757 -> 4022 bytes
 tests/RTT/ref/poly_triangle.remote.gz              |  Bin 6330 -> 6269 bytes
 tests/RTT/ref/poly_triangle.scad                   |   83 +
 tests/RTT/ref/poly_triangle.svg                    |   12 +-
 tests/RTT/ref/rat.bbrd.png                         |  Bin 0 -> 189 bytes
 tests/RTT/ref/rat.dsn                              |    3 -
 tests/RTT/ref/rat.eps                              |   31 +
 tests/RTT/ref/rat.gbr/rat.fab.gbr                  |    4 +-
 tests/RTT/ref/rat.nelma.em                         |   51 +
 tests/RTT/ref/rat.png                              |  Bin 163 -> 681 bytes
 tests/RTT/ref/rat.png.text                         |    6 +
 tests/RTT/ref/rat.ps.gz                            |  Bin 4487 -> 3753 bytes
 tests/RTT/ref/rat.remote.gz                        |  Bin 6038 -> 5979 bytes
 tests/RTT/ref/rat.scad                             |   83 +
 tests/RTT/ref/rat.svg                              |   12 +-
 tests/RTT/ref/text_rot.bbrd.png                    |  Bin 0 -> 189 bytes
 tests/RTT/ref/text_rot.dsn                         |    3 -
 tests/RTT/ref/text_rot.eps                         |   81 +
 tests/RTT/ref/text_rot.gbr/text_rot.fab.gbr        |    4 +-
 tests/RTT/ref/text_rot.gbr/text_rot.topsilk.gbr    |    4 +-
 tests/RTT/ref/text_rot.nelma.em                    |   51 +
 tests/RTT/ref/text_rot.png                         |  Bin 1751 -> 1755 bytes
 tests/RTT/ref/text_rot.png.text                    |   13 +
 tests/RTT/ref/text_rot.ps.gz                       |  Bin 4049 -> 3596 bytes
 tests/RTT/ref/text_rot.remote.gz                   |  Bin 5378 -> 5548 bytes
 tests/RTT/ref/text_rot.scad                        |  130 +
 tests/RTT/ref/text_rot.svg                         |   12 +-
 tests/RTT/ref/text_scale.bbrd.png                  |  Bin 0 -> 189 bytes
 tests/RTT/ref/text_scale.dsn                       |    3 -
 tests/RTT/ref/text_scale.eps                       |   73 +
 tests/RTT/ref/text_scale.gbr/text_scale.fab.gbr    |    4 +-
 .../RTT/ref/text_scale.gbr/text_scale.topsilk.gbr  |    4 +-
 tests/RTT/ref/text_scale.nelma.em                  |   51 +
 tests/RTT/ref/text_scale.png                       |  Bin 1737 -> 1682 bytes
 tests/RTT/ref/text_scale.png.text                  |   30 +-
 tests/RTT/ref/text_scale.ps.gz                     |  Bin 4034 -> 3597 bytes
 tests/RTT/ref/text_scale.remote.gz                 |  Bin 5390 -> 5560 bytes
 tests/RTT/ref/text_scale.scad                      |  121 +
 tests/RTT/ref/text_scale.svg                       |   12 +-
 tests/RTT/ref/text_sides.bbrd.png                  |  Bin 0 -> 189 bytes
 tests/RTT/ref/text_sides.dsn                       |    3 -
 tests/RTT/ref/text_sides.eps                       |   43 +
 .../ref/text_sides.gbr/text_sides.bottomsilk.gbr   |    4 +-
 tests/RTT/ref/text_sides.gbr/text_sides.fab.gbr    |    4 +-
 .../RTT/ref/text_sides.gbr/text_sides.topsilk.gbr  |    4 +-
 tests/RTT/ref/text_sides.nelma.em                  |   51 +
 tests/RTT/ref/text_sides.png                       |  Bin 904 -> 902 bytes
 tests/RTT/ref/text_sides.png.text                  |    8 +
 tests/RTT/ref/text_sides.ps.gz                     |  Bin 3756 -> 3505 bytes
 tests/RTT/ref/text_sides.remote.gz                 |  Bin 5161 -> 5261 bytes
 tests/RTT/ref/text_sides.scad                      |  104 +
 tests/RTT/ref/text_sides.svg                       |   12 +-
 tests/RTT/ref/thermal_last.bbrd.png                |  Bin 0 -> 189 bytes
 tests/RTT/ref/thermal_last.dsn                     |    9 +-
 tests/RTT/ref/thermal_last.eps                     |  195 +
 .../RTT/ref/thermal_last.gbr/thermal_last.fab.gbr  |    4 +-
 .../ref/thermal_last.gbr/thermal_last.group2.gbr   |   58 -
 .../ref/thermal_last.gbr/thermal_last.group3.gbr   |  118 -
 .../ref/thermal_last.gbr/thermal_last.group5.gbr   |   58 +
 .../ref/thermal_last.gbr/thermal_last.group7.gbr   |  118 +
 tests/RTT/ref/thermal_last.nelma.em                |   75 +
 tests/RTT/ref/thermal_last.png                     |  Bin 2182 -> 2049 bytes
 tests/RTT/ref/thermal_last.png.text                |   10 +
 tests/RTT/ref/thermal_last.ps.gz                   |  Bin 15871 -> 15014 bytes
 tests/RTT/ref/thermal_last.remote.gz               |  Bin 18910 -> 19126 bytes
 tests/RTT/ref/thermal_last.scad                    |   90 +
 tests/RTT/ref/thermal_last.svg                     |   14 +-
 tests/RTT/ref/thermal_layer.bbrd.png               |  Bin 0 -> 189 bytes
 tests/RTT/ref/thermal_layer.dsn                    |   21 +-
 tests/RTT/ref/thermal_layer.eps                    |  417 +
 .../ref/thermal_layer.gbr/thermal_layer.bottom.gbr |    4 +-
 .../ref/thermal_layer.gbr/thermal_layer.fab.gbr    |    4 +-
 .../ref/thermal_layer.gbr/thermal_layer.top.gbr    |    4 +-
 tests/RTT/ref/thermal_layer.nelma.em               |   75 +
 tests/RTT/ref/thermal_layer.png                    |  Bin 3630 -> 3421 bytes
 tests/RTT/ref/thermal_layer.png.text               |   10 +
 tests/RTT/ref/thermal_layer.ps.gz                  |  Bin 7151 -> 6468 bytes
 tests/RTT/ref/thermal_layer.remote.gz              |  Bin 9025 -> 9017 bytes
 tests/RTT/ref/thermal_layer.scad                   |   90 +
 tests/RTT/ref/thermal_layer.svg                    |   14 +-
 tests/RTT/text_rot.pcb.text                        |   14 +
 tests/RTT/text_scale.pcb.text                      |   26 +
 tests/RTT/text_sides.pcb.text                      |    5 +
 tests/RTT/thermal_last.pcb.text                    |    8 +
 tests/RTT/thermal_layer.pcb.text                   |    8 +
 util/Makefile                                      |   34 +-
 util/devhelpers/chgstat.sh                         |    6 +-
 util/devhelpers/font2c.sh                          |   96 +
 util/gsch2pcb-rnd/Makefile.in                      |   57 +-
 util/gsch2pcb-rnd/glue.c                           |   10 +
 util/gsch2pcb-rnd/gsch2pcb.c                       |   11 +-
 util/gsch2pcb-rnd/gsch2pcb.h                       |    3 -
 util/gsch2pcb-rnd/method_import.c                  |   11 +-
 util/gsch2pcb-rnd/method_pcb.c                     |   17 +-
 util/gsch2pcb-rnd/netlister.c                      |    3 +-
 924 files changed, 37473 insertions(+), 55347 deletions(-)

diff --git a/Changelog b/Changelog
index f6cda84..fb8b8f2 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,132 @@
+pcb-rnd 1.2.1 (r6916)
+~~~~~~~~~~~~~~~~~~~~~
+	[layer]
+		-Cleanup: better layer group support; clear separation of physical and logical layers; real and explicit layer stack concept
+		-Fix: remove silk and component and solder assumptuion from crosshair and search
+		-Fix: auto enforce drc only on copper layers, remove silk assumption
+		-Fix: autorouter refuses to route on outline; also remove silk assumptions
+		-Fix: teardrop works only on copper layers
+		-Add: cross-section view: an userfriendly, a common, HID-independent mechanism for layer group edit
+
+	[random i/o and the ecosystem concept]
+		-Add: export_fidocadj
+		-Rewrite: import_dsn, proper parser
+		-Add: import_ltspice
+		-Add: import_mucs
+		-Add: import_tinycad
+		-Add: import_ltspice: parse a mentor netlist
+		-Workaround: SVG: near-360 degree arcs break some of the rendering engines
+
+	[core]
+		-Add: accept # comments in action scripts
+		-Add: self contained pcb-rnd executable: embedded font and default.pcb
+		-Fix: Draw the correct pin/via shape when the SQUARE flag is set in thin-draw mode
+		-Fix: NoHolesValid cache bit set bug that made silk polys disappear
+		-Fix: do not attempt to calculate bbox of empty elements - throw an error instead and ignore the element (or even assert, in --debug)
+		-Fix: don't depend on layer name for outline
+		-Fix: don't let negative clearance happen
+		-Fix: layer max assert off-by-1 - really allow 16 layers
+		-Fix: polygon arc rounding error when drawing clearance around a pad
+		-Fix: polygon drawn using the poly tool caused crash on save due to overwriting the list-administration when copying corsshair-poly to newly allocated layer poly
+		-Fix: redraw after pin number/name change to get the change displayed
+		-Fix: refuse to create attribute with NULL or empty name
+		-Fix: remove arc endpoint should remove the arc, just like with lines
+		-Fix: when deriving default file name of the board, don't truncate hardwired .pcb, try all io's file extensions until the first that is there
+
+	[arc]
+		-Fix: arc-in-box macro uses the real bounding box of arcs so an arc can be selected by a positive selection box just barely embedding it
+
+	[doc]
+		-Fix: html validation and cleanups
+
+	[drc]
+		-Add: Draw DRC outline of pads when enabled
+		-Fix: Draw DRC outline when moving lines
+		-Fix: Improve the drawing of the DRC outline around pins and vias
+		-Fix: When moving an Arc, draw the DRC outline if enabled. Draw the Arc as an outline instead of thin
+		-Fix: When moving vias, draw the DRC outline when enabled 
+
+	[dynstyle]
+		-Fix: when a new style is created, the gtk-side cache needs to be regenerated
+
+
+	[export_gerber]
+		-Add: copy hackvana extensions from mainline
+		-Fix: eagle file suffix bug made top layer and bottom copper layer clash with top and bottom silk
+
+	[export_png]
+		-Fix: notice gc color and cap style changes and update the brush
+		-Fix: properly draw corner case: full-circle arcs
+		-Fix: scale rouding bugs
+		-Fix: use gc for zero-length arcs too
+
+	[gsch2pcb-rnd]
+		-Fix: don't depend on scconfig objects, use pcb_concat() instead of str_concat()
+		-Fix: stop fighting with src/ for compiling the src_3rd/ objects, just call src/ for doing that
+
+	[hid_gtk]
+		-Split: hid_gtk common parts into a lib (lib_gtk_common)
+		-Fix: arc delta angle > 360 means full curcle, don't modulo
+		-Fix: arc endpoint rounding error when drawing with gdk (reported by Evan)
+		-Fix: don't run the netlist window if gtkhid is not yet active (batch mode)
+		-Fix: set the right layer color when changing layer colors - store the context struct for each layer index separately (more memory leaks...)
+		-Del: unused ghid_dialog_confirm_all() and ghid_dialog_confirm()
+		-Del: utf8 dup string is not even used anywhere
+		-Del: free_glist_and_data() is not in use, get rid of it
+		-Del: dead code: ghid message dialog: we use the log now, that should be the only one way to inform the user
+		-Del: unused abort functions
+		-Del: gui-keyref dialog (outdated, hardwired, unaccessible)
+		-Change: About dialog is more gtkish and uses the pcb-rnd logo
+		-Change: disable mnemonics for main menus because mnemonics lets gtk steal our keyboard input
+
+	[hid_lesstif]
+		-Fix: arc delta angle > 360 is always a full circle, don't modulo
+		-Fix: don't try to change cursor shape for being busy if the hid is not running
+		-Fix: typo in the menu config for show_mask made solder mask unable to display
+
+	[io_kicad]
+		-Change: use the new, simpler layer creation API
+		-Fix: refuse to use any negative layer
+		-Fix: residual arc format parsing errors; homeomorphic linear mappings R us.
+		-Fix: empty altium2kicad element definitions now imported with a 1nm line at the module centroid
+		-Fix: fixed non cummutative symmetry operations when importing fp_arc and gr_arc elements
+		-Fix: fixed off by one tree traversal error for polygonal zones
+		-Add: Kicad supports arcs on the Edge.Cut layer, now implemented
+		-Add: accept # comments when reading a KiCad s-expr file
+		-Add: improved handling of SMD layer definitions board
+
+	[io_lihata]
+		-Fix: default output formatting (indentation bugs)
+		-Fix: properly load the outline layer, even if it appears to be in group -1
+		-Fix: translate the new, rich layer group table to the old, dummy format for saving v1
+
+	[io_pcb]
+		-Fix: don't attempt to save attrib with NULL value
+		-Fix: layer number boundary check bug (the legacy +2)
+
+	[poly]
+		-Fix: poly clipped out of existence can come back without an assert
+		-Fix: when priting 'cleared out of exitence' message, use mm for coords
+
+	[res]
+		-Add: all new importes in the import menu
+		-Change: default file menu rearranged, import options grouped in a submenu to keep things simpler
+
+	[rubberband]
+		-Add: Support rubberbanding of lines attached to an arc
+		-Fix: Allow both ends of a line to be included in a rubberband move
+
+	[scconfig]
+		-Add: detect and use -std=c99 if available, some versions of gcc doesn't go for that by default - we also want to avoid accidentally using extensions in C99 code
+		-Add: detect cairo for the breadboard exporter
+		-Fix: allow parallel build
+		-Fix: mod CLEANFILES takes effect now
+		-Fix: when compiling with --debug, display debug symbols as implicit-enabled in the summary
+
+	[toporouter]
+		-Del: remove toporouter and gts - we have better alternatives now
+
+
 pcb-rnd 1.2.0 (r5967)
 ~~~~~~~~~~~~~~~~~~~~~
 	[unravel]
diff --git a/Makefile b/Makefile
index 155fc7e..7ee399d 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,6 @@ distclean: FORCE
 	cd src_3rd/genlist && $(MAKE) clean ; true
 	cd src_3rd/genregex && $(MAKE) clean ; true
 	cd src_3rd/genvector && $(MAKE) clean ; true
-	cd src_3rd/gts && $(MAKE) clean ; true
 	cd src_3rd/liblihata && $(MAKE) clean ; true
 	cd src_3rd/liblihata/genht && $(MAKE) clean ; true
 	cd src_3rd/qparse && $(MAKE) clean ; true
diff --git a/Makefile.conf.in b/Makefile.conf.in
index dc0e1ed..cdb07df 100644
--- a/Makefile.conf.in
+++ b/Makefile.conf.in
@@ -15,5 +15,6 @@ RM=@/host/fstools/rm@
 CP=@/host/fstools/cp@
 LN=@/host/fstools/ln@
 MKDIR=@/host/fstools/mkdir@
+SCCBOX=$(ROOT)/scconfig/sccbox
 EXE=@/target/sys/ext_exe@
 @]
diff --git a/Release_notes b/Release_notes
index 85dfc77..24bbe11 100644
--- a/Release_notes
+++ b/Release_notes
@@ -1,20 +1,29 @@
-pcb-rnd 1.2.0
+pcb-rnd 1.2.1
 ~~~~~~~~~~~~~~
-Finally, the long postponed major core cleanup has been implemented. This
-probably has been among the top 5 cleanups in the project history back to
-the 90s.
 
-First, the code is now reorganized to build up around object types
-instead of actions. This means there's an obj_line.c, obj_arc.c, etc.
-that know how to do everything with lines, arc, etc. The old code had
-everything built around actions, so there was move.c, rotate.c, etc.,
-that knew how to move, rotate, etc. all object types. The new
-organization makes it much simpler to change how objects behave or to
-introduce new objects.
+With a new peak in number of developers and contributors, version 1.2.1
+introduces a large amount of bug fixes, cleanups and new features that
+can be sorted in the following main groups.
 
-The second part of the cleanup was to add pcb_ and PCB_ prefix to global
-symbols in core API. This will allow us to split core into libs with
-external, public API later, without risking name clashes. This will provide
-better code reuse and cleaner, more stable API to external plugins.
+1. Layer model rewrite; pcb-rnd now has a clear separation of physical
+layer and logical layer concepts. There's new, board cross-section GUI
+to visualize and manipulate the layer stack.
 
-Among with the large cleanup, a lot of bugs have been found and fixed.
+2. The hid_gtk refactoring; big, monolithic code blocks are split up in
+smaller, more independent, lib-like modules and are moved to a lib plugin.
+This paves the road for a modular setup to support multiple graphic
+renderings and maybe even different gtk versions.
+
+3. Automated testing and validation: a new infrastructure for automated
+testing of exporters is added. The reference PNG files are manually validated
+against the input PCB geometry - by now, we know exactly how much error
+the PNG rendering has.
+
+4. UI fixes: better rubber band, xor-outline-while-moving and DRC outline
+visualization support.
+
+5. Introducing the "EDA ecosystem" idea: real working import/export bridges
+or flows to fidocadj, freerouting.net, ltspice, mucs and TinyCAD. Major
+improvements in the KiCad file format compatibility.
+
+6. The toporouter got removed in favor of the new routers for now.
diff --git a/config.h.in b/config.h.in
index 3d4a597..4d541b9 100644
--- a/config.h.in
+++ b/config.h.in
@@ -41,17 +41,17 @@ print [@ /***** Generated by scconfig - DO NOT EDIT *****/
 @]
 
 print {\n\n/* Macro to add a funciton attribute to suppress "function unused" for static inline functions declared in .h files */\n}
-print_ternary cc/func_attr/unused/presents {#define PCB_FUNC_UNUSED __attribute__((unused))} {#define PCB_FUNC_UNUSED}
+print_ternary ?cc/func_attr/unused/presents {#define PCB_FUNC_UNUSED __attribute__((unused))} {#define PCB_FUNC_UNUSED}
 
 
 print {\n\n/* Define to 1 if you have the `snprintf' function. */\n}
-print_ternary libs/snprintf {#define HAVE_SNPRINTF 1} {/* #undef HAVE_SNPRINTF */}
+print_ternary ?libs/snprintf {#define HAVE_SNPRINTF 1} {/* #undef HAVE_SNPRINTF */}
 
 print {\n\n/* Define to 1 if you have the `vsnprintf' function. */\n}
-print_ternary libs/vsnprintf {#define HAVE_VSNPRINTF 1} {/* #undef HAVE_VSNPRINTF */}
+print_ternary ?libs/vsnprintf {#define HAVE_VSNPRINTF 1} {/* #undef HAVE_VSNPRINTF */}
 
 print {\n\n/* Define to 1 if you have the `getcwd' function. */\n}
-print_ternary libs/fs/getcwd/presents {#define HAVE_GETCWD 1} {/* #undef HAVE_GETCWD */}
+print_ternary ?libs/fs/getcwd/presents {#define HAVE_GETCWD 1} {/* #undef HAVE_GETCWD */}
 
 print {\n\n/* Define to 1 if you have the `_getcwd' function. */\n}
 print_ternary ?libs/fs/_getcwd/presents {#define HAVE__GETCWD 1} {/* #undef HAVE__GETCWD */}
@@ -60,25 +60,25 @@ print {\n\n/* Define to 1 if you have the `getwd' function. */\n}
 print_ternary ?libs/fs/_getwd/presents {#define HAVE_GETWD 1} {/* #undef HAVE_GETWD */}
 
 print {\n\n/* Define to 1 if you have the <gd.h> header file. */\n}
-print_ternary libs/gui/gd/presents {#define HAVE_GD_H 1} {/* #undef HAVE_GD_H */}
+print_ternary ?libs/gui/gd/presents {#define HAVE_GD_H 1} {/* #undef HAVE_GD_H */}
 
 print {\n\n/* Define to 1 if you have the `gdImageGif' function. */\n}
-print_ternary libs/gui/gd/gdImageGif/presents {#define HAVE_GDIMAGEGIF 1} {/* #undef HAVE_GDIMAGEGIF */}
+print_ternary ?libs/gui/gd/gdImageGif/presents {#define HAVE_GDIMAGEGIF 1} {/* #undef HAVE_GDIMAGEGIF */}
 
 print {\n\n/* Define to 1 if you have the `gdImageJpeg' function. */\n}
-print_ternary libs/gui/gd/gdImageJpeg/presents {#define HAVE_GDIMAGEJPEG 1} {/* #undef HAVE_GDIMAGEJPEG */}
+print_ternary ?libs/gui/gd/gdImageJpeg/presents {#define HAVE_GDIMAGEJPEG 1} {/* #undef HAVE_GDIMAGEJPEG */}
 
 print {\n\n/* Define to 1 if you have the `gdImagePng' function. */\n}
-print_ternary libs/gui/gd/gdImagePng/presents {#define HAVE_GDIMAGEPNG 1} {/* #undef HAVE_GDIMAGEPNG */}
+print_ternary ?libs/gui/gd/gdImagePng/presents {#define HAVE_GDIMAGEPNG 1} {/* #undef HAVE_GDIMAGEPNG */}
 
 print {\n\n/* Define to 1 if you have the `getpwuid' function. */\n}
-print_ternary libs/userpass/getpwuid/presents {#define HAVE_GETPWUID 1} {/* #undef HAVE_GETPWUID */}
+print_ternary ?libs/userpass/getpwuid/presents {#define HAVE_GETPWUID 1} {/* #undef HAVE_GETPWUID */}
 
 print {\n\n/* Define to 1 if you have the `rint' function. */\n}
-print_ternary libs/math/rint/presents {#define HAVE_RINT 1} {/* #undef HAVE_RINT */}
+print_ternary ?libs/math/rint/presents {#define HAVE_RINT 1} {/* #undef HAVE_RINT */}
 
 print {\n\n/* Define to 1 if you have the `round' function. */\n}
-print_ternary libs/math/round/presents {#define HAVE_ROUND 1} {/* #undef HAVE_ROUND */}
+print_ternary ?libs/math/round/presents {#define HAVE_ROUND 1} {/* #undef HAVE_ROUND */}
 
 print {\n\n/* Wrapper for S_ISLNK(x); always return 0 if S_ISLNK doesn't exist */\n}
 switch ?/target/libs/fs/stat/macros/S_ISLNK
@@ -93,7 +93,7 @@ print {\n\n/* Define to 1 if Xrender is available */\n}
 print_ternary ?libs/gui/xrender/presents {#define HAVE_XRENDER 1} {/*#undef HAVE_XRENDER */}
 
 print {\n\n/* Define to 1 if translation of program messages to the user's native language is requested. */\n}
-print_ternary /local/pcb/want_nls {#define ENABLE_NLS 1} {/*#undef ENABLE_NLS */}
+print_ternary ?/local/pcb/want_nls {#define ENABLE_NLS 1} {/*#undef ENABLE_NLS */}
 
 print {\n\n/* Define to 1 if we should use windows api for dynamic linking. */\n}
 print_ternary ?libs/LoadLibrary/presents {#define USE_LOADLIBRARY 1} {/* #undef USE_LOADLIBRARY */}
diff --git a/doc/TODO b/doc/TODO
index 9417130..daeff58 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -1,25 +1,16 @@
 - BUGS
-	+ gerber top layer doesn't have pads on A.pcb (layer cleanup) [report:James]
-	+ gerber layer group name [report:James]
-	? all route styles deleted when using 'File>load layout data to paste buffer'
-	+ in the 45-deg line mode, while DRC enforce settings toggled 'on' can cause isolated trace crossing, violating DRC
-	? `--dump-actions` and `--show-actions` ends with segmentation fault (compile without debug) Can't reproduce [report:miloh]
-	? GTK: redraws the board after tab-flip but it doesn't hit the screen on mac [report:James]
-
+	+ rats not disappearing after routing [report: erich/cm13g09]
+	- cycledrag doesn't work on arc endpoint + line endpoint [report:Ade]
+	- load data from layout to paste buffer:
+		- settings and even layer visibility gets messed up - there shall be no change in any of those at all
+		- probably IDs are messed too: copy and paste new arc loaded that way a few times and it will disappear after other edits (silk)
 
 - Lihata persistent save:
 	- flag compatibility: save unknown, string-flags as loaded by io_pcb
-	- ind: space in ha:layer name
-	- ind: symbol height is not in-line on the output
-	- ind: indentation bug in via and netlists
 	- ind: indentation bug in inline struct therm: closing } is preceded by indentation whitespace for some reason
-	- ind: style attribute members in a fresh save
 	- keep numeric format: test all
 	- keep unknown subtrees
 
-- unravel:
-	- replace "outline" and "route" layer name checks with a central layer call
-
 - replace settings with lihata (conf_*)
 	- TEST:
 		- vendor drill mapping (all functionality, including regex based refdes ignore)
@@ -38,35 +29,39 @@
 		- geo speed
 		- regex and string cmp match speed vs. select by name
 
-- gsch2pcb-rnd migration
-	- remove old project file support
-	- remove -m pcb
+
+RELEASE 1.2.2:
+	- gsch2pcb-rnd migration
+		- remove old project file support
+		- remove -m pcb
 
 CLEANUP #5
-- del on arc endpoint should remove the arc, just like del on line endpoint remvoes the line [report:Evan]
-- BUG: arcbug1.lht: draw a polygon over the rightmost ^ arc andit will calculate a self-intersecting clearance [report:Evan]
-- draw code: pin numbers/names are drawn under the silk [report:Evan]
+- insonsistencies in UI/terminology:
+	- allow clearance to be set to 0 in the route style [report: miloh]
+	- similar thing on hole size [report: miloh]
+	- report dialog should use the same terminology as route style dialog [report: miloh]
+- GTK layers [report: Ade]:
+	- add a left-click context menu for the layer selector widget
+	- move the layer+selected color change from the preferecnes menu there (but this should probably live in gui-config.h)
+	- move the logical layer preferences menu tab items in this context menu too (e.g. move up/down, rename, delete, insert)
+- layer group rewrite:
+	- remove PCB_MAX_LAYERGRP and PCB_MAX_LAYER and make them dynamic
+- BUG: arcbug1.lht: draw a polygon over the rightmost ^ arc and it will calculate a self-intersecting clearance [report:Evan]
+- draw code: pin numbers/names are drawn under the silk: pins/pads are drawn in one go, both copper and the numebring, and the copper needs to go under the silk so the number ends up there too [report:Evan]
 - lihata board:
 	- move generates much more diff than reasonable: does it renumber IDs?
-- BUG: liblihata shouldn't compile genht (different cflags)
-- BUG: recompile scconfig's str.c for gsch2pcb-rnd (or consider removing it) because of the different compiler flags; fix: use pcb_concat instead [report:debian's QA page for kfreebsd]
-- BUG: redraw after pin renumber in gtk with shift+ctrl+n
 - save buffer element to file - preferred format is hardwired and file name guess is crude (function Save() in gtkhid-main.c)
-- import hackvana gerber naming scheme from mainline [report:Erich]
-- gsch2pcb-rnd: plugin_register() should be in glue.c
 - pcb_act_Attributes -> this could be handled by the property editor maybe? but what about layout attributes and the lesstif hid?
 - unravel the undo code
 	- grid size change should be undoable? [report:Evan]
 	- maybe other conf settings too?
 - src/check_icon.data - is it used?
 - search for move.dst_layer - don't compare pointer to -1!
-- make uninstall doesn't remove an scm
 - rework the gpmi plugin to make it more standard in regard of the build system and to remove a few directories
 - dir rename trunk/pcblib/tru-hole should handle make correctly and not walk on existing web services or user installs
 - grid status line label doesn't update when using setvalue(grid,delta) add another hook to update this value [miloh]
 - Erich's select undo bug: place an element, select, save & load, unselect, undo 2 times: bad serial
 - Erich's gtk lag report: press 's' a lot then move the mouse - 's' ends up in the new loc!
-- conf: throw an error if user config can not be written
 - the TAB bug: (over ssh -X) press tab for a good 15 seconds; release; it won't work again for a fraction of a second
 - mark bug - ortho shouldn't use it, it should use last point (crosshair.X2); make sure nothing else abuses it [James]
 - improve locking:
@@ -82,9 +77,6 @@ CLEANUP #5
 	- switch the lesstif HID over from attribs to conf
 	- remove redundancy: don't store values in the PCB struct that are in the design conf
 	- increments are not really implemented
-	- if font file is not found:
-		- embedded version?
-		- warn when try to write text on pcb?
 - action bug: gui_act.c shouldn't reference Crosshair.X directly; check d-fix.patch about how to fix it
 - next_gui: keep them open, hide
 - look for #warnings
@@ -98,12 +90,17 @@ CLEANUP #5
 - check whether local copy of gts is needed, bisect when toporouter broke 
 - check gpmi when pcb-rnd is fully linstalled - broken symlinks?
 - multi-key: display state on the gui
-- implement loglevels and log style tags in the lesstif HID
 - TODO#3: works only on US keyboard
-- gsch2pcb: generalize plugin/buildin loading for external tools, check if gsch2pcb can work from plugins
 - gtk hid: display element numbers; flip board with tab: numbers get mirrored [report:Evan]
+- layer rewrite:
+	- catch the layer change signal from polygons and reclip; Evan's test case:
+	  draw a line on a layer and a poly on another and change whether they are in
+	  the same layer group
 
 CLEANUP #6:
+- silent failure on parser error in io_pcb: e.g. missing or non-integer fields of Via[] [report: Erich]
+- core lib splitup:
+	- gsch2pcb: generalize plugin/buildin loading for external tools, check if gsch2pcb can work from plugins
 - lihata board/fp format:
 	- pads should be polygons (0 long line can't be rotated!)
 	- footprint orientation with a vector (just a second point)
@@ -134,9 +131,7 @@ CLEANUP #6:
 	- mods:
 		- gpmi (and other buildins/plugins) not showing up in the about box
 - self contained
-	- files
-		- default font
-	- action (--show-paths!) and dialog box to print where the actual files are coming from
+	- dialog box to print where the actual files are coming from, including if the font came from embedded/internal (gui version of --show-paths)
 	- project specific menus from extra lihata files - maybe from project.lht
 - main.c:
 	- SIGPIPE - detect it (needed for popen)
@@ -149,8 +144,10 @@ CLEANUP #7: the big object split
 
 FEATURES
 - BUILD: menuconfig and a config file for scconfig
+- menu item for export of multiple selected layout elements to discrete .fp files
 
 Low prio:
+- bug: rubberband_orig: draw a 90 deg arc, a 45 deg line that ends in the endpoints of the arc; enable rubber band, move the arc: only one endpoint of the line is moved [fixing:Ade]
 - bug: redrawbug1: grap c1, the diagonal trace gets dran over U1's silk - it's redrawn because of the overlapping bounding box with C1, while U1 has no overlap [report:Evan]
 - bug: draw overlapping lines, a short fully under a long; click on the short, it gets selected but it's not visible because the long hides it [report:Evan]
 - GTK "save as" dialog: there should be an "auto" or "guess by extension" option in the save dialog format
diff --git a/doc/datasheet.html b/doc/datasheet.html
new file mode 100644
index 0000000..c971ff8
--- /dev/null
+++ b/doc/datasheet.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+	<title> pcb-rnd - datasheet </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+<!--AUTO head begin-->
+	<link rel="icon" href="http://repo.hu/projects/pcb-rnd/resources/logo16.png">
+<!--AUTO head end-->
+</head>
+<body>
+
+<!--AUTO navbar begin-->
+<table border=0 cellspacing=2 cellpadding=10  bgcolor="#eeeeee" width="100%">
+<tr>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/projects/pcb-rnd/"> Main </a>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/projects/pcb-rnd/news.html"> News </a>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/projects/pcb-rnd/doc.html"> Doc </a>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/cgi-bin/pcb-rnd-people.cgi">People</a>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/cgi-bin/pcb-rnd-people.cgi?cmd=events">Events</a> & <a href="http://www.repo.hu/cgi-bin/pcb-rnd-people.cgi?cmd=timeline"> timeline </a>
+<td align=right width="60%"> <font size="+2"><i>pcb-rnd</i></font> <img src="http://repo.hu/projects/pcb-rnd/resources/logo32.png" alt="[pcb-rnd logo]">
+</table>
+<!--AUTO navbar end-->
+
+<h1> pcb-rnd - datasheet </h1>
+
+<table border=1 cellspacing=0 cellpadding=5>
+<tr>
+	<td bgcolor="#ccccff"> layout characteristics
+	<td bgcolor="#ddddff"> multiple layers (16 copper, compile time tunable limit)
+                         <br> smd and through-hole components
+                         <br> solder mask, paste, assembly drawings
+                         <br> board size up to 2x2 meter at nanometer precision
+                         <br> arbitrary amount of routing styles
+                         <br> Design Rule Checker
+<tr>
+	<td bgcolor="#ccccff"> board file formats
+	<td bgcolor="#ddddff"> lihata (native), geda/PCB's .pcb, KiCad's s-expr kicad_pcb
+<tr>
+	<td bgcolor="#ccccff"> other native formats
+	<td bgcolor="#ddddff"> geda/PCB's .fp for footprints (native)
+<tr>
+	<td bgcolor="#ccccff"> import formats
+	<td bgcolor="#ddddff"> gEDA/gaf sch, gEDA/gaf netlist, dsn, edif
+<tr>
+	<td bgcolor="#ccccff"> export formats
+	<td bgcolor="#ddddff"> gerber, png, ps, svg, bom, xy, bboard, dsn, gcode, ipcd356, lpr, nelma, kicad old pcb format
+<tr>
+	<td bgcolor="#ccccff"> UI options
+	<td bgcolor="#ddddff"> gtk2, lesstif (motif), batch (automated processing)
+                         <br> configurable menus, keyboard and mouse actions
+<tr>
+	<td bgcolor="#ccccff"> footprint library
+	<td bgcolor="#ddddff"> parametric footprints written in any programming language
+	                       <br>optionally per system, per user, per project libs
+	                       <br>footprints from local files
+	                       <br>footprints from the web (gedasymbols.org)
+<tr>
+	<td bgcolor="#ccccff"> scripting
+	<td bgcolor="#ddddff"> embedded scripting using libgpmi (awk, python, lua, tcl, ruby, perl, php, scheme, lisp)
+<tr>
+	<td bgcolor="#ccccff"> layout helpers
+	<td bgcolor="#ddddff"> basic autorouter, basic autoplace, place objects in aligned grid,
+	                       asymmetric pin shapes, back annotation tracking,
+	                       trace puller, teardrops
+	                       <br>understands internal connections in footprints
+	                       <br>query mini-language for finding and selecting objects by rules
+<tr>
+	<td bgcolor="#ccccff"> misc
+	<td bgcolor="#ddddff"> flexible configuration system
+	                       <br>support for small screen (800x600)
+	                       <br>strong support for automated processing
+                         <br>modularity (most code implemented in plugins)
+                         <br>slim code, reduced external dependency, portability
+</table>
+<p>
+<a href="features/index.html">More details on some of the features</a>, especially compared to gEDA/PCB.
+
+</body>
+</html>
diff --git a/doc/developer/bridges/Makefile b/doc/developer/bridges/Makefile
new file mode 100644
index 0000000..9986c6b
--- /dev/null
+++ b/doc/developer/bridges/Makefile
@@ -0,0 +1,2 @@
+bridges.png: bridges.dot
+	dot -Tpng bridges.dot > bridges.png
diff --git a/doc/developer/bridges/bridges.dot b/doc/developer/bridges/bridges.dot
new file mode 100644
index 0000000..1497a08
--- /dev/null
+++ b/doc/developer/bridges/bridges.dot
@@ -0,0 +1,52 @@
+digraph gr {
+	rankdir=LR
+	
+	pcbrnd [label="pcb-rnd" style=filled fillcolor=cyan shape=box height=8]
+	kicad [label="KiCad" shape=box]
+	pcb [label="gEDA/PCB" shape=box]
+	freerouting [label="freerouting.net\njava application" shape=box]
+	mucs [label="mucs pcb with autorouter" shape=box]
+
+	batch   [label="hid_batch" shape=diamond]
+	gtk     [label="hid_gtk" shape=diamond]
+	lesstif [label="hid_lesstif" shape=diamond]
+	remote  [label="hid_remote" shape=diamond]
+
+	pcbrnd -> kicad [label="board: legacy format"]
+	pcbrnd -> kicad [label="board: s-expression"]
+	kicad -> pcbrnd [label="board: s-expression"]
+	pcbrnd -> kicad [label="footprint: s-expression"]
+	kicad -> pcbrnd [label="footprint: s-expression"]
+
+	pcbrnd -> pcb [label="board: .pcb"]
+	pcbrnd -> pcb [label="footprint: .fp"]
+	pcb -> pcbrnd [label="board: .pcb"]
+	pcb -> pcbrnd [label="footprint: .fp"]
+
+	pcbrnd -> freerouting [label="export: .dsn"]
+	freerouting -> pcbrnd [label="import: .dsn"]
+	mucs -> pcbrnd [label="import"]
+
+	pcbrnd -> breadboard [label="export: .png"]
+	pcbrnd -> BoM [label="export: text"]
+	pcbrnd -> XY [label="export: .xy\nfor pick and place"]
+	pcbrnd -> gerber [label="export: .gbr, .cnc"]
+	pcbrnd -> ipcd356 [label="export"]
+	pcbrnd -> lpr [label="print"]
+	pcbrnd -> nelma [label="export"]
+	pcbrnd -> png [label="export: bitmap"]
+	pcbrnd -> ps [label="export: .ps, .eps"]
+	pcbrnd -> stat [label="export: statsitics .lht"]
+	pcbrnd -> svg [label="export: .svg"]
+
+	edif -> pcbrnd [label="import"]
+	ltspice -> pcbrnd [label="import: schematics"]
+	netlist -> pcbrnd [label="import: pcb .net"]
+	gschem -> pcbrnd [label="import: schematics"]
+	tinycad -> pcbrnd [label="import: schematics"]
+
+	pcbrnd -> batch [label="hid"]
+	pcbrnd -> gtk [label="hid"]
+	pcbrnd -> lesstif [label="hid"]
+	pcbrnd -> remote [label="hid"]
+}
\ No newline at end of file
diff --git a/doc/developer/bridges/bridges.png b/doc/developer/bridges/bridges.png
new file mode 100644
index 0000000..6e16210
Binary files /dev/null and b/doc/developer/bridges/bridges.png differ
diff --git a/doc/developer/hid_gtk3/Makefile b/doc/developer/hid_gtk3/Makefile
new file mode 100644
index 0000000..0560411
--- /dev/null
+++ b/doc/developer/hid_gtk3/Makefile
@@ -0,0 +1,5 @@
+%.html: %.adoc
+	asciidoctor --safe-mode=secure $^
+
+
+#	asciidoctor $^ > $@
diff --git a/doc/developer/hid_gtk3/default.css b/doc/developer/hid_gtk3/default.css
new file mode 100644
index 0000000..5f9bdbd
--- /dev/null
+++ b/doc/developer/hid_gtk3/default.css
@@ -0,0 +1,358 @@
+/* pcb-rnd (c) Alain Vigne*/
+ at import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Sans:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
+article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
+[hidden],template{display:none}
+script{display:none!important}
+html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
+a{background:transparent}
+a:focus{outline:thin dotted}
+a:active,a:hover{outline:0}
+h1{font-size:2em;margin:.67em 0}
+abbr[title]{border-bottom:1px dotted}
+b,strong{font-weight:bold}
+hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
+mark{background:#ff0;color:#000}
+code,kbd,pre,samp{font-family:monospace;font-size:1em}
+pre{white-space:pre-wrap}
+q{quotes:"\201C" "\201D" "\2018" "\2019"}
+small{font-size:80%}
+sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
+sup{top:-.5em}
+sub{bottom:-.25em}
+img{border:0}
+svg:not(:root){overflow:hidden}
+figure{margin:0}
+legend{border:0;padding:0}
+button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
+button,input{line-height:normal}
+button,select{text-transform:none}
+button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
+button[disabled],html input[disabled]{cursor:default}
+input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
+input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}
+input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}
+button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
+textarea{overflow:auto;vertical-align:top}
+table{border-collapse:collapse;border-spacing:0}
+*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
+html,body{font-size:100%}
+body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Sans","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
+a:hover{cursor:pointer}
+img,object,embed{max-width:100%;height:auto}
+object,embed{height:100%}
+img{-ms-interpolation-mode:bicubic}
+.left{float:left!important}
+.right{float:right!important}
+.text-left{text-align:left!important}
+.text-right{text-align:right!important}
+.text-center{text-align:center!important}
+.text-justify{text-align:justify!important}
+.hide{display:none}
+img,object,svg{display:inline-block;vertical-align:middle}
+textarea{height:auto;min-height:50px}
+select{width:100%}
+.center{margin-left:auto;margin-right:auto}
+.spread{width:100%}
+p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{font-size:1.21875em;line-height:1.6}
+.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
+div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
+a{color:#2156a5;text-decoration:underline;line-height:inherit}
+a:hover,a:focus{color:#1d4b8f}
+a img{border:none}
+p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
+p aside{font-size:.875em;line-height:1.35;font-style:italic}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#804419;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
+h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
+h1{font-size:2.125em}
+h2{font-size:1.6875em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
+h4,h5{font-size:1.125em}
+h6{font-size:1em}
+hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
+em,i{font-style:italic;line-height:inherit}
+strong,b{font-weight:bold;line-height:inherit}
+small{font-size:60%;line-height:inherit}
+code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
+ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
+ul,ol,ul.no-bullet,ol.no-bullet{margin-left:1.5em}
+ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
+ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
+ul.square{list-style-type:square}
+ul.circle{list-style-type:circle}
+ul.disc{list-style-type:disc}
+ul.no-bullet{list-style:none}
+ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
+dl dt{margin-bottom:.3125em;font-weight:bold}
+dl dd{margin-bottom:1.25em}
+abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
+abbr{text-transform:none}
+blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
+blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
+blockquote cite:before{content:"\2014 \0020"}
+blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
+blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
+ at media only screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
+h1{font-size:2.75em}
+h2{font-size:2.3125em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
+h4{font-size:1.4375em}}
+table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
+table thead,table tfoot{background:#f7f8f7;font-weight:bold}
+table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
+table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
+table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
+table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
+h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
+.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}
+.clearfix:after,.float-group:after{clear:both}
+*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
+*:not(pre)>code.nobreak{word-wrap:normal}
+*:not(pre)>code.nowrap{white-space:nowrap}
+pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
+em em{font-style:normal}
+strong strong{font-weight:400}
+.keyseq{color:rgba(51,51,51,.8)}
+kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
+.keyseq kbd:first-child{margin-left:0}
+.keyseq kbd:last-child{margin-right:0}
+.menuseq,.menu{color:rgba(0,0,0,.8)}
+b.button:before,b.button:after{position:relative;top:-1px;font-weight:400}
+b.button:before{content:"[";padding:0 3px 0 2px}
+b.button:after{content:"]";padding:0 2px 0 3px}
+p a>code:hover{color:rgba(0,0,0,.9)}
+#header,#content,#footnotes,#footer{width:95%;margin-left:2em;margin-right:auto;margin-top:0;margin-bottom:0;/*max-width:62.5em;*/*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
+#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table}
+#header:after,#content:after,#footnotes:after,#footer:after{clear:both}
+#content{margin-top:1.25em}
+#content:before{content:none}
+#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
+#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
+#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
+#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
+#header .details span:first-child{margin-left:-.125em}
+#header .details span.email a{color:rgba(0,0,0,.85)}
+#header .details br{display:none}
+#header .details br+span:before{content:"\00a0\2013\00a0"}
+#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
+#header .details br+span#revremark:before{content:"\00a0|\00a0"}
+#header #revnumber{text-transform:capitalize}
+#header #revnumber:after{content:"\00a0"}
+#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
+#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
+#toc>ul{margin-left:.125em}
+#toc ul.sectlevel0>li>a{font-style:italic}
+#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
+#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
+#toc li{line-height:1.3334;margin-top:.3334em}
+#toc a{text-decoration:none}
+#toc a:active{text-decoration:underline}
+#toctitle{color:#7a2518;font-size:1.2em}
+body.toc2{padding-left:20em;padding-right:0}
+#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:20em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
+#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
+#toc.toc2>ul{font-size:.9em;margin-bottom:0}
+#toc.toc2 ul ul{margin-left:0;padding-left:1em}
+#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
+body.toc2.toc-right{padding-left:0;padding-right:15em}
+body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}
+.sect1+.sect1{border-top:1px solid #efefed}
+#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
+#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
+#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
+#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
+#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
+#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
+#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
+.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
+.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Sans","DejaVu Serif",serif;font-size:1rem;font-style:italic}
+table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0}
+.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{color:rgba(0,0,0,.85)}
+table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit}
+.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
+.admonitionblock>table td.icon{text-align:center;width:80px}
+.admonitionblock>table td.icon img{max-width:none}
+.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
+.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
+.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
+.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
+.exampleblock>.content>:first-child{margin-top:0}
+.exampleblock>.content>:last-child{margin-bottom:0}
+.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+.sidebarblock>:first-child{margin-top:0}
+.sidebarblock>:last-child{margin-bottom:0}
+.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
+.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
+.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
+.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
+.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
+.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
+.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}
+.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
+.listingblock pre.highlightjs{padding:0}
+.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
+.listingblock pre.prettyprint{border-width:0}
+.listingblock>.content{position:relative}
+.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
+.listingblock:hover code[data-lang]:before{display:block}
+.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:.5em;color:#999}
+.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"}
+table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
+table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
+table.pyhltable td.code{padding-left:.75em;padding-right:0}
+pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
+pre.pygments .lineno{display:inline-block;margin-right:.25em}
+table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
+.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
+.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
+.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
+.quoteblock blockquote{margin:0;padding:0;border:0}
+.quoteblock blockquote:before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
+.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
+.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
+.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
+.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
+.quoteblock .quoteblock blockquote:before{display:none}
+.verseblock{margin:0 1em 1.25em 1em}
+.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
+.verseblock pre strong{font-weight:400}
+.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
+.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
+.quoteblock .attribution br,.verseblock .attribution br{display:none}
+.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
+.quoteblock.abstract{margin:0 0 1.25em 0;display:block}
+.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0}
+.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none}
+table.tableblock{max-width:100%;border-collapse:separate}
+table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0}
+table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
+table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0}
+table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0}
+table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0}
+table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0}
+table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0}
+table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0}
+table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0}
+table.frame-all{border-width:1px}
+table.frame-sides{border-width:0 1px}
+table.frame-topbot{border-width:1px 0}
+th.halign-left,td.halign-left{text-align:left}
+th.halign-right,td.halign-right{text-align:right}
+th.halign-center,td.halign-center{text-align:center}
+th.valign-top,td.valign-top{vertical-align:top}
+th.valign-bottom,td.valign-bottom{vertical-align:bottom}
+th.valign-middle,td.valign-middle{vertical-align:middle}
+table thead th,table tfoot th{font-weight:bold}
+tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
+tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
+p.tableblock>code:only-child{background:none;padding:0}
+p.tableblock{font-size:1em}
+td>div.verse{white-space:pre}
+ol{margin-left:1.75em}
+ul li ol{margin-left:1.5em}
+dl dd{margin-left:1.125em}
+dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
+ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
+ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none}
+ul.unstyled,ol.unnumbered,ul.checklist{margin-left:.625em}
+ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1em;font-size:.85em}
+ul.checklist li>p:first-child>input[type="checkbox"]:first-child{width:1em;position:relative;top:1px}
+ul.inline{margin:0 auto .625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden}
+ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block}
+ul.inline>li>*{display:block}
+.unstyled dl dt{font-weight:400;font-style:normal}
+ol.arabic{list-style-type:decimal}
+ol.decimal{list-style-type:decimal-leading-zero}
+ol.loweralpha{list-style-type:lower-alpha}
+ol.upperalpha{list-style-type:upper-alpha}
+ol.lowerroman{list-style-type:lower-roman}
+ol.upperroman{list-style-type:upper-roman}
+ol.lowergreek{list-style-type:lower-greek}
+.hdlist>table,.colist>table{border:0;background:none}
+.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
+td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
+td.hdlist1{font-weight:bold;padding-bottom:1.25em}
+.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
+.colist>table tr>td:first-of-type{padding:0 .75em;line-height:1}
+.colist>table tr>td:last-of-type{padding:.25em 0}
+.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
+.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
+.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
+.imageblock>.title{margin-bottom:0}
+.imageblock.thumb,.imageblock.th{border-width:6px}
+.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
+.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
+.image.left{margin-right:.625em}
+.image.right{margin-left:.625em}
+a.image{text-decoration:none;display:inline-block}
+a.image object{pointer-events:none}
+sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
+sup.footnote a,sup.footnoteref a{text-decoration:none}
+sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
+#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
+#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em 0;border-width:1px 0 0 0}
+#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;text-indent:-1.05em;margin-bottom:.2em}
+#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none}
+#footnotes .footnote:last-of-type{margin-bottom:0}
+#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
+.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
+.gist .file-data>table td.line-data{width:99%}
+div.unbreakable{page-break-inside:avoid}
+.big{font-size:larger}
+.small{font-size:smaller}
+.underline{text-decoration:underline}
+.overline{text-decoration:overline}
+.line-through{text-decoration:line-through}
+.aqua{color:#00bfbf}
+.aqua-background{background-color:#00fafa}
+.black{color:#000}
+.black-background{background-color:#000}
+.blue{color:#0000bf}
+.blue-background{background-color:#0000fa}
+.fuchsia{color:#bf00bf}
+.fuchsia-background{background-color:#fa00fa}
+.gray{color:#606060}
+.gray-background{background-color:#7d7d7d}
+.green{color:#006000}
+.green-background{background-color:#007d00}
+.lime{color:#00bf00}
+.lime-background{background-color:#00fa00}
+.maroon{color:#600000}
+.maroon-background{background-color:#7d0000}
+.navy{color:#000060}
+.navy-background{background-color:#00007d}
+.olive{color:#606000}
+.olive-background{background-color:#7d7d00}
+.purple{color:#600060}
+.purple-background{background-color:#7d007d}
+.red{color:#bf0000}
+.red-background{background-color:#fa0000}
+.silver{color:#909090}
+.silver-background{background-color:#bcbcbc}
+.teal{color:#006060}
+.teal-background{background-color:#007d7d}
+.white{color:#bfbfbf}
+.white-background{background-color:#fafafa}
+.yellow{color:#bfbf00}
+.yellow-background{background-color:#fafa00}
+span.icon>.fa{cursor:default}
+.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
+.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c}
+.admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
+.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900}
+.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}
+.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}
+.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
+.conum[data-value] *{color:#fff!important}
+.conum[data-value]+b{display:none}
+.conum[data-value]:after{content:attr(data-value)}
+pre .conum[data-value]{position:relative;top:-.125em}
+b.conum *{color:inherit!important}
+.conum:not([data-value]):empty{display:none}
+dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
+h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
+p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
+p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
+p{margin-bottom:1.25rem}
+.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
+.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
diff --git a/doc/developer/hid_gtk3/img_route_style/gtk2-edit_route_styles_001.png b/doc/developer/hid_gtk3/img_route_style/gtk2-edit_route_styles_001.png
new file mode 100644
index 0000000..a19986a
Binary files /dev/null and b/doc/developer/hid_gtk3/img_route_style/gtk2-edit_route_styles_001.png differ
diff --git a/doc/developer/hid_gtk3/img_route_style/gtk2-pcb-rnd_001.png b/doc/developer/hid_gtk3/img_route_style/gtk2-pcb-rnd_001.png
new file mode 100644
index 0000000..47f4a80
Binary files /dev/null and b/doc/developer/hid_gtk3/img_route_style/gtk2-pcb-rnd_001.png differ
diff --git a/doc/developer/hid_gtk3/index.adoc b/doc/developer/hid_gtk3/index.adoc
new file mode 100644
index 0000000..dff1eae
--- /dev/null
+++ b/doc/developer/hid_gtk3/index.adoc
@@ -0,0 +1,9 @@
+//:toc: left
+:stylesheet: default.css
+:linkcss:
+
+= GTK2 / GTK3 GUI related topics
+
+* `cairo` back-end
+* GTK3 compatibility ?
+* <<route_style.adoc#, Route styles>> dialog + widget. Concepts
\ No newline at end of file
diff --git a/doc/developer/hid_gtk3/index.html b/doc/developer/hid_gtk3/index.html
new file mode 100644
index 0000000..3747ed3
--- /dev/null
+++ b/doc/developer/hid_gtk3/index.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.5">
+<title>GTK2 / GTK3 GUI related topics</title>
+<link rel="stylesheet" href="./default.css">
+</head>
+<body class="article">
+<div id="header">
+<h1>GTK2 / GTK3 GUI related topics</h1>
+</div>
+<div id="content">
+<div class="ulist">
+<ul>
+<li>
+<p><code>cairo</code> back-end</p>
+</li>
+<li>
+<p>GTK3 compatibility ?</p>
+</li>
+<li>
+<p><a href="route_style.html">Route styles</a> dialog + widget. Concepts</p>
+</li>
+</ul>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2017-02-11 19:00:50 CET
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/doc/developer/hid_gtk3/route_style.adoc b/doc/developer/hid_gtk3/route_style.adoc
new file mode 100644
index 0000000..10f6531
--- /dev/null
+++ b/doc/developer/hid_gtk3/route_style.adoc
@@ -0,0 +1,198 @@
+:author: Alain
+:toc: left
+:icons: font
+:imagesdir: img_route_style
+:stylesdir: ./
+:stylesheet: default.css
+:linkcss:
+
+// Substitutions...
+:prg:     pass:q[`pcb-rnd`]
+:yes:     icon:check[role="green"]
+:no:      icon:times[role="red"]
+
+= Route style GUI design
+
+[abstract]
+== Abstract
+
+This document is a WIP, working document, mixture of many sources of documentation
+linked to the <<img-gtk2_gui, Route Style>> GUI part, as presented to the user.
+
+PCB means PCB/gEDA, or mainline, {prg} is the primary focus for this WIP.
+
+:experimental:
+:numbered:
+== Introduction
+
+=== What is a Route Style
+
+The `menu:Edit[Route Styles]` menu allows you to select a style which is a group
+of line thickness, via diameter, via drill size, and clearance (keepaway)
+(collectively called a _routing style_) to be copied to the _active_ sizes.
+You can also change the names given to the routing styles and adjust their
+values from `menu:Edit[Route Styles > Edit]` menu.
+
+The active sizes are also adjustable from this menu (How ?).
+The active sizes are shown in the status-line and control the initial size of
+new vias, drilling holes, lines, clearances, text-objects and also
+the maximum dimensions of the board layout.
+
+A routing style can be attributed to a net. (How ?, How am I sure all the
+nets/lines/tracks are affected to the selected routing style ?)
+
+=== Using the autorouter
+
+Do we still have the autorouter ? Is what is described next working elsewhere ?
+
+Use routing styles in the netlist to have per-net routing styles.
+Note that the routing style will be used for an entire net.
+This means if you have a wide metal setting for a power net you will need to
+manually route breakouts from any fine pitch parts on their power pins because
+the router will not be able to change to a narrow trace to connect to the part.
+
+== Design intentions
+
+=== {prg} goals
+
+* Alleviate the limitation of 4 only different route styles.
+* Keep track of "current" route style
+
+=== {prg} implementation prior 1.2.1
+
+A radio-button area + extra <<img-gtk2-edit_route, dialog>>
+
+==== Add a new route style
+
+This is ensured via the `<New>` selection
+
+[[img-gtk2-edit_route]]
+.Edit route styles dialog
+image::gtk2-edit_route_styles_001.png[]
+
+Q: No `Add` button: historical reasons. The original code in mainline
+has 4 route styles, hardwired. It can not remove styles.
+We inherited the mechanism of adding style by selecting the `<New>`.
+(In mainline if you add styles more than 4, they are lost on save).
+
+The inherited code tries not to do modifications immediately but only when
+you close the window. This is a common pattern in the gtk hid at the
+moment: all data from core copied to some "hid_gtk-specific" mirror cache
+for the dialog, then the dialog works on the cache and it is copied back
+when you close the dialog.
+
+Igor2 thinks the idea was that the dialogs are modal and if the user says
+cancel, you just don't do the copy-back. It's a lot of extra code and complication.
+The strange <new style> mechanism might be a result of this: the dialog-cache
+is probably not smart enough to hold multiple new styles, but with
+the current mechanism you can add only one new style until you close the dialog.
+
+==== Keep track of current route style
+
+This is ensured via the `<custom>` selection in <<img-gtk2-edit_route, dialog>>.
+
+At the end you are not drawing with the selected style, you are drawing
+with a pen. When you change style, all parameters of the style
+are copied into the pen. However, you can change any parameter of
+the pen with hotkeys, which means you can easily end up drawing with a pen
+that does not match any of the currently existing styles.
+
+Mainline has this too, it's all inherited.
+
+Using such a custom pen is useful when you want to draw a
+single net of some special geometry - it is not worth adding a
+new style, but you may still want to set the temporary pen up properly.
+
+The problem was that when you used such a custom pen, you didn't really
+have a way to see your current setting and besides the `add +5 mils` kind of
+hotkeys, you couldn't really set it up, e.g.
+"I want 80 mil wide traces temporarily"
+was hard to do. So I introduced the `<current>` style, which shows the current
+settings of the pen so it is not hidden anymore.
+
+NOTE: Lapsus here from Igor, who really means <current>. I suggest to rename it <current> ??
+
+This way you can see and change all parameters of the pen, without having to
+create a new style or having to use CLI actions.
+
+Igor2 definitely wants to keep `<custom>` in the gtk2 hid, wants to add it in the
+lesstif hid and wants all new GUI hids to support it the same way.
+
+
+`<current>` mode is indicated by not selecting any style (no radio button selected).
+As long as your pen matches any of the existing style, you are drawing with
+that style and the style is marked in the radio button.
+When you change your pen to something that doesn't match any existing style,
+the radio button turns off.
+
+This is by design, Igor2 likes it, miloh, with whom we coded it likes it too.
+Please do not change this.
+
+PCB Mainline does the same, except:
+
+* you can't see or modify the numeric fields of the `<custom>` style
+  directly (only modification possible is via hotkeys)
+* you can't explicitly switch to the `<custom>` style (you need to make a
+  hotkey-modification of the pen)
+
+But the pen concept exists there too: press kbd:[Ctrl+Shift+V], it will change
+the via drill size of the pen. This will result in a pen not matching
+any existing style -> radio button selection disappears.
+
+=== PCB
+
+mainline has no explicit <custom>, no delete button and has the hardwired number of 4 styles.
+
+=== {prg} Next
+
+Honestly, I don't like it and want to change it (in all dialog boxes,even in gtk2):
+
+* I want the dialog boxes non-modal: you should be able to edit the layout while
+  the route style dialog is open
+* I want changes to happen immediately - so if you change the line
+  width for a style and draw with it, it should have immediate effect
+* I want to add undo code for the route style changes; I think the original
+  idea behind. Combining non-modal dialog and immediate effect makes cancel
+  meaningless, but if the user has the usual, central undo, that's fine.
+
+== GTK2 situation
+
+=== User manual
+
+Document this part... Most of the info are above. Select and create a section
+-> See FIXME.
+
+Especially, document `Attributes`
+
+* what for ?
+* expected key, values ?
+* format ? units ?
+
+[[img-gtk2_gui]]
+.{prg} on an empty design, with Edit Route Style dialog open
+image::gtk2-pcb-rnd_001.png[]
+
+IMPORTANT: Where is `saved "as default"` ? Documentation here ?
+
+=== Short-term improvements ?
+
+This seems to be low priority w.r.t. cairo and GTK3... Am I right ?
+
+== GTK3 design proposal
+
+TODO: A mock-up (screenshot)
+
+A `GtkTreeView`, allowing the direct rename of style, allow sorting, or drag
+and drop the styles to change order.
+
+Can be selected (highlighted) to show the active route style.
+
+`GtkButtonBox` with usual buttons : Add, Delete, Raise, Down ...
+
+Still another dialog is needed for other infos...
+
+== GTK2 retro-fit ?
+
+If so, then trade for a less advanced GtkTreeView
+
+`GtkHButtonBox` i.s.o `GtkButtonBox`.
diff --git a/doc/developer/hid_gtk3/route_style.html b/doc/developer/hid_gtk3/route_style.html
new file mode 100644
index 0000000..91065b5
--- /dev/null
+++ b/doc/developer/hid_gtk3/route_style.html
@@ -0,0 +1,354 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.5">
+<meta name="author" content="Alain">
+<title>Route style GUI design</title>
+<link rel="stylesheet" href="./default.css">
+</head>
+<body class="article toc2 toc-left">
+<div id="header">
+<h1>Route style GUI design</h1>
+<div class="details">
+<span id="author" class="author">Alain</span><br>
+</div>
+<div id="toc" class="toc2">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel1">
+<li><a href="#_abstract">Abstract</a></li>
+<li><a href="#_introduction">1. Introduction</a>
+<ul class="sectlevel2">
+<li><a href="#_what_is_a_route_style">1.1. What is a Route Style</a></li>
+<li><a href="#_using_the_autorouter">1.2. Using the autorouter</a></li>
+</ul>
+</li>
+<li><a href="#_design_intentions">2. Design intentions</a>
+<ul class="sectlevel2">
+<li><a href="#__code_pcb_rnd_code_goals">2.1. <code>pcb-rnd</code> goals</a></li>
+<li><a href="#__code_pcb_rnd_code_implementation_prior_1_2_1">2.2. <code>pcb-rnd</code> implementation prior 1.2.1</a></li>
+<li><a href="#_pcb">2.3. PCB</a></li>
+<li><a href="#__code_pcb_rnd_code_next">2.4. <code>pcb-rnd</code> Next</a></li>
+</ul>
+</li>
+<li><a href="#_gtk2_situation">3. GTK2 situation</a>
+<ul class="sectlevel2">
+<li><a href="#_user_manual">3.1. User manual</a></li>
+<li><a href="#_short_term_improvements">3.2. Short-term improvements ?</a></li>
+</ul>
+</li>
+<li><a href="#_gtk3_design_proposal">4. GTK3 design proposal</a></li>
+<li><a href="#_gtk2_retro_fit">5. GTK2 retro-fit ?</a></li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_abstract">Abstract</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>This document is a WIP, working document, mixture of many sources of documentation
+linked to the <a href="#img-gtk2_gui">Route Style</a> GUI part, as presented to the user.</p>
+</div>
+<div class="paragraph">
+<p>PCB means PCB/gEDA, or mainline, <code>pcb-rnd</code> is the primary focus for this WIP.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_introduction">1. Introduction</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_what_is_a_route_style">1.1. What is a Route Style</h3>
+<div class="paragraph">
+<p>The <code><span class="menuseq"><span class="menu">Edit</span> ▸ <span class="menuitem">Route Styles</span></span></code> menu allows you to select a style which is a group
+of line thickness, via diameter, via drill size, and clearance (keepaway)
+(collectively called a <em>routing style</em>) to be copied to the <em>active</em> sizes.
+You can also change the names given to the routing styles and adjust their
+values from <code><span class="menuseq"><span class="menu">Edit</span> ▸ <span class="submenu">Route Styles</span> ▸ <span class="menuitem">Edit</span></span></code> menu.</p>
+</div>
+<div class="paragraph">
+<p>The active sizes are also adjustable from this menu (How ?).
+The active sizes are shown in the status-line and control the initial size of
+new vias, drilling holes, lines, clearances, text-objects and also
+the maximum dimensions of the board layout.</p>
+</div>
+<div class="paragraph">
+<p>A routing style can be attributed to a net. (How ?, How am I sure all the
+nets/lines/tracks are affected to the selected routing style ?)</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_using_the_autorouter">1.2. Using the autorouter</h3>
+<div class="paragraph">
+<p>Do we still have the autorouter ? Is what is described next working elsewhere ?</p>
+</div>
+<div class="paragraph">
+<p>Use routing styles in the netlist to have per-net routing styles.
+Note that the routing style will be used for an entire net.
+This means if you have a wide metal setting for a power net you will need to
+manually route breakouts from any fine pitch parts on their power pins because
+the router will not be able to change to a narrow trace to connect to the part.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_design_intentions">2. Design intentions</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="__code_pcb_rnd_code_goals">2.1. <code>pcb-rnd</code> goals</h3>
+<div class="ulist">
+<ul>
+<li>
+<p>Alleviate the limitation of 4 only different route styles.</p>
+</li>
+<li>
+<p>Keep track of "current" route style</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect2">
+<h3 id="__code_pcb_rnd_code_implementation_prior_1_2_1">2.2. <code>pcb-rnd</code> implementation prior 1.2.1</h3>
+<div class="paragraph">
+<p>A radio-button area + extra <a href="#img-gtk2-edit_route">dialog</a></p>
+</div>
+<div class="sect3">
+<h4 id="_add_a_new_route_style">2.2.1. Add a new route style</h4>
+<div class="paragraph">
+<p>This is ensured via the <code><New></code> selection</p>
+</div>
+<div id="img-gtk2-edit_route" class="imageblock">
+<div class="content">
+<img src="img_route_style/gtk2-edit_route_styles_001.png" alt="gtk2 edit route styles 001">
+</div>
+<div class="title">Figure 1. Edit route styles dialog</div>
+</div>
+<div class="paragraph">
+<p>Q: No <code>Add</code> button: historical reasons. The original code in mainline
+has 4 route styles, hardwired. It can not remove styles.
+We inherited the mechanism of adding style by selecting the <code><New></code>.
+(In mainline if you add styles more than 4, they are lost on save).</p>
+</div>
+<div class="paragraph">
+<p>The inherited code tries not to do modifications immediately but only when
+you close the window. This is a common pattern in the gtk hid at the
+moment: all data from core copied to some "hid_gtk-specific" mirror cache
+for the dialog, then the dialog works on the cache and it is copied back
+when you close the dialog.</p>
+</div>
+<div class="paragraph">
+<p>Igor2 thinks the idea was that the dialogs are modal and if the user says
+cancel, you just don’t do the copy-back. It’s a lot of extra code and complication.
+The strange <new style> mechanism might be a result of this: the dialog-cache
+is probably not smart enough to hold multiple new styles, but with
+the current mechanism you can add only one new style until you close the dialog.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_keep_track_of_current_route_style">2.2.2. Keep track of current route style</h4>
+<div class="paragraph">
+<p>This is ensured via the <code><custom></code> selection in <a href="#img-gtk2-edit_route">dialog</a>.</p>
+</div>
+<div class="paragraph">
+<p>At the end you are not drawing with the selected style, you are drawing
+with a pen. When you change style, all parameters of the style
+are copied into the pen. However, you can change any parameter of
+the pen with hotkeys, which means you can easily end up drawing with a pen
+that does not match any of the currently existing styles.</p>
+</div>
+<div class="paragraph">
+<p>Mainline has this too, it’s all inherited.</p>
+</div>
+<div class="paragraph">
+<p>Using such a custom pen is useful when you want to draw a
+single net of some special geometry - it is not worth adding a
+new style, but you may still want to set the temporary pen up properly.</p>
+</div>
+<div class="paragraph">
+<p>The problem was that when you used such a custom pen, you didn’t really
+have a way to see your current setting and besides the <code>add +5 mils</code> kind of
+hotkeys, you couldn’t really set it up, e.g.
+"I want 80 mil wide traces temporarily"
+was hard to do. So I introduced the <code><current></code> style, which shows the current
+settings of the pen so it is not hidden anymore.</p>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<div class="title">Note</div>
+</td>
+<td class="content">
+Lapsus here from Igor, who really means <current>. I suggest to rename it <current> ??
+</td>
+</tr>
+</table>
+</div>
+<div class="paragraph">
+<p>This way you can see and change all parameters of the pen, without having to
+create a new style or having to use CLI actions.</p>
+</div>
+<div class="paragraph">
+<p>Igor2 definitely wants to keep <code><custom></code> in the gtk2 hid, wants to add it in the
+lesstif hid and wants all new GUI hids to support it the same way.</p>
+</div>
+<div class="paragraph">
+<p><code><current></code> mode is indicated by not selecting any style (no radio button selected).
+As long as your pen matches any of the existing style, you are drawing with
+that style and the style is marked in the radio button.
+When you change your pen to something that doesn’t match any existing style,
+the radio button turns off.</p>
+</div>
+<div class="paragraph">
+<p>This is by design, Igor2 likes it, miloh, with whom we coded it likes it too.
+Please do not change this.</p>
+</div>
+<div class="paragraph">
+<p>PCB Mainline does the same, except:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>you can’t see or modify the numeric fields of the <code><custom></code> style
+directly (only modification possible is via hotkeys)</p>
+</li>
+<li>
+<p>you can’t explicitly switch to the <code><custom></code> style (you need to make a
+hotkey-modification of the pen)</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>But the pen concept exists there too: press <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>V</kbd></span>, it will change
+the via drill size of the pen. This will result in a pen not matching
+any existing style → radio button selection disappears.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_pcb">2.3. PCB</h3>
+<div class="paragraph">
+<p>mainline has no explicit <custom>, no delete button and has the hardwired number of 4 styles.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="__code_pcb_rnd_code_next">2.4. <code>pcb-rnd</code> Next</h3>
+<div class="paragraph">
+<p>Honestly, I don’t like it and want to change it (in all dialog boxes,even in gtk2):</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>I want the dialog boxes non-modal: you should be able to edit the layout while
+the route style dialog is open</p>
+</li>
+<li>
+<p>I want changes to happen immediately - so if you change the line
+width for a style and draw with it, it should have immediate effect</p>
+</li>
+<li>
+<p>I want to add undo code for the route style changes; I think the original
+idea behind. Combining non-modal dialog and immediate effect makes cancel
+meaningless, but if the user has the usual, central undo, that’s fine.</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_gtk2_situation">3. GTK2 situation</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_user_manual">3.1. User manual</h3>
+<div class="paragraph">
+<p>Document this part…​ Most of the info are above. Select and create a section
+→ See FIXME.</p>
+</div>
+<div class="paragraph">
+<p>Especially, document <code>Attributes</code></p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>what for ?</p>
+</li>
+<li>
+<p>expected key, values ?</p>
+</li>
+<li>
+<p>format ? units ?</p>
+</li>
+</ul>
+</div>
+<div id="img-gtk2_gui" class="imageblock">
+<div class="content">
+<img src="img_route_style/gtk2-pcb-rnd_001.png" alt="gtk2 pcb rnd 001">
+</div>
+<div class="title">Figure 2. <code>pcb-rnd</code> on an empty design, with Edit Route Style dialog open</div>
+</div>
+<div class="admonitionblock important">
+<table>
+<tr>
+<td class="icon">
+<div class="title">Important</div>
+</td>
+<td class="content">
+Where is <code>saved "as default"</code> ? Documentation here ?
+</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_short_term_improvements">3.2. Short-term improvements ?</h3>
+<div class="paragraph">
+<p>This seems to be low priority w.r.t. cairo and GTK3…​ Am I right ?</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_gtk3_design_proposal">4. GTK3 design proposal</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>TODO: A mock-up (screenshot)</p>
+</div>
+<div class="paragraph">
+<p>A <code>GtkTreeView</code>, allowing the direct rename of style, allow sorting, or drag
+and drop the styles to change order.</p>
+</div>
+<div class="paragraph">
+<p>Can be selected (highlighted) to show the active route style.</p>
+</div>
+<div class="paragraph">
+<p><code>GtkButtonBox</code> with usual buttons : Add, Delete, Raise, Down …​</p>
+</div>
+<div class="paragraph">
+<p>Still another dialog is needed for other infos…​</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_gtk2_retro_fit">5. GTK2 retro-fit ?</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>If so, then trade for a less advanced GtkTreeView</p>
+</div>
+<div class="paragraph">
+<p><code>GtkHButtonBox</code> i.s.o <code>GtkButtonBox</code>.</p>
+</div>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2017-02-11 19:25:04 CET
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/doc/developer/hid_remote/proto_high.html b/doc/developer/hid_remote/proto_high.html
index 02cfe46..776f6ab 100644
--- a/doc/developer/hid_remote/proto_high.html
+++ b/doc/developer/hid_remote/proto_high.html
@@ -57,34 +57,49 @@ Same as inval(x1 x2 y1 y2) but invalidates the whole screen.
 <p>
 Arguments: none
 
-<h3> newly(name id flags groups) </h3>
-Inform the client that the next set of drawing commands are for a specific
-layer.
+<h3> newlg(name group_id flags) </h3>
+Create a new layer group.
 <p>
 Arguments:
 <ul>
-	<li> name: name of the layer (can be empty)
-	<li> id: unique group ID (decimal integer)
+	<li> name: name of the layer group - names are <b>not</b> unique
+	<li> group_id: unique group ID (decimal integer, may be large)
 	<li> flags: a list of 3 items: location, purpose and properties. Each item is a list of values (or an empty list).
-	<li> group: group ID; layers in the same group are turned on/off together and are considered to be on the same physical layer; -1 means not part of any group
 </ul>
 <p>
 Example:
 <pre>
-newly(bottomassembly 16777226 ((bottom) (assy) (virtual)) -1)
+newlg(topassembly 16777219 ((top) (assy) (virtual)))
 </pre>
-Creates the bottom assembly virtual layer with ID 16777226. It is not part of
-any layer group and is called "bottomassembly".
+Creates the top assembly virtual layer with ID 16777219 with the name
+of "topassembly"
 
-<h3> setlg(group_id group_flags is_empty) </h3>
+<h3> newly(name layer_id group_id) </h3>
+Create a new layer within an existing layer group.
+<p>
+Arguments:
+<ul>
+	<li> name: name of the layer (can be empty, <b>not</b> unique)
+	<li> layer_id: unique ID of this layer (decimal integer, may be large)
+	<li> group_id: reference to a previously created layer group which this layer is part of
+</ul>
+<p>
+Example:
+<pre>
+newly(soldergnd 3 11)
+</pre>
+Creates a layer 3 called "soldergnd" in group 11.
+
+<h3> setlg(group_id is_empty) </h3>
 Inform the client that the next set of drawing commands are for a specific
-layer group.
+layer group. (Note: the reason for announcing groups and not layers:
+all layers in that group are drawn at once; visibility
+of layers within the same group are switched together.)
 <p>
 Arguments:
 <ul>
 	<li> group_id: unique ID of the layer group
-	<li> flags: TODO
-	<li> is_empty: 1 if the layer group may be empty, 0 if the layer is not empty
+	<li> is_empty: 1 if the layer group may be empty, 0 if the layer is not empty (TODO: this bit is not 100% reliable yet)
 </ul>
 
 <h3> makeGC() </h3>
@@ -95,9 +110,6 @@ The ID uniquely identifies the GC; it should be small positive integer
 <p>
 Arguments: none
 
-
-
-
 <h3> delGC(ID) </h3>
 Inform the client that a given GC is not needed anymore. The server
 will not reference the GC again and the GC can be destroyed (but graphics
diff --git a/doc/developer/mods3/after.png b/doc/developer/mods3/after.png
index e69de29..a3980ee 100644
Binary files a/doc/developer/mods3/after.png and b/doc/developer/mods3/after.png differ
diff --git a/doc/developer/mods3/export.png b/doc/developer/mods3/export.png
index 57f0cb1..b34aa26 100644
Binary files a/doc/developer/mods3/export.png and b/doc/developer/mods3/export.png differ
diff --git a/doc/developer/mods3/feature.png b/doc/developer/mods3/feature.png
index 3b6c9a1..2ba958a 100644
Binary files a/doc/developer/mods3/feature.png and b/doc/developer/mods3/feature.png differ
diff --git a/doc/developer/mods3/gen.sh b/doc/developer/mods3/gen.sh
index a3a59d9..7a03adf 100755
--- a/doc/developer/mods3/gen.sh
+++ b/doc/developer/mods3/gen.sh
@@ -30,7 +30,7 @@ echo "#autogenerated by gen.sh" > after.pie
 echo Core >&2
 tmp=/tmp/pcb-mods-stat
 mkdir $tmp
-cp -r ../../src/*.c ../../src/*.h ../../src/Makefile* $tmp
+cp -r ../../../src/*.c ../../../src/*.h ../../../src/Makefile* $tmp
 code_size=`sloc $tmp`
 gen_pie "core" $code_size "#00ff88" >> after.pie
 
diff --git a/doc/developer/mods3/hid.png b/doc/developer/mods3/hid.png
index 5438001..0ff8556 100644
Binary files a/doc/developer/mods3/hid.png and b/doc/developer/mods3/hid.png differ
diff --git a/doc/developer/mods3/import.png b/doc/developer/mods3/import.png
index 09f9943..f91ca4f 100644
Binary files a/doc/developer/mods3/import.png and b/doc/developer/mods3/import.png differ
diff --git a/doc/developer/mods3/index.html b/doc/developer/mods3/index.html
index 937967f..3a94d41 100644
--- a/doc/developer/mods3/index.html
+++ b/doc/developer/mods3/index.html
@@ -101,7 +101,7 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
 <td> Automatically place elements. 
-<tr><th align=left>autoroute<td>4341
+<tr><th align=left>autoroute<td>4360
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
@@ -133,17 +133,22 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
 <td> Same as distalign, operates on text objects. 
-<tr><th align=left>djopt<td>2320
+<tr><th align=left>djopt<td>2331
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
 <td> Various board optimization algorithms. 
-<tr><th align=left>draw_fab<td>257
+<tr><th align=left>draw_csect<td>575
+<td  > WIP
+<td bgcolor="lightgreen"> buildin
+<td> (feature)
+<td> Draw cross section and layer map. 
+<tr><th align=left>draw_fab<td>255
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
 <td> Draw the fab layer (for various exporters). 
-<tr><th align=left>export_bboard<td>410
+<tr><th align=left>export_bboard<td>417
 <td  > WIP
 <td bgcolor="red"> disabled
 <td> export
@@ -153,22 +158,22 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> export
 <td> Export bom (Bill of Materials) 
-<tr><th align=left>export_dsn<td>447
-<td  > Work-in-progress
-<td bgcolor="red"> disable
+<tr><th align=left>export_dsn<td>453
+<td bgcolor="lightgreen" > works
+<td > enabled
 <td> export
 <td> Export specctra .dsn files 
-<tr><th align=left>export_dxf<td>3987
+<tr><th align=left>export_dxf<td>3980
 <td  > WIP
 <td bgcolor="red"> disabled
 <td> export
 <td> Export dxf 
-<tr><th align=left>export_gcode<td>2470
+<tr><th align=left>export_gcode<td>2472
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> export
 <td> Export to gcode 
-<tr><th align=left>export_gerber<td>939
+<tr><th align=left>export_gerber<td>989
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> export
@@ -183,32 +188,32 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> export
 <td> Export to lpr (using export_ps to generate postscript) 
-<tr><th align=left>export_nelma<td>668
+<tr><th align=left>export_nelma<td>670
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> export
 <td> Export to nelma (Numerical capacitance calculator) 
-<tr><th align=left>export_openscad<td>1373
+<tr><th align=left>export_openscad<td>1380
 <td  > WIP
 <td bgcolor="red"> disabled
 <td> export
 <td> Export openscad 
-<tr><th align=left>export_png<td>1090
+<tr><th align=left>export_png<td>1112
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> export
 <td> Export to png, gif and jpeg 
-<tr><th align=left>export_ps<td>1623
+<tr><th align=left>export_ps<td>1634
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> export
 <td> Export postscript or embedded postscript. 
-<tr><th align=left>export_stat<td>259
+<tr><th align=left>export_stat<td>265
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> export
 <td> Export various board statistics in lihata format 
-<tr><th align=left>export_svg<td>562
+<tr><th align=left>export_svg<td>565
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> export
@@ -224,7 +229,7 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> export
 <td> Export XY centroid element data for pick & place. 
-<tr><th align=left>fontmode<td>165
+<tr><th align=left>fontmode<td>168
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
@@ -245,35 +250,40 @@ Below is a table with the summary of core plugins.
 <td bgcolor="red"> disabled
 <td> (feature)
 <td> Common gl functions for hids. 
-<tr><th align=left>gpmi<td>3221
+<tr><th align=left>gpmi<td>3215
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <br> (if gpmi is installed)
 <td> (feature)
 <td> Scriptable plugin system with about 10 scripting languages supported and dynamic load/unload of scripts that can manipulate the GUI, the board, can implement exporters, etc. 
-<tr><th align=left>hid_batch<td>317
+<tr><th align=left>hid_batch<td>315
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> hid
 <td> HID without GUI; read actions from stdin. 
-<tr><th align=left>hid_gtk<td>16287
+<tr><th align=left>hid_gtk<td>9755
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> hid
 <td> GUI: the GTK HID. 
-<tr><th align=left>hid_lesstif<td>6919
+<tr><th align=left>hid_gtk3<td>25
+<td  > WIP
+<td bgcolor="red"> disable
+<td> hid
+<td> GUI: the GTK3 HID, using cairo for rendering 
+<tr><th align=left>hid_lesstif<td>6875
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> hid
 <td> GUI: the lesstif HID. 
-<tr><th align=left>hid_remote<td>1116
+<tr><th align=left>hid_remote<td>1171
 <td  > WIP
 <td bgcolor="red"> disable
 <td> hid
 <td> Remote access HID: implement a protocol and use it to relay between a core and a remote HID implementation. 
-<tr><th align=left>import_dsn<td>115
-<td  > Work-in-progress
-<td bgcolor="red"> disable
+<tr><th align=left>import_dsn<td>233
+<td bgcolor="lightgreen" > works
+<td > enabled
 <td> import
 <td> Import specctra .dsn files 
 <tr><th align=left>import_edif<td>3624
@@ -281,11 +291,21 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> import
 <td> Import plugin for netlists in the EDIF format. 
-<tr><th align=left>import_hyp<td>1547
+<tr><th align=left>import_hyp<td>2400
 <td  > WIP
 <td bgcolor="red"> disable
 <td> import
 <td> Import plugin for hyperlynx geometry. 
+<tr><th align=left>import_ltspice<td>504
+<td bgcolor="lightgreen" > works
+<td bgcolor="lightgreen"> buildin
+<td> import
+<td> Import the netlist and footprints from an ltspice .asc and .net pair of files 
+<tr><th align=left>import_mucs<td>108
+<td bgcolor="lightgreen" > works
+<td > builtin
+<td> import
+<td> Import lines and vias from MUCS unixplot .pl files 
 <tr><th align=left>import_netlist<td>136
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
@@ -296,7 +316,12 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> import
 <td> Imports element and netlist data from the schematics (or some other source). 
-<tr><th align=left>io_kicad<td>2987
+<tr><th align=left>import_tinycad<td>147
+<td bgcolor="lightgreen" > works
+<td bgcolor="lightgreen"> buildin
+<td> import
+<td> Import the netlist and footprints from a tinycad netlist. 
+<tr><th align=left>io_kicad<td>3060
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> io
@@ -306,12 +331,12 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> io
 <td> Export the design and elements in Kicad's legacy format. 
-<tr><th align=left>io_lihata<td>1973
+<tr><th align=left>io_lihata<td>2097
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> io
 <td> Load and save the design and elements in the lihata board format. 
-<tr><th align=left>io_pcb<td>2200
+<tr><th align=left>io_pcb<td>2207
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> io
@@ -326,6 +351,11 @@ Below is a table with the summary of core plugins.
 <td bgcolor="red"> disabled
 <td> (lib)
 <td> S-expression parser lib 
+<tr><th align=left>lib_gtk_common<td>6915
+<td bgcolor="lightgreen" > works
+<td bgcolor="red"> disabled
+<td> (lib)
+<td> hid_gtk* common code (regardless of gtk version or drawing mechanism: for  both gtk2 and gtk3 and for both sw rendering and gl) 
 <tr><th align=left>lib_legacy_func<td>87
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
@@ -381,7 +411,7 @@ Below is a table with the summary of core plugins.
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
 <td> Report() and ReportObject() actions - print a report about design objects. 
-<tr><th align=left>rubberband_orig<td>599
+<tr><th align=left>rubberband_orig<td>668
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
@@ -401,17 +431,11 @@ Below is a table with the summary of core plugins.
 <td bgcolor="red"> disabled
 <td> (feature)
 <td> Gesture recognition with libstroke. 
-<tr><th align=left>teardrops<td>226
+<tr><th align=left>teardrops<td>232
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
 <td> (feature)
 <td> Draw teardrops on pins. 
-<tr><th align=left>toporouter<td>6161
-<td bgcolor="red" > fails
-<br> (infinite loop in gts)
-<td bgcolor="red"> disabled
-<td> (feature)
-<td> Automatically route selected or all rats using a topological algorithm. This is the new autorouter from 2009. 
 <tr><th align=left>vendordrill<td>516
 <td bgcolor="lightgreen" > works
 <td bgcolor="lightgreen"> buildin
diff --git a/doc/developer/mods3/io.png b/doc/developer/mods3/io.png
index 8da3757..be4f231 100644
Binary files a/doc/developer/mods3/io.png and b/doc/developer/mods3/io.png differ
diff --git a/doc/developer/mods3/lib.png b/doc/developer/mods3/lib.png
index ea68b9a..75e2d83 100644
Binary files a/doc/developer/mods3/lib.png and b/doc/developer/mods3/lib.png differ
diff --git a/doc/developer/mods3/mods.png b/doc/developer/mods3/mods.png
index 7a14b28..89d5ceb 100644
Binary files a/doc/developer/mods3/mods.png and b/doc/developer/mods3/mods.png differ
diff --git a/doc/developer/renames b/doc/developer/renames
index 1301dc7..1a16860 100644
--- a/doc/developer/renames
+++ b/doc/developer/renames
@@ -737,7 +737,7 @@ LinePoly -> pcb_poly_from_line
 ArcPoly -> pcb_poly_from_arc
 PinPoly -> pcb_poly_from_pin
 BoxPolyBloated -> pcb_poly_from_box_bloated
-frac_circle -> pcb_poly_frac_cicle
+frac_circle -> pcb_poly_frac_circle
 InitClip -> pcb_poly_init_clip
 RestoreToPolygon -> pcb_poly_restore_to_poly
 ClearFromPolygon -> pcb_poly_clear_from_poly
diff --git a/doc/devlog/20170205_schimp.html b/doc/devlog/20170205_schimp.html
new file mode 100644
index 0000000..9678027
--- /dev/null
+++ b/doc/devlog/20170205_schimp.html
@@ -0,0 +1,35 @@
+<html>
+<body>
+<h1> pcb-rnd <a href="http://repo.hu/projects/pcb-rnd/devlog">devlog</a> </h1>
+
+<H2> what's needed for schematics -> pcb-rnd </H2>
+If a path between a schematics capture program and pcb-rnd is to be implemented,
+the following information needs to be passed:
+<ul>
+	<li> schematics -> pcb (forward annotation)
+		Any file format the schematics tool prefers and delivers at least this
+		set of information:
+		<ul>
+			<li> Each component/part needs an unique identifier, a "refdes", e.g. R1, U4.
+			<li> Each pin/pad needs an unique identifier within it's component/part, so at the end "U4-3" uniquely identifies pin 3 of component U4.
+			<li> Each component/part needs a footprint (a free form text). Optionally arbitrary user specified key=value pairs per part can solve this and a lot more.
+			<li> A list of named networks. Optionally with user specified key=value pairs per network (less important here).
+			<li> A list of component-pin pairs per network.
+			<li> The netlist can be flat or hierarhic.
+		</ul>
+
+	<li> pcb -> schematics (back annotation)
+		pcb-rnd emits a netlist patch described
+		<a href="20150830b_back_ann.html"> here </a>, but it
+		could emit any other format the schematics tool needs. The schematics tool
+		would need to understand the following concepts while reading a back
+		annotation file:
+		<ul>
+			<li> Unique part refdes and pin number, as above
+			<li> Named networks, as above
+			<li> "this is how the network looked like when we started" (net name, list of pins)
+			<li> "the user removed this pin from that network" operation
+			<li> "the user added this pin from that network" operation
+			<li> optional: "the user changed this key=value pair of this part"
+		</ul>
+</ul>
diff --git a/doc/devlog/20170212_ecosys.html b/doc/devlog/20170212_ecosys.html
new file mode 100644
index 0000000..d1c2d8c
--- /dev/null
+++ b/doc/devlog/20170212_ecosys.html
@@ -0,0 +1,154 @@
+<html>
+<body>
+<h1> pcb-rnd <a href="http://repo.hu/projects/pcb-rnd/devlog">devlog</a> </h1>
+
+<H2> The FOS EDA ecosystem and pcb-rnd in it</H2>
+
+<H3> current scene of EDA tools </H3>
+<p>
+There are some large, proprietary EDA tools out there. Most of them are
+monolithic and many of them actively seek legal and technical measures
+against free flow of data - as part of the lock-in model, vendors
+often prefer users to exclusively use their tool once they started to use
+it with a design. <i>It seems most users are happy with this setup.</i>
+<p>
+Sometimes large open source software projects are also built in a monolithic
+approach. It sometimes makes it easier for the users of the above proprietary
+software to switch to a free tool if the free tool has a similar monolithic
+design. However, for smaller, specialized tools, it might be as hard to
+join the flow of such a monolithic free tool, as in the flow of a proprietary tool.
+Not because of technical measures, but because of how users regard and use
+the software.<sup><a href="#footnote1">1</a></sup>
+<p>
+An UNIX approach would be to provide a set of tools each doing a small
+part of the job, being able to communicate to each other, and let the user
+find the workflows (and combinations) that fit their needs. We already have
+such tools available: the gEDA project is a collection of them, but other
+projects like QUCS, PetEd, TinyCAD, nicely fit too. But how could a random
+selection of unrelated tools, developed independently by different people
+compete with an integrated solution? My proposal is: by converting them into
+an <i>ecosystem</i>.
+
+<H3> An EDA ecosystem </H3>
+<p>
+The key is to connect all the little tools in meaningful ways. In an ideal
+worlds, there would a one universal format (like line based plain text in
+UNIX) that all files could operate on. Unfortunately we are not living in
+an ideal world. Still, we could get pairs or even small groups of tools
+to temporarily work together by writing converters and import/export modules.
+Let's just build random bridges between random tools, without worrying about
+how general a given bridge is as long as it fully functions between 2 specific
+tools!
+<p>
+The next thing we'd need to do is to present a large number of examples and
+tutorials explaining how these flows can be used. This would make it easier
+for users to explore the ecosystem and even find new, unexpected ways to use it.
+(This obviously won't be appealing for some users who really just prefer
+an integrated solution with out-of-the-box icons - but we should just target
+the rest of the users with the ecosystem approach.)
+<p>
+Then we should stop worrying about packing and distributing the tools. Let it
+be done by professionals, e.g. package maintainers of Linux distributions. When
+we write pcb-rnd, we should worry about how we import schematics from TinyCAD,
+we should write the import plugin, we should present tutorials and documentations
+explaining this flow, but we shouldn't worry too much about how the user gets
+TinyCAD in the first place.
+<p>
+We should also give up some of our idealism. As Peter Clifton said in his
+2016 FOSDEM talk, this approach would end up in n*n converters for n tools.
+But I'd rather have n*n or even n*n/10 converters today than one perfect
+interchange tool that covers it all, earliest shipped in 2094. I believe
+the hardest part of this is <b>accepting alternatives</b>. Different
+projects choose different approaches, different design, different
+programming language, different data models. <i>This is not a bad thing,
+this is a good thing.</i> This is what gives us alternatives. Unfortunately
+this means code duplication, effort duplication, waste of human resources.
+But it's still much much cheaper than the loss we'd induce by forcing
+everyone to work on and use the One True Solution! That said, I don't
+suggest we should just always duplicate everything. I only say that we
+should accept the different goals and constraints of different project and
+accept that a specific piece of code or data can not always be reused as-is
+in another project, even despite of best intention of all parties.
+<p>
+Once we get past our fears of code duplication, and we build the bridges,
+we potentially get a large collection of independent utilities. This sort
+of joins and pools developer resources too. At the end, the sum of all
+developers, users, experience, knowledge, data and code behind such an
+ecosystem. even with the overheads subtracted, can overweight of those
+behind centralized monolithic projects. <i>This is how it could compete with
+those - not on the level of individual tools, but on the level of the whole
+ecosystem.</i>
+<p>
+There are well known examples of this setup. To list only two:
+<ul>
+	<li> the classic UNIX shell tools: shell, grep, sed, awk, tr, make, wc, tail, and a lot more; if we pick one, e.g. grep, and put only that on an alien system (e.g. windows), it is already useful - but it doesn't compete with the native tools found on that system. However, if we consider the whole ecosystem together, it is pretty much competitive. In fact we still use these tools daily.
+	<li> the ecosystems of each bigger modern scripting languages, such as python, perl, ruby, etc. Users and programmers of these languages heavily depend on the rich set of libraries and modules available. The ecosystem is not the interpreter alone, but the interpreter and the number of independently developed modules written by various individuals. Such ecosystems successfully compete even with commercial "we provide a procedure for every problem" kind of suites.
+</ul>
+
+<H3> What we'd need to do for this today </H3>
+<p>
+Much less than it first seems.
+<p>
+First we need to code the bridges. Do you maintain one of the tools?
+Find what other tools can be input to you and code importers on your side.
+Find what other tools can use your output and code exporters on your side.
+Really, it's that easy. You may want to contact the other tool's team, you
+may request and even get assistance, or you can even build a bridge that takes
+some coding on both sides. But it is not even required: most of the time, the
+simplest import or export module written on one side can solve the problem.
+Or write a converter. Can be a simple foo2bar for a single flow, shared as
+a mini-tool. If it's useful, it will become the part of the ecosystem.
+<p>
+If you did any of this, you are done with half of the job. We need good PR
+or else no one will know about this new bridge. Write a tutorials, blog
+posts. Show how this specific bridge can be used in a flow to produce
+something useful, even if it is just a blinking LED board.
+<p>
+Let distributions pick up the tools. Let blogs reference your tutorials. Let
+3rd party people collect a bunch of tutorials they found useful in a
+super-tutorial. When someone asks how to do something exotic on some
+public forum, and you know 2..3 tools that can be combined to do it, just
+tell them the solution. Don't mind if they'll be a one-time user of the
+toolchain, for this single shell pipeline to solve this one problem.
+
+<H3> What we are not REQUIRED to do </H3>
+In this section I list what we are not required to do, which doesn't
+mean we don't want to do these, or we can't do these or we shouldn't do these.
+It only means we could just do the cheap part today and worry about these
+tomorrow instead of getting blocked wondering how to solve these.
+<p>
+<b>Centralization:</b> it's not required to have a central organization or
+effort to coordinate such an ecosystem in any way. It may be useful to
+have such coordination in smaller clusters of the ecosystem, tho, but I
+don't think we should worry too much about this at all. If the tools and
+tutorials are available, and people found them useful, there would be multiple
+independent organizations doing the coordination in parallel - just how a 
+number of different Linux distributions package the same software, making sure
+all pieces work together. Both packaging and getting the packages work together
+are totally distribution-specific.
+<p>
+<b>Standardization:</b> e.g. standard, common file formats. Yes, life
+would be much easier if we had these already, but we can proceed without
+them. Let's waste some time today so we still have users by next week when
+we can come up with the common file format multiple tools accept.
+<p>
+<b>Packaging:</b> we don't have to invent our own packaging and distribution
+on the ecosystem-level. We don't need to worry how all the tools will land at
+the user. As long as each tool is easy to get and installed, let the user do
+it, or let 3rd parties (like Linux distributions) do it. We could also
+pack up random collections, but it may cause more trouble when it starts to
+interfere with local installations or distro installation.
+
+
+
+<hr>
+Footnotes:
+<br>
+<a id="footnote1"> 1: Some gEDA/PCB users are excited about the new features
+in pcb-rnd. They'd switch. When I ask what keeps them back, I often get
+this answer: "I'll finish my current design in gEDA/PCB but I will try
+pcb-rnd with my next design". Even if pcb-rnd is 100% compatible with gEDA/PCB
+for reading .pcb files. I call it the <i>invisible lock-in</i>: we do not
+have any technical measures that would keep users from switching between
+PCB and pcb-rnd forth and back but they act as if there was. Maybe they
+just got used to this lock-in idea too much with other CADs.
diff --git a/doc/devlog/20170213_edacore1.html b/doc/devlog/20170213_edacore1.html
new file mode 100644
index 0000000..60220a0
--- /dev/null
+++ b/doc/devlog/20170213_edacore1.html
@@ -0,0 +1,198 @@
+<html>
+<body>
+<h1> pcb-rnd <a href="http://repo.hu/projects/pcb-rnd/devlog">devlog</a> </h1>
+
+<H2> "Edacore" minimum commons</H2>
+<p>
+History and background: there is a lot happening in pcb-rnd these days. A set
+of these seem to nicely connect up and form something that's a big portion
+of the edacore idea, just implemented in a different way. We did not have
+a grand edacore-like plan behind these, they mostly started to happen
+independently. But they really happen to connect that way. In the same time
+edacore seems to be in hibernation. When I realized this, I contacted
+the edacore people to find out if they are interested in a reboot.
+<p>
+Naming: they haven't yet answered; for the purpose of this document, I'll
+use the name "edacore", but I mean it more like a concept than as a project
+name or implementation. It may be that it gets realized as a reboot of
+the original edacore and it will be the official name; else we will just find
+a different name for it.
+
+<H3> Acceptance and mutual respect </H3>
+<p>
+Before we start, we must accept that we have alternative implementations,
+different projects going in different directions. Although this means
+code and effort duplication, <i>this is not a bad thing, this is a good
+thing</i>. Most of us doesn't want to live in a world where there's only
+one EDA software available, even if every development effort is concentrated
+there. (If you think you do, then rethink it with substituting your favorite
+package with one you really dislike and imagine that's the only one available.)
+<p>
+Respecting the choices of another project seems to be simple in theory, but
+it is important to see a few examples of what we need to accept in practice.
+Else we make decisions tat are unacceptable for one project or another
+too easily. An incomplete list of examples of what differs in another EDA project:
+<ul>
+	<li> It has different goals. Aspects that are extremely important core
+	     concepts here are something to be avoided there.
+	<li> Different data model. Different way the tool models the world. Even,
+	     different subset of the world is modelled by to tool.
+	<li> Obviously, different code. This doesn't seem to be a big issue
+	     until a common effort accidentally starts to depend on it, e.g. because
+	     of the lib API.
+	<li> Different programming languages. Again shouldn't be a big deal, until
+	     you try to provide common code. As edacore spotted too, a plain C lib
+	     seems to be a common minimum for <b>most</b> of the world, but even
+	     there it might be something alien and can easily become a
+	     "why couldn't we just reimplement in OOP/python/ruby/java" question.
+	<li> Different design choices, even beyond the programming language.
+	     For example pcb-rnd walks the minilib way while gEDA/PCB goes for glib.
+	     This has many consequences: pcb-rnd is more portable, less dependent
+	     on GNU, compiles faster. In return we need to ship the minilibs with it
+	     and if someone joins the project they need to learn the APIs. Both choices
+	     are valid in their domain. If we want do anything common, we must make
+	     it neutral to such choices, else it's automatically locked out from
+	     some projects.
+</ul>
+In practice this means if we are to do anything common, shared, we either
+accept the ways of the other projects and come up with a minimal common
+denominator or the common/shared effort will be refused by some (or even most)
+projects we target. This has a few consequences, some requirements we
+must obey while designing the common:
+<ul>
+	<li> It should not interfere with any existing program, code, project
+	<li> It should not try to push excess amount of new concepts and ways onto
+	     existing projects; there obviously will be some new concepts, as we
+	     are trying to introduce a new shared feature, but it should be actively
+	     kept minimal.
+	<li> Thus we have to live with the idea of code/effort duplication. E.g.
+	     we implement a common library of footprints - it may be a good idea
+	     to also implement a way to index them and store the result in some
+	     complex data format. But what if the other program already has a
+	     complex data format for this? What if our hash is an incompatible
+	     idea with their lists? It's better to step back and rethink:
+	     do we really <b>have to</b> do the indexing in order to achieve
+	     our goals? If the answer is not "absolutely yes!", we just need
+	     skip it. Less is more.
+	<li> This obviously includes dependencies. If our shared solution depends
+	     on qt, programs using gtk will hate it. If it depends on glib,
+	     programs using minilibs will hate it. If all documentation and comments
+	     are written in Italian, everyone but Italian projects will hate it.
+	     Just reduce such external dependencies, even if this means less
+	     features. Go for a common minimum instead of "would remove some
+	     code duplications and costs only an extra dependency".
+	<li> Free/open source means open <b>from ground up</b>, no exceptions.
+	     An open source hardware is not really free if the schematics
+	     comes in a format that's readable only by a proprietary CAD package.
+	     A library or a file format is not free if it is specified by a standard
+	     that can't be included in the same repository for whatever legal
+	     reasons. Yes, this excludes a lot of ISO and STEP and IPC stuff,
+	     and results in effort duplication while we design our own formats.
+	     But there's no point in making a compromise on this and building on
+	     non-free things then see some projects refusing to depend on it
+	     because of the legal implications.
+</ul>
+
+<H3> What we could do within these limits? </H3>
+<p>
+These problems are not new. There are good examples on how people
+have solved these in the past - some examples implemented decades
+ago and are still widely used in one form or another! The most trivial
+of these are network protocols: SMTP, ftp, HTTP, TCP/IP, the IRC protocol,
+etc. What's common in them:
+<ul>
+	<li> They specify a protocol and not the actual implementation.
+	<li> They are freely accessible as RFCs - no registration, no shopping
+	     carts, no much restrictions; if I wanted to copy the RFC next to my
+	     implementation as a documentation and distribute the pack, I am free
+	     to do so.
+	<li> They try to concentrate on one thing, specify all relevant details
+	     and leave everything up to the user.
+</ul>
+<p>
+This is a pretty important difference compared to the original edacore
+idea (of the 2015 FOSDEM talk). We should try to write a lib and sell
+that as the common. Instead, we should:
+<ul>
+	<li> Define free, open file formats and mechanisms;
+	<li> Design for the common minimum, not for the fancy extras and completeness.
+	     This format is for interchange, and we want to reach every project, not
+	     just the big, complex ones. If the format requires you to implement
+	     splines, we lock out a bunch of small players with no curve support.
+	     Don't expect interchange formats to be lossless. Don't expect interchange
+	     formats would <i>replace</i> per project native formats.
+	<li> Preferably design even the file formats and mechanisms in a modular
+	     way, expecting some projects would want to implement only parts of it;
+	     make it work as good as possible in such partial implementations!
+	<li> As an <b>optional</b> extra we may provide a reference implementation
+	     (code) lib, or even libs. Some projects would use these, embed these, others
+	     would read the source and yet others would totally ignore them. It's
+	     all fine as long as the lib is not the common but is just an appendix.
+	<li> Provide <b>optional</b>, but out-of-the-box tools. Small, simple, but
+	     useful ones. If we specify a footprint format, provide tools
+	     that parses it, makes checks on it ("lint"), tools that visualize
+	     the footprint (e.g. generate a png). This can be anything from a
+	     web service to command line tools. Best if there are even multiple
+	     interfaces and APIs. This helps projects to adapt the file formats
+	     as they can try it in advance and they see they have debug tools
+	     readily available, still these tools won't interfere with their projects.
+</ul>
+
+In other words: <b>solve the interchange problem, not the code
+duplication problem</b>!
+
+<H3> What we don't need to do? </H3>
+<p>
+We could also do any of these, but to get the project started and be
+useful, we are not required to do them. It's an important consideration:
+we don't have much resources, we should spend it where it's spent the best.
+I believe we don't need to do the below in order to get an "edacore" idea work:
+<ul>
+	<li> Common code lib implementations; it's a nice extra, but it's the file 
+	     format specs that would make it work
+	<li> Some centralized repository, web service, etc. for sharing user content:
+	     once a few tools already have support for "edacore", this will
+	     automatically happen. Someone, or hopefully even multiple people will
+	     make their public services. Or people will just use github, torrent
+	     or whatever techniques. Of course we can also run
+	     <a href="20170213_edacore2.html"> our own repository service </a> but
+	     that should not be tied together with the "edacore" idea, it should just
+	     be one instance that happens to be maintained by the same people who
+	     made up the specs.
+	<li> "Fancy features". Provide the bare minimum. It's a tradeoff between
+	     the "works everywhere" vs. "looks perfect in all little details". If
+	     the user wants the former, an interchange format is for that; for the
+	     latter, use a native format.
+</ul>
+
+<H3> What we could expect from such a project? </H3>
+<p>
+Assume we designed a set of interchange formats and maybe mechanisms and
+we optionally provided some libs and tools.
+<ul>
+	<li> If we can get at least 2 projects using the new format for exchanging
+	     data, we are at the same point as with the original n*n converter
+	     <a href="20170212_ecosys.html"> EDA ecosystem </a> idea. We just
+	     wasted some more time on a yet-another-format.
+	<li> But if 3 or more projects are using it, we may saved some effort already!
+	<li> If that happens, users can build and share libraries more easily.
+	<li> Users will find new ways to combine our tools in the ecosystem - even
+	     unusual ways developers didn't think of, e.g. using schematics cap from
+	     one project and PCB editor from another, even if both projects were
+	     "integrated".
+</ul>
+
+<H3> What we should NOT expect from such a project? </H3>
+<p>
+<ul>
+	<li> A common interchange format replacing local native formats
+	<li> A common interchange format capturing all tiny details that a native
+	     format can
+	<li> Proprietary EDA tools cooperating on this on the export-side - they
+	     don't want their users to be able to get the design out of their
+	     program, especially not if it's clearly for importing in another
+	<li> Everyone's support - even with the most careful design and the lowest
+	     barriers there will be project that won't like it and won't join. Some
+	     projects will hate it exactly because it's not restrictive enough, e.g.
+	     that it doesn't mandate OOP or SQL or other specific complexities.
+</ul>
diff --git a/doc/devlog/20170213_edacore2.html b/doc/devlog/20170213_edacore2.html
new file mode 100644
index 0000000..27551b8
--- /dev/null
+++ b/doc/devlog/20170213_edacore2.html
@@ -0,0 +1,57 @@
+<html>
+<body>
+<h1> pcb-rnd <a href="http://repo.hu/projects/pcb-rnd/devlog">devlog</a> </h1>
+
+<H2> "Edacore" - extras </H2>
+I believe an edacore-like idea requires only what's described in
+<a href="20170213_edacore1.html"> this document </a>. Once we have that,
+or if we have enough resources, in parallel to that, we could also
+develop some extras. This document describes some of those extras.
+
+<H3> Services: library repositories  </H3>
+<ul>
+	<li> a repository is a collection of data files in the interchange
+	     and/or other random formats
+	<li> there are existing examples out there, including gedasymbols.org
+	     and random cvs, svn, git repositories of users
+	<li> we shouldn't expect to have a single central service for this;
+	     we may run our own service any time, but it's even better if we design
+	     our formats and tools to let people easily set up their own services
+	<li> such separately ran and maintained repositories would have different
+	     goals and policies; we shall accept that and be happy about that; we
+	     should distribute file formats and tools, not policies and ideologies.
+</ul>
+
+<H3> How my favorite service would look like </H3>
+<ul>
+	<li> project-neutral - not a gEDA or KiCad or eagle or qucs or ltspice
+	     library, but a generic user library. If done with converters and/or
+	     interchange formats, neither the originator nor the consumer project
+	     would matter.
+	<li> optimized for multiple UIs:
+		<ul>
+			<li> CLI access (e.g. through a VCS client)
+			<li> web access, maybe even web2.0
+			<li> remote repo integration (e.g. pcb-rnd has strong support for this)
+		</ul>
+	<li> backed up by a version control system in the background
+	<li> instead of complex meta-data systems, offer free form tagging, like
+	     openstreetmap does:
+		<ul>
+			<li> tags are free form key=value pairs, both key and value are simple strings
+			<li> let tagging conventions emerge
+			<li> let the these conventions be specified and maintained by the user community
+			<li> do not split the repository on a per uploader basis - that's the least useful information for an end user
+			<li> maybe implement a separate namespace for "signed" tags; e.g. some registered user would validate a few footprints and would tag them "went on copper and looked good"; if it's a signed tag, end users have the chance to validate the source of the tag and other contributors can not change or overwrite this tag
+		</ul>
+	<li> content licensing:
+		<ul>
+			<li> the ToS would say users must not upload footprints not drawn by themselves
+			<li> chose 2..3 reasonable licenses and require the user to specify which one the footprint uses upon upload
+			<li> <b>optionally</b> have a separate distribution and use license
+		</ul>
+	<li> first support footprints and symbols because we have converters for
+	     those; gradually extend to 3d models, FEM, spice, schematics, PCBs
+	     as common formats and/or converters emerge.
+</ul>
+
diff --git a/doc/features/debian.html b/doc/features/debian.html
index 20d9e74..93370ea 100644
--- a/doc/features/debian.html
+++ b/doc/features/debian.html
@@ -37,22 +37,28 @@ and the batch HID. The GUI HIDs are in <b>pcb-rnd-gtk</b> and
 When there are multiple HIDs installed, the user can select one by the
 --gui command line parameter or by changing the GUI preference in the
 configuration (the default preference is gtk > lesstif > batch).
+</font>
 <p>
+<font size="-4">
 The rest of the packages are features, importers and exporters, e.g.
 <b>pcb-rnd-svg</b> is the SVG exporter, <b>pcb-rnd-query</b> is the object
 query language needed for the advanced search.
+</font>
 <p>
+<font size="-4">
 A metapackage called <b>pcb-rnd</b> is provided for convenience: it installs
 the packages for the most common, yet small setup, with the GTK HID.
+</font>
 <p>
+<font size="-4">
 How to get the packages:
+</font>
 <ul>
-	<li> decide which packages you need; this <a href="debian_list.html"> package list </a> may help
-	<li> use <i>apt-get install</i> after configuring <a href="http://repo.hu/debian"> repo.hu's debian repository </a> as source in your /etc/apt/sources.list
-	<li> use <i>dpkg -i</i> after manually downloading the packages from repo.hu's <a href="http://repo.hu/debian/list.html"> flat package list </a> or from <a href="http://repo.hu/debian/pool/main/p/pcb-rnd"> the package pool </a>
-	<li> build them on your Debian box: use svn trunk, install debhelper and all the build dependencies of pcb-rnd and run "fakeroot debian/rules binary" in trunk (shorthand: "make deb")
+	<li><font size="-4"> decide which packages you need; this <a href="debian_list.html"> package list </a> may help</font>
+	<li><font size="-4"> use <i>apt-get install</i> after configuring <a href="http://repo.hu/debian"> repo.hu's debian repository </a> as source in your /etc/apt/sources.list</font>
+	<li><font size="-4"> use <i>dpkg -i</i> after manually downloading the packages from repo.hu's <a href="http://repo.hu/debian/list.html"> flat package list </a> or from <a href="http://repo.hu/debian/pool/main/p/pcb-rnd"> the package pool </a></font>
+	<li><font size="-4"> build them on your Debian box: use svn trunk, install debhelper and all the build dependencies of pcb-rnd and run "fakeroot debian/rules binary" in trunk (shorthand: "make deb")</font>
 </ul>
-</font>
 
 <h2> plans </h2>
 No plans - this feature is fully implemented.
diff --git a/doc/help.html b/doc/help.html
index 4c0d470..b79d1ed 100644
--- a/doc/help.html
+++ b/doc/help.html
@@ -51,6 +51,7 @@ a mail.
 <p>
 <table border=1 cellspacing=0 cellpadding=0>
 <tr><th> ID        <th> skill required <th> description
+<tr><td> validation<td> geda user      <td> reference output valudation (gerber and other formats)
 <tr><td> tutorial  <td> geda user      <td> tutorial projects
 <tr><td> windows   <td> geda user      <td> generic testing on windows
 <tr><td> mtest     <td> geda user      <td> systematic manual testing
diff --git a/doc/index.html b/doc/index.html
index 510cf05..dc62b0d 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -30,11 +30,10 @@
 	<tr><th align=right valign=top bgcolor="#ccccff"> 
 		<table border=0 width="100%" cellpadding=0 cellspacing=0><tr><td align=left><img src="resources/logo128.png" alt="[pcb-rnd logo]"><th align=right>pcb-rnd</table>
 		<td bgcolor="#ddddff">
-		    <b>is a flexible, modular Printed Circuit Board editor</b>
+		    <b>is a <a href="license.html"> free/open source</a>, flexible, modular Printed Circuit Board editor</b>
+		<p>is <a href="datasheet.html"> feature-rich and compatible
 		<p><a href="motivation.html">historically</a> is a fork of <a href="http://pcb.geda-project.org">PCB</a>
 		<p>is an informal part of the geda project
-		<p>features a lot of small and large <a href="features/index.html">improvements and bugfixes</a>
-		
 
 	<tr><th align=right valign=top bgcolor="#ccccff"> Version Control              <td bgcolor="#ddddff"> <a href="http://igor2.repo.hu/cgi-bin/minisvn.cgi?cmd=browse&repo=pcb-rnd&path=trunk"> svn://repo.hu/pcb-rnd/trunk </a>
 	<tr><th align=right valign=top bgcolor="#ccccff"> Download                     <td bgcolor="#ddddff"> <a href="releases/"> source releases </a>
diff --git a/doc/license.html b/doc/license.html
new file mode 100644
index 0000000..f99ffe0
--- /dev/null
+++ b/doc/license.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+	<title> pcb-rnd - license </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+<!--AUTO head begin-->
+	<link rel="icon" href="http://repo.hu/projects/pcb-rnd/resources/logo16.png">
+<!--AUTO head end-->
+</head>
+<body>
+
+<!--AUTO navbar begin-->
+<table border=0 cellspacing=2 cellpadding=10  bgcolor="#eeeeee" width="100%">
+<tr>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/projects/pcb-rnd/"> Main </a>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/projects/pcb-rnd/news.html"> News </a>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/projects/pcb-rnd/doc.html"> Doc </a>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/cgi-bin/pcb-rnd-people.cgi">People</a>
+<th align=center bgcolor="#ccc0cc"> <a href="http://repo.hu/cgi-bin/pcb-rnd-people.cgi?cmd=events">Events</a> & <a href="http://www.repo.hu/cgi-bin/pcb-rnd-people.cgi?cmd=timeline"> timeline </a>
+<td align=right width="60%"> <font size="+2"><i>pcb-rnd</i></font> <img src="http://repo.hu/projects/pcb-rnd/resources/logo32.png" alt="[pcb-rnd logo]">
+</table>
+<!--AUTO navbar end-->
+
+<H1> pcb-rnd - license </H1>
+Pcb-rnd is a Free Software, Open source, under the terms of GPL version 2.
+<p>
+Pcb-rnd started as a fork of gEDA/PCB thus inherited its GPL2+ license.
+See file <a href="http://igor2.repo.hu/cgi-bin/minisvn.cgi?cmd=cat&repo=pcb-rnd&path=trunk/COPYING">
+trunk/COPYING</a> for more details on the license terms. Pcb-rnd
+incorporates a few mini-libs with various, GPL-compatible licenses, mostly
+BSD, MIT and public domain - the official Debian package has a great index of these.
+<p>
+<b>For users</b>: the resulting software is distributable under the GNU GPL version 2
+(or later versions), the usual GPL terms and conditions apply.
+<p>
+<b>Contribution:</b> by contributing, you agree to submit patches that are conforming
+to the license terms (e.g. don't copy random code from other projects). We
+are keeping track of copyright: each contributor holds the copyright for and
+is responsible for their part. Contributors agree to license their contribution
+under the same term as the subproject they are adding to, which is typically
+GPL2+ for core and plugins and utilities.
+<p>
+<b>Re-licensing under different conditions:</b> pcb-rnd's GPL2+ allows the user
+to upgrade to GPL3 or later versions of the GPL (as long as new versions
+don't contradict with the license of the mini-libs). It is not possible to
+change pcb-rnd's license to anything else unless all past developers agree
+(but there's not even a index of all the names!). It is possible to request
+relicensing of the files that are brand new in pcb-rnd (they are all marked
+in the copyright banner on the top of the file) - this requires the agreement
+of all copyright holders listed in the file, and wouldn't affect other files.
+Same rules apply for mini-libs.
+
+
+</body>
+</html>
diff --git a/doc/man/Makefile b/doc/man/Makefile
index db75680..d639cfc 100644
--- a/doc/man/Makefile
+++ b/doc/man/Makefile
@@ -1,5 +1,6 @@
 # This Makefile is a plain old hand written one; all configuration settings
-# are included from ../../Makefile.conf which is scconfig generated
+# are included from $(ROOT)/Makefile.conf which is scconfig generated
+ROOT=../..
 
 IN=pcb-rnd.1.mml pcb-strip.1.mml pcb-prj2lht.1.mml fp2anim.1.mml
 OUT_HTML = pcb-rnd.1.html pcb-strip.1.html pcb-prj2lht.1.html fp2anim.1.html
@@ -25,9 +26,10 @@ lint: $(OUT_LINT)
 	$(MML) -i copyright.mml -f linkmap $(IN) > $@
 
 index.html: $(IN)
-	@echo "<HTML><BODY>" > $@
+	@echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">' > $@
+	@echo '<HTML><HEAD><meta http-equiv="Content-Type" content="text/html;charset=us-ascii"><TITLE>man page index - pcb-rnd</TITLE></HEAD><BODY><UL>' >> $@
 	$(MML) -i copyright.mml -f indexhtml $(IN) >> $@
-	@echo "</BODY></HTML>" >> $@
+	@echo "</UL></BODY></HTML>" >> $@
 
 clean:
 
@@ -39,26 +41,22 @@ genclean:
 .mml.lint:
 	$(MML) -i copyright.mml -f lint $<
 
-install_:
-	$(MKDIR) "$(MAN1DIR)"
-	$(CPC) "`pwd`/pcb-rnd.1" "$(MAN1DIR)/pcb-rnd.1"
-	$(CPC) "`pwd`/pcb-strip.1" "$(MAN1DIR)/pcb-strip.1"
-	$(CPC) "`pwd`/pcb-prj2lht.1" "$(MAN1DIR)/pcb-prj2lht.1"
-	$(CPC) "`pwd`/gsch2pcb-rnd.1" "$(MAN1DIR)/gsch2pcb-rnd.1"
-	$(CPC) "`pwd`/fp2anim.1" "$(MAN1DIR)/fp2anim.1"
-
-uninstall:
-	$(RM) "$(MAN1DIR)/pcb-rnd.1"
-	$(RM) "$(MAN1DIR)/pcb-strip.1"
-	$(RM) "$(MAN1DIR)/pcb-prj2lht.1"
-	$(RM) "$(MAN1DIR)/gsch2pcb-rnd.1"
-	$(RM) "$(MAN1DIR)/fp2anim.1"
+install_all:
+	$(SCCBOX) mkdir -p "$(MAN1DIR)"
+	$(SCCBOX) $(HOW) "pcb-rnd.1" "$(MAN1DIR)/pcb-rnd.1"
+	$(SCCBOX) $(HOW) "pcb-strip.1" "$(MAN1DIR)/pcb-strip.1"
+	$(SCCBOX) $(HOW) "pcb-prj2lht.1" "$(MAN1DIR)/pcb-prj2lht.1"
+	$(SCCBOX) $(HOW) "gsch2pcb-rnd.1" "$(MAN1DIR)/gsch2pcb-rnd.1"
+	$(SCCBOX) $(HOW) "fp2anim.1" "$(MAN1DIR)/fp2anim.1"
 
 install:
-	$(MAKE) install_ CPC="$(CP)"
+	$(MAKE) install_all HOW="install -f"
 
 linstall:
-	$(MAKE) install_ CPC="$(LN)"
+	$(MAKE) install_all HOW="linstall -f"
+
+uninstall:
+	$(MAKE) install_all HOW="uninstall"
 
-include ../../Makefile.conf
+include $(ROOT)/Makefile.conf
 
diff --git a/doc/man/fp2anim.1.html b/doc/man/fp2anim.1.html
index 8759167..4ea23bd 100644
--- a/doc/man/fp2anim.1.html
+++ b/doc/man/fp2anim.1.html
@@ -1,4 +1,8 @@
-<HTML><BODY>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML><HEAD>
+<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+<title>fp2anim - pcb-rnd manual</title>
+</HEAD><BODY>
 <!--
 pcb-rnd - manual
 Copyright (C) 2016 Tibor 'Igor2' Palinkas
@@ -19,11 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 Contact: pcb-rnd[removethis]@igor2.repo.hu
 -->
-<table width=100%>
+<table width="100%">
 <TR>
-		<TH align=left>   fp2anim 1
-		<TH align=middle> 2016-12-27
-		<TH align=right>  pcb-rnd manual
+		<TH align="left">   fp2anim 1
+		<TH align="center"> 2016-12-27
+		<TH align="right">  pcb-rnd manual
 </table>
 
 
@@ -87,11 +91,11 @@ If <I>inputfile</I> is not specified, <B>fp2anim</B> reads its STDIN for the foo
 </table>
 </blockquote>
 <P>
-<table width=100%>
+<table width="100%">
 <TR>
-		<TH align=left>   fp2anim 1
-		<TH align=middle> 2016-12-27
-		<TH align=right>  pcb-rnd manual
+		<TH align="left">   fp2anim 1
+		<TH align="center"> 2016-12-27
+		<TH align="right">  pcb-rnd manual
 </table>
 
 
diff --git a/doc/man/index.html b/doc/man/index.html
index a7bf77b..2150c5f 100644
--- a/doc/man/index.html
+++ b/doc/man/index.html
@@ -1,6 +1,7 @@
-<HTML><BODY>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML><HEAD><meta http-equiv="Content-Type" content="text/html;charset=us-ascii"><TITLE>man page index - pcb-rnd</TITLE></HEAD><BODY><UL>
 		<LI> <a href="pcb-rnd.1.html">pcb-rnd</a> <I>(1)</I> -- pcb-rnd - Printed Circuit Board editor
 		<LI> <a href="pcb-strip.1.html">pcb-strip</a> <I>(1)</I> -- pcb-strip - remove sections of a pcb file
 		<LI> <a href="pcb-prj2lht.1.html">pcb-prj2lht</a> <I>(1)</I> -- pcb-prj2lht - convert old gsch2pcb project file to pcb-rnd project
 		<LI> <a href="fp2anim.1.html">fp2anim</a> <I>(1)</I> -- fp2anim - convert a gEDA/PCB footprint to animator script
-</BODY></HTML>
+</UL></BODY></HTML>
diff --git a/doc/man/pcb-prj2lht.1.html b/doc/man/pcb-prj2lht.1.html
index 7a157fe..d8e1ee7 100644
--- a/doc/man/pcb-prj2lht.1.html
+++ b/doc/man/pcb-prj2lht.1.html
@@ -1,4 +1,8 @@
-<HTML><BODY>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML><HEAD>
+<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+<title>pcb-prj2lht - pcb-rnd manual</title>
+</HEAD><BODY>
 <!--
 pcb-rnd - manual
 Copyright (C) 2016 Tibor 'Igor2' Palinkas
@@ -19,11 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 Contact: pcb-rnd[removethis]@igor2.repo.hu
 -->
-<table width=100%>
+<table width="100%">
 <TR>
-		<TH align=left>   pcb-prj2lht 1
-		<TH align=middle> 2016-12-27
-		<TH align=right>  pcb-rnd manual
+		<TH align="left">   pcb-prj2lht 1
+		<TH align="center"> 2016-12-27
+		<TH align="right">  pcb-rnd manual
 </table>
 
 
@@ -47,11 +51,11 @@ pcb-prj2lht - convert old gsch2pcb project file to pcb-rnd project
 <B>pcb-prj2lht</B> converts the old gsch2pcb project file to the new, lihata project file format that is usable with pcb-rnd and gsch2pcb-rnd. If <I>inputfile</I> is specified, the file is modified in-place, else <B>pcb-prj2lht</B> reads from STDIN and writes the result to STDOUT.
 </blockquote>
 <P>
-<table width=100%>
+<table width="100%">
 <TR>
-		<TH align=left>   pcb-prj2lht 1
-		<TH align=middle> 2016-12-27
-		<TH align=right>  pcb-rnd manual
+		<TH align="left">   pcb-prj2lht 1
+		<TH align="center"> 2016-12-27
+		<TH align="right">  pcb-rnd manual
 </table>
 
 
diff --git a/doc/man/pcb-rnd.1.html b/doc/man/pcb-rnd.1.html
index fee997f..fe0bc68 100644
--- a/doc/man/pcb-rnd.1.html
+++ b/doc/man/pcb-rnd.1.html
@@ -1,4 +1,8 @@
-<HTML><BODY>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML><HEAD>
+<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+<title>pcb-rnd - pcb-rnd manual</title>
+</HEAD><BODY>
 <!--
 pcb-rnd - manual
 Copyright (C) 2016 Tibor 'Igor2' Palinkas
@@ -19,11 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 Contact: pcb-rnd[removethis]@igor2.repo.hu
 -->
-<table width=100%>
+<table width="100%">
 <TR>
-		<TH align=left>   pcb-rnd 1
-		<TH align=middle> 2016-10-29
-		<TH align=right>  pcb-rnd manual
+		<TH align="left">   pcb-rnd 1
+		<TH align="center"> 2016-10-29
+		<TH align="right">  pcb-rnd manual
 </table>
 
 
@@ -68,11 +72,11 @@ pcb-rnd - Printed Circuit Board editor
 </table>
 </blockquote>
 <P>
-<table width=100%>
+<table width="100%">
 <TR>
-		<TH align=left>   pcb-rnd 1
-		<TH align=middle> 2016-10-29
-		<TH align=right>  pcb-rnd manual
+		<TH align="left">   pcb-rnd 1
+		<TH align="center"> 2016-10-29
+		<TH align="right">  pcb-rnd manual
 </table>
 
 
diff --git a/doc/man/pcb-strip.1.html b/doc/man/pcb-strip.1.html
index 221ad90..859264a 100644
--- a/doc/man/pcb-strip.1.html
+++ b/doc/man/pcb-strip.1.html
@@ -1,4 +1,8 @@
-<HTML><BODY>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML><HEAD>
+<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+<title>pcb-strip - pcb-rnd manual</title>
+</HEAD><BODY>
 <!--
 pcb-rnd - manual
 Copyright (C) 2016 Tibor 'Igor2' Palinkas
@@ -19,11 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 Contact: pcb-rnd[removethis]@igor2.repo.hu
 -->
-<table width=100%>
+<table width="100%">
 <TR>
-		<TH align=left>   pcb-strip 1
-		<TH align=middle> 2016-12-27
-		<TH align=right>  pcb-rnd manual
+		<TH align="left">   pcb-strip 1
+		<TH align="center"> 2016-12-27
+		<TH align="right">  pcb-rnd manual
 </table>
 
 
@@ -64,11 +68,11 @@ pcb-strip - remove sections of a pcb file
 </table>
 </blockquote>
 <P>
-<table width=100%>
+<table width="100%">
 <TR>
-		<TH align=left>   pcb-strip 1
-		<TH align=middle> 2016-12-27
-		<TH align=right>  pcb-rnd manual
+		<TH align="left">   pcb-strip 1
+		<TH align="center"> 2016-12-27
+		<TH align="right">  pcb-rnd manual
 </table>
 
 
diff --git a/doc/resources/logo32.xpm b/doc/resources/logo32.xpm
new file mode 100644
index 0000000..fddccb8
--- /dev/null
+++ b/doc/resources/logo32.xpm
@@ -0,0 +1,295 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"32 32 256 2",
+/* colors */
+"   c #000000",
+" . c #838D91",
+" X c #365938",
+" o c #5F6767",
+" O c #E2E0E1",
+" + c #799A7D",
+" @ c #9FA9B3",
+" # c #2F5331",
+" $ c #B1C3B4",
+" % c #2B552D",
+" & c #2D512F",
+" * c #6B6F76",
+" = c #DBDADA",
+" - c #2A532C",
+" ; c #2B512D",
+" : c #99A3AD",
+" > c #AEBFB1",
+" , c #2A4F2C",
+" < c #729276",
+" 1 c #294F2B",
+" 2 c #859396",
+" 3 c #284F2A",
+" 4 c #709274",
+" 5 c #6C9870",
+" 6 c #274F29",
+" 7 c #264F28",
+" 8 c #254F27",
+" 9 c #264D28",
+" 0 c #254D27",
+" q c #244D26",
+" w c #234D25",
+" e c #939DA7",
+" r c #244B26",
+" t c #6A8C6E",
+" y c #8F99A3",
+" u c #8F97A3",
+" i c #6E737C",
+" p c #8D97A1",
+" a c #1B451D",
+" s c #8B959F",
+" d c #608C64",
+" f c #9FAFA2",
+" g c #89939D",
+" h c #9DAFA0",
+" j c #5D8861",
+" k c #87919B",
+" l c #708E77",
+" z c #96AB99",
+" x c #727B83",
+" c c #113D13",
+" v c #58785C",
+" b c #547458",
+" n c #537457",
+" m c #57645B",
+" M c #4B6C4F",
+" N c #101112",
+" B c #747C7E",
+" V c #7D9D80",
+" C c #73787D",
+" Z c #7B9288",
+" A c #B1C2B3",
+" S c #879497",
+" D c #55625C",
+" F c #636A6D",
+" G c #274828",
+" H c #244C25",
+" J c #9FB6A1",
+" K c #A0B0A2",
+" L c #9DAE9F",
+" P c #709376",
+" I c #87909A",
+" U c #5B855E",
+" Y c #858E98",
+" T c #558558",
+" R c #7E9987",
+" E c #678B6D",
+" W c #CAD3CB",
+" Q c #4E7B51",
+" ! c #49794C",
+" ~ c #728D7B",
+" ^ c #4C6D4F",
+" / c #496F4C",
+" ( c #B8C1B9",
+" ) c #6E7577",
+" _ c #465749",
+" ` c #B3BBB4",
+" ' c #37693A",
+" ] c #3B5D3E",
+" [ c #646D6D",
+" { c #E7E6E7",
+" } c #E2E4E2",
+" | c #38513B",
+".  c #E1E2E1",
+".. c #9099A2",
+".X c #384D3B",
+".o c #7D858C",
+".O c #6C6F78",
+".+ c #DBDCDB",
+".@ c #729877",
+".# c #2C512F",
+".$ c #879399",
+".% c #719476",
+".& c #709475",
+".* c #D8D8D8",
+".= c #719276",
+".- c #709275",
+".; c #6F9274",
+".: c #6E9073",
+".> c #949FA9",
+"., c #6D9072",
+".< c #6D8E72",
+".1 c #6A8E6F",
+".2 c #6B8C70",
+".3 c #67926C",
+".4 c #303133",
+".5 c #909BA5",
+".6 c #678C6C",
+".7 c #8E99A3",
+".8 c #68886D",
+".9 c #8D97A2",
+".0 c #CDCECD",
+".q c #517A53",
+".w c #8EA18F",
+".e c #9BB39F",
+".r c #686F77",
+".t c #517053",
+".y c #2C2F32",
+".u c #F3EDF2",
+".i c #456047",
+".p c #426444",
+".a c #3C6A3E",
+".s c #58645D",
+".d c #161719",
+".f c #39683B",
+".g c #969EA7",
+".h c #39543B",
+".j c #7B9B7F",
+".k c #2D562F",
+".l c #B1C2B4",
+".z c #2D522F",
+".x c #6B7076",
+".c c #677F68",
+".v c #658166",
+".b c #677B68",
+".n c #89909A",
+".m c #6F9773",
+".M c #2E4830",
+".N c #98A2AC",
+".B c #565E5E",
+".V c #265028",
+".C c #274E29",
+".Z c #6F9173",
+".A c #264E28",
+".S c #254E27",
+".D c #6E8F72",
+".F c #244E26",
+".G c #254C27",
+".H c #274829",
+".J c #244C26",
+".K c #234C25",
+".L c #234A25",
+".P c #214A23",
+".I c #909AA4",
+".U c #69896D",
+".Y c #6F747D",
+".T c #8E98A2",
+".R c #577758",
+".E c #68876C",
+".W c #8C96A0",
+".Q c #658769",
+".! c #7B828C",
+".~ c #5E8D62",
+".^ c #9EB0A1",
+"./ c #9DAEA0",
+".( c #7F9789",
+".) c #456746",
+"._ c #C2CFC4",
+".` c #859E88",
+".' c #1D2022",
+".] c #315732",
+".[ c #426746",
+".{ c #7C927F",
+".} c #B1C1B3",
+".| c #8B919B",
+"X  c #2E4D2F",
+"X. c #2A512B",
+"XX c #264F27",
+"Xo c #224B23",
+"XO c #7F878F",
+"X+ c #8D97A0",
+"X@ c #74947A",
+"X# c #88919B",
+"X$ c #6B9071",
+"X% c #62696F",
+"X& c #57845A",
+"X* c #6B8C71",
+"X= c #698E6F",
+"X- c #678C6D",
+"X; c #638A69",
+"X: c #1A1B1B",
+"X> c #697179",
+"X, c #477A4A",
+"X< c #5E7E64",
+"X1 c #467649",
+"X2 c #2F3336",
+"X3 c #F6F1F6",
+"X4 c #416A44",
+"X5 c #6D7876",
+"X6 c #436446",
+"X7 c #8E949D",
+"X8 c #060707",
+"X9 c #415644",
+"X0 c #385C3B",
+"Xq c #3E5241",
+"Xw c #355A38",
+"Xe c #355838",
+"Xr c #E2E3E2",
+"Xt c #7B9B80",
+"Xy c #7A997F",
+"Xu c #8E9AA0",
+"Xi c #E0DFE0",
+"Xp c #DFDFDF",
+"Xa c #315434",
+"Xs c #DDDFDD",
+"Xd c #739B78",
+"Xf c #729577",
+"Xg c #739378",
+"Xh c #D9D9D9",
+"Xj c #D8D9D8",
+"Xk c #709375",
+"Xl c #6F9374",
+"Xz c #6F9174",
+"Xx c #6E9173",
+"Xc c #6B9570",
+"Xv c #6D8F72",
+"Xb c #919CA6",
+"Xn c #698D6E",
+"Xm c #909AA5",
+"XM c #8F9AA4",
+"XN c #69896E",
+"XB c #8E98A3",
+"XV c #8D96A2",
+"XC c #8C96A1",
+"XZ c #7C848E",
+"XA c #8B96A0",
+"XS c #65856A",
+"XD c #CACDCA",
+"XF c #5F7F64",
+"XG c #879E88",
+"XH c #899A8A",
+"XJ c #889889",
+"XK c #2B2E31",
+"XL c #446546",
+"XP c #EDE8EC",
+"XI c #546359",
+"XU c None",
+/* pixels */
+"XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXxXxXxXkXf.<.<Xk.&.;XxXxXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXx.< n ] & 1 3.# X ^.UXxXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXx.2.z.A 6 6 6 6 6 6 7 9 tXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXx v.S 6 6 6 6 6 6 6 6 6 Q.:XxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXS H 7.H.XXI mXqX .F.L.~XxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXx.;X<X5X7 :XM.9.>.n BX;XlXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXv.8XvXx ~XC s s p s.W p pXA u.(.,.;XSXNXxXxXxXxXxXx",
+"XxXxXxXxXx.2 #.KXw lXC p.W.W.W p.W.W p p pXV RX6 q 9.QXxXxXxXxXx",
+"XxXxXxXx.; M 7 6Xo ..W.W p.W p y y p.W.W p.W IX. 6 6X4XzXxXxXxXx",
+"XxXxXxXx PXa 6 6.M.g p.W.W.T xX2XKX> y p.W.WX#X9 7 6 7. at XxXxXxXx",
+"XxXxXxXxX*.C 6 7.s y p.W p.r        X%.W.W.WXM o.F 6 r.3XxXxXxXx",
+"XxXxXxXx.E H 6XX ).W.W.W.5.d         N e p p.T * - 6.G jXxXxXxXx",
+"XxXxXxXxXF 0 6 8 C s p p pX8           @ p.W p.O.k 6 9X&.:XxXxXx",
+"XxXxXxXxXN.K 6 7 [ p.W.W.I.y        .4.I.W p p.x.V 6.G dXxXxXxXx",
+"XxXxXxXxXv , 6 6 _Xm s.W p k.'    X:...W.W p y D.S 6.L 5XxXxXxXx",
+"XxXxXxXx.%Xe 6 6 G.| s.W.W.WXbXO.o.N.W p.W p Y.h 6 6 %XdXxXxXxXx",
+"XxXxXxXxXx b.S 6.P Z p p.W.W p.W p.W.W p p.W S q 6.C !.:XxXxXxXx",
+"XxXxXxXxXx.Z /.f T.,.$.W p.W.W p.W.W.W p.TX+.e.{.aX1.mXxXxXxXxXx",
+"XxXxXxXxXxXxXz.-XxXx.: 2 sXB.W p.W.W.7 gXuX at .l h.-XzXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXzXL |.B i.!XZ.Y FX9X0.D $./XxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXt.6.`.R.] w.p.i.b ;.V q.) V._ hXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXn.+ W.0 `.c.t.*XsXDXH.K.vXp (Xi.^XxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXx.j =X$.[.F.J.wXJ aX3 cXr.qXc.} hXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXx.jXj.1.;Xl U JXG '.uX, }XyX- A LXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXx +XhX=XxXxXx > f EXP.6 z O.  { KXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXx.,.-XxXxXxXx.,.-XxXzXx.,.=Xg < 4XxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx",
+"XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx"
+};
diff --git a/doc/resources/logo64.xpm b/doc/resources/logo64.xpm
new file mode 100644
index 0000000..3f71bad
--- /dev/null
+++ b/doc/resources/logo64.xpm
@@ -0,0 +1,618 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 547 2",
+/* colors */
+"   c #000000",
+" . c #829C86",
+" X c #3F4941",
+" o c #365738",
+" O c #75A879",
+" + c #365538",
+" @ c #B4C7B7",
+" # c #7A987E",
+" $ c #E0DEDF",
+" % c #79987D",
+" & c #305532",
+" * c #E0DCDF",
+" = c #77987B",
+" - c #DEDCDD",
+" ; c #729C76",
+" : c #344736",
+" > c #749478",
+" , c #2B512D",
+" < c #709674",
+" 1 c #28512A",
+" 2 c #294F2B",
+" 3 c #275129",
+" 4 c #274F29",
+" 5 c #6F9273",
+" 6 c #264F28",
+" 7 c #607C61",
+" 8 c #264D28",
+" 9 c #6E9072",
+" 0 c #669C6A",
+" q c #254D27",
+" w c #244D26",
+" e c #D5D2D4",
+" r c #244B26",
+" t c #234B25",
+" y c #224B24",
+" u c #6B8C6F",
+" i c #919BA5",
+" p c #224924",
+" a c #6A8C6E",
+" s c #204922",
+" d c #619665",
+" f c #1F4921",
+" g c #8F99A3",
+" h c #7B9682",
+" j c #8E97A2",
+" k c #1D471F",
+" l c #8D97A1",
+" z c #799480",
+" x c #1C471E",
+" c c #8C95A0",
+" v c #91969B",
+" b c #1B451D",
+" n c #8B959F",
+" m c #8A959E",
+" M c #8A939E",
+" N c #89939D",
+" B c #638267",
+" V c #174119",
+" C c #87919B",
+" Z c #8B9095",
+" A c #607C64",
+" S c #646B72",
+" D c #54595F",
+" F c #5F7C63",
+" G c #5E7A62",
+" H c #989EA5",
+" J c #CDDACF",
+" K c #75767C",
+" L c #697A70",
+" P c #547058",
+" I c #537057",
+" U c #4F7453",
+" Y c #516C55",
+" T c #575C5B",
+" R c #888E95",
+" E c #777C81",
+" W c #4C6A50",
+" Q c #4B6A4F",
+" ! c #4B684F",
+" ~ c #BACCBC",
+" ^ c #374C38",
+" / c #446248",
+" ( c #9CA6AF",
+" ) c #415E45",
+" _ c #2B542C",
+" ` c #69A16C",
+" ' c #285229",
+" ] c #68A16B",
+" [ c #2A482B",
+" { c #264E27",
+" } c #254E26",
+" | c #959EA8",
+".  c #949EA7",
+".. c #254C26",
+".X c #A9B8AB",
+".o c #939CA6",
+".O c #828A92",
+".+ c #629B65",
+".@ c #639966",
+".# c #A7B6A9",
+".$ c #909AA3",
+".% c #808890",
+".& c #7D868D",
+".* c #5D9360",
+".= c #5C935F",
+".- c #879D90",
+".; c #686E75",
+".: c #719377",
+".> c #8D9196",
+"., c #588F5B",
+".< c #9AAE9C",
+".1 c #869099",
+".2 c #858E98",
+".3 c #6D9173",
+".4 c #848E97",
+".5 c #838C96",
+".6 c #828C95",
+".7 c #727A82",
+".8 c #707880",
+".9 c #92A894",
+".0 c #69896F",
+".q c #7D8690",
+".w c #4D8350",
+".e c #474C51",
+".r c #97A9A6",
+".t c #575F5A",
+".y c #FAF8FA",
+".u c #58575B",
+".i c #A7B1B9",
+".p c #F9F6F9",
+".a c #A6AFB8",
+".s c #74797D",
+".d c #1E2022",
+".f c #0E0E0F",
+".g c #525555",
+".h c #A3ABB5",
+".j c #4C5D4F",
+".k c #515354",
+".l c #416544",
+".z c #4E4F51",
+".x c #8A9B99",
+".c c #435F46",
+".v c #B6BDB7",
+".b c #B5BDB6",
+".n c #EDECED",
+".m c #B1BFB2",
+".M c #ECEAEC",
+".N c #3F5D42",
+".B c #56635C",
+".V c #38673B",
+".C c #585B5E",
+".Z c #365F39",
+".A c #E6E6E6",
+".S c #54575A",
+".D c #37593A",
+".F c #38573B",
+".G c #E4E4E4",
+".H c #E5E2E5",
+".J c #37573A",
+".K c #535359",
+".L c #525358",
+".P c #E2E2E2",
+".I c #E1E0E1",
+".U c #335536",
+".Y c #E0E0E0",
+".T c #E0DEE0",
+".R c #315534",
+".E c #2F5332",
+".W c #77967C",
+".Q c #DDDCDD",
+".! c #DCDCDC",
+".~ c #719C76",
+".^ c #2B552E",
+"./ c #749679",
+".( c #DBDADB",
+".) c #709A75",
+"._ c #DADADA",
+".` c #DBD8DB",
+".' c #719676",
+".] c #59905B",
+".[ c #719476",
+".{ c #709475",
+".} c #709275",
+".| c #5D845F",
+"X  c #859197",
+"X. c #6F9274",
+"XX c #6E9273",
+"Xo c #656B71",
+"XO c #6E9073",
+"X+ c #6B9470",
+"X@ c #848D96",
+"X# c #6D9072",
+"X$ c #6E8E73",
+"X% c #97AB98",
+"X& c #6C9071",
+"X* c #D1D8D1",
+"X= c #939DA8",
+"X- c #6C8E71",
+"X; c #95A996",
+"X: c #D2D2D2",
+"X> c #6B8C70",
+"X, c #94A995",
+"X< c #698E6E",
+"X1 c #909BA5",
+"X2 c #93A794",
+"X3 c #698A6E",
+"X4 c #678C6C",
+"X5 c #94A395",
+"X6 c #7E8790",
+"X7 c #68886D",
+"X8 c #67886C",
+"X9 c #4E8450",
+"X0 c #658A6A",
+"Xq c #7C858E",
+"Xw c #82848A",
+"Xe c #8C95A1",
+"Xr c #8B95A0",
+"Xt c #CBCCCB",
+"Xy c #65846A",
+"Xu c #8A959F",
+"Xi c #4B7E4D",
+"Xp c #FEFBFD",
+"Xa c #777F89",
+"Xs c #899F8A",
+"Xd c #767F88",
+"Xf c #666D75",
+"Xg c #7C7E84",
+"Xh c #555B61",
+"Xj c #607E65",
+"Xk c #585C5A",
+"Xl c #5F7C64",
+"Xz c #636B72",
+"Xx c #F9F7F8",
+"Xc c #555C57",
+"Xv c #A7B0B8",
+"Xb c #67666C",
+"Xn c #437445",
+"Xm c #A5AEB6",
+"XM c #4F555B",
+"XN c #2E3134",
+"XB c #A3ACB4",
+"XV c #3D4146",
+"XC c #4C5C4E",
+"XZ c #476449",
+"XA c #57745C",
+"XS c #3D703F",
+"XD c #436645",
+"XF c #465C48",
+"XG c #416443",
+"XH c #050505",
+"XJ c #3F5E41",
+"XK c #38663A",
+"XL c #3C5E3E",
+"XP c #575A5C",
+"XI c #111314",
+"XU c #375E39",
+"XY c #809F84",
+"XT c #365E38",
+"XR c #336035",
+"XE c #809B84",
+"XW c #3B523D",
+"XQ c #326034",
+"X! c #7F9B83",
+"X~ c #76A97A",
+"X^ c #38543A",
+"X/ c #708571",
+"X( c #525257",
+"X) c #75A579",
+"X_ c #335835",
+"X` c #3D423F",
+"X' c #7A977E",
+"X] c #4F5054",
+"X[ c #315433",
+"X{ c #3C423E",
+"X} c #79977D",
+"X| c #39463B",
+"o  c #6B816C",
+"o. c #38463A",
+"oX c #70A374",
+"oo c #39443B",
+"oO c #6FA373",
+"o+ c #2D562F",
+"o@ c #729D76",
+"o# c #6DA571",
+"o$ c #364638",
+"o% c #374439",
+"o& c #697F6A",
+"o* c #709F74",
+"o= c #2E5230",
+"o- c #778A85",
+"o; c #2D522F",
+"o: c #6DA171",
+"o> c #2B542D",
+"o, c #2B522D",
+"o< c #DBD9DA",
+"o1 c #719775",
+"o2 c #709774",
+"o3 c #2A502C",
+"o4 c #DAD7D9",
+"o5 c #28522A",
+"o6 c #98A2AC",
+"o7 c #29502B",
+"o8 c #28502A",
+"o9 c #294E2B",
+"o0 c #2C482E",
+"oq c #275029",
+"ow c #265028",
+"oe c #2A482C",
+"or c #264E28",
+"ot c #55585D",
+"oy c #254E27",
+"ou c #235025",
+"oi c #254C27",
+"op c #54565C",
+"oa c #244C26",
+"os c #264828",
+"od c #234C25",
+"of c #244A26",
+"og c #929CA6",
+"oh c #234A25",
+"oj c #808C91",
+"ok c #61666C",
+"ol c #214A23",
+"oz c #224824",
+"ox c #204A22",
+"oc c #214823",
+"ov c #629566",
+"ob c #688B6C",
+"on c #658F69",
+"om c #8F98A3",
+"oM c #204622",
+"oN c #3E4043",
+"oB c #8E98A2",
+"oV c #1D481F",
+"oC c #6D747B",
+"oZ c #8D96A1",
+"oA c #618F65",
+"oS c #8C96A0",
+"oD c #8B969F",
+"oF c #8B949F",
+"oG c #909E90",
+"oH c #8A949E",
+"oJ c #788089",
+"oK c #628166",
+"oL c #869D90",
+"oP c #728F79",
+"oI c #7B7D82",
+"oU c #607D64",
+"oY c #96AE99",
+"oT c #133C15",
+"oR c #56875A",
+"oE c #707881",
+"oW c #6B8972",
+"oQ c #58755C",
+"o! c #557959",
+"o~ c #7F8589",
+"o^ c #8BA28E",
+"o/ c #536F57",
+"o( c #415D42",
+"o) c #637D6A",
+"o_ c #88A08B",
+"o` c #4D6B51",
+"o' c #57595B",
+"o] c #212426",
+"o[ c #859A88",
+"o{ c #385B39",
+"o} c #959DA5",
+"o| c #728672",
+"O  c #49674D",
+"O. c #0B0C0D",
+"OX c #46634A",
+"Oo c #3F4140",
+"OO c #B2C5B4",
+"O+ c #B4BDB6",
+"O@ c #EBEEEC",
+"O# c #9BA5AE",
+"O$ c #9AA3AD",
+"O% c #274F28",
+"O& c #679C6A",
+"O* c #959FA8",
+"O= c #7F9C85",
+"O- c #659A68",
+"O; c #929BA5",
+"O: c #525359",
+"O> c #224923",
+"O, c #254126",
+"O< c #629665",
+"O1 c #8D97A0",
+"O2 c #DBE2DC",
+"O3 c #8B959E",
+"O4 c #5B5F65",
+"O5 c #D9E0DA",
+"O6 c #9DB59F",
+"O7 c #5A5D64",
+"O8 c #59905C",
+"O9 c #88919B",
+"O0 c #87919A",
+"Oq c #676D74",
+"Ow c #868F99",
+"Oe c #848D97",
+"Or c #838D96",
+"Ot c #6B9071",
+"Oy c #95AB97",
+"Ou c #828B95",
+"Oi c #717981",
+"Op c #698E6F",
+"Oa c #6B8871",
+"Os c #6F777F",
+"Od c #C9D2CA",
+"Of c #517C54",
+"Og c #7B858E",
+"Oh c #81848A",
+"Oj c #8B9E97",
+"Ok c #C7D0C8",
+"Ol c #FDFBFD",
+"Oz c #FAF9FA",
+"Ox c #69686F",
+"Oc c #F9F7F9",
+"Ov c #212325",
+"Ob c #A7AEB9",
+"On c #F8F5F8",
+"Om c #6E8477",
+"OM c #F5F5F5",
+"ON c #427245",
+"OB c #A3ACB5",
+"OV c #829184",
+"OC c #0B0B0C",
+"OZ c #F2F1F2",
+"OA c #71747A",
+"OS c #436246",
+"OD c #3C6C3F",
+"OF c #8D949C",
+"OG c #415E44",
+"OH c #405E43",
+"OJ c #4B4C4E",
+"OK c #3B663E",
+"OL c #E9E7E9",
+"OP c #E7E7E7",
+"OI c #E6E5E6",
+"OU c #39583C",
+"OY c #E5E5E5",
+"OT c #E4E3E4",
+"OR c #365839",
+"OE c #365639",
+"OW c #808C8F",
+"OQ c #525258",
+"O! c #335636",
+"O~ c #515057",
+"O^ c #E0DFE0",
+"O/ c #325435",
+"O( c #DFDFDF",
+"O) c #485A4E",
+"O_ c #2E5231",
+"O` c #DCDBDC",
+"O' c #75957A",
+"O] c #729977",
+"O[ c #749579",
+"O{ c #D8DDD8",
+"O} c #DAD9DA",
+"O| c #709775",
+"+  c #719576",
+"+. c #DAD7DA",
+"+X c #29502C",
+"+o c #588F5A",
+"+O c #6F9574",
+"++ c #709375",
+"+@ c #849D8C",
+"+# c #6F9374",
+"+$ c #6F9174",
+"+% c #D2DDD2",
+"+& c #849096",
+"+* c #6E9173",
+"+= c #6D9172",
+"+- c #D5D5D5",
+"+; c #6E8F73",
+"+: c #D6D3D6",
+"+> c #646A70",
+"+, c #D5D3D5",
+"+< c #838C95",
+"+1 c #6C8F71",
+"+2 c #D5D1D5",
+"+3 c #6B8F70",
+"+4 c #818A93",
+"+5 c #698D6E",
+"+6 c #D1D1D1",
+"+7 c #6A8B6F",
+"+8 c #5B755D",
+"+9 c #8F9AA4",
+"+0 c #CED1CE",
+"+q c #8F98A4",
+"+w c #68896D",
+"+e c #1E4821",
+"+r c #668B6B",
+"+t c #8E98A3",
+"+y c #84858C",
+"+u c #1D4820",
+"+i c #67876C",
+"+p c #65896A",
+"+a c #8D96A2",
+"+s c #82858A",
+"+d c #8C96A1",
+"+f c #66856B",
+"+g c #929E93",
+"+h c #7B848D",
+"+j c #65856A",
+"+k c #818389",
+"+l c #4C814E",
+"+z c #4D7F4F",
+"+x c #909E91",
+"+c c #4C7F4E",
+"+v c #8A949F",
+"+b c #CACBCA",
+"+n c #19441C",
+"+m c #89949E",
+"+M c #697078",
+"+N c #88929D",
+"+B c #628167",
+"+V c #778089",
+"+C c #8A9E8B",
+"+Z c #9CA3AA",
+"+A c #617F66",
+"+S c #607D65",
+"+D c #728B7A",
+"+F c #89988A",
+"+G c #5E7D63",
+"+H c #A9B1BA",
+"+J c #F9F6F8",
+"+K c #5C7B61",
+"+L c #829883",
+"+P c #466948",
+"+I c #8FAA93",
+"+U c #4D5D4F",
+"+Y c #4C5D4E",
+"+T c #58755D",
+"+R c #4A5D4C",
+"+E c #1B1C1E",
+"+W c #EDECEC",
+"+Q c #445746",
+"+! c #788E79",
+"+~ c #141617",
+"+^ c #3D5F3F",
+"+/ c #38673A",
+"+( c #595D5E",
+"+) c #84A288",
+"+_ c #83A287",
+"+` c #3A5D3C",
+"+' c None",
+/* pixels */
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+#.{+ +iX7X7X7X-.{++X.+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*.{Xy GO OE.FX[O_O_o= o.J.N I+AX-X.+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* 9Xl /.R wor 4 4 4 4 4 4 4 4 6oy+X.J PX8+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* !o7or 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 }ORX.+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*X.XA 6 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4or U+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*++ /or 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4XRO]+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*.{OU 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4oMX~+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*X. Wor 4 4 4 4oqoyocoeo0o0o0or t 6 4 4 4 4 4.Vo at +*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+Ao3 4 4oyosX|OoOxXgXw+sOhXb.k XX^ y 4 4oh.,+O+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*X.oK.ZO,X{ K v.iO$.$ n+moH | (OFOA.z ^ '.] <+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+7o-ObXmO*+d l noBoSoS loSoSoBXrO#.h.r./+=+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*X..0X XroB noS n l loSoSoS loS l l l loHoBom hX#+*+*+*+*+*X.X.+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*.{Xj+KoU+BX.+*+*Oa coDoB l loS noSoS noSoSoS loS l l l loSoBXeoLX&+*+*X- Fo/oQ+i+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+* Y ,oy wo; B+* a.1oSoS l noSoS n loS loB noS n loSoSoSoB l n n+qO=X# u.N 4oy w.DX>+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*XX+T 6 4 4 4 4 2obojoHoB l noS noS loSoSoS l loS loS loB n l l loS lom = )oy 4 4 4O%.lX.+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*X-.J 4 4 4 4 4oro) joSoSoS l loSoS n l l n noS l l g loS loS l l loHoSOWo, 4 4 4 4 4O>.)+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+* A+X 4 4 4 4 4of+k+voSoB n l l loS l loB+doB noBoH l n loSoSoSoSoS l lXao( 4 4 4 4 4 4OfXO+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+#O or 4 4 4 4oq : ZoHoBoH noSoS loS noBoH+h DXhoEOe l loS l loS loB n lXd.tod 4 4 4 4 4XQ.[+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*.J 4 4 4 4 4odOJ.aoSoSoB loS noSoS g.7XN        o]Xf+toS loSoH l noS lO0O:+^ 4 4 4 4 4 po*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*X7o= 4 4 4 4 4 [ K.ooS loS n n loSoBOiO.              Xz n l l l noS n n g+>+Roy 4 4 4 4oi dXO+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+Ao3 4 4 4 4oq :.>+N l n l loS l l+4XI                  oBoHoS loS l noBoBXdXc w 4 4 4 4 8oRXO+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*Xloy 4 4 4 4oqo% H loSoHoSoSoS lX1XM                    .eoSoH l l noB n lOg T 1 4 4 4 4 4.w+;+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*X.+Toy 4 4 4 4owX`OB loS l l l NoSO9Ov                    .fo6 l loSoS l l l.5O~XU 4 4 4 4 4ON+#+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*X. Qor 4 4 4 4owX`OB noS l loH loS.2+~                      +HoS l l n n l nX at OQXT 4 4 4 4 4XK ;+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*X.o`or 4 4 4 4owX`XBoBoSoSoS loS l.4+E                      Xv loSoS n loS lOrOQXT 4 4 4 4 4OD.~+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+Soy 4 4 4 4oqooo} l noSoS loS l+9XV                    oN. oSoSoSoS loS lOuXPo+ 4 4 4 4 4X9X$+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*Xl w 4 4 4 4oqo$ R+doS noS loSoSoSX6XH                  +ZoSoS n l loSoS n+VXk w 4 4 4 4 4+l+;+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+f.E 4 4 4 4 4o0oI+m l n noS l l lO3 S                .sO;oSoB noS l l noBoCXC q 4 4 4 4oa. at XO+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*X3.U 4 4 4 4 4ol.uX=oBoSoSoSoS l loS lOs.d        OCo~ ioBoS n noSoS noS lO7XJ 4 4 4 4 4 r 0XO+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*.{.N 6 4 4 4 4oqo..O n noSoH goSoSoSoSoSog.%.S.C E+HO1oSoSoBoSoS loBoS l.q+( 3 4 4 4 4 4 4 O+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*X. I } 4 4 4 4 4os+yoHoS noSoS noBoBoSoSoSoSoHoHXuoS l n loS l n n loS noJXFor 4 4 4 4 4XnO|+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+j.R 4 4 4 4 4oq L n noBoS l loSoSoS loSoSoS l loSoS loH l noSoB noBoS.& _ 4 4 4 4 4oi.++;+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*.{OX { 4 4 4 4ozO- C loH l loSoS loSoS l loS loS l l l noSoSoSoSoSoB+a zO/ 4 4 4 4 4o>X)+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+wO!oa 4 8 pO8O|oWoS l loBoS l n loSoS l loSoS l noSoS loS l noSoZ.-+_o[o9.. 4 q.^ ]+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+$oA+c+oO&o2+*X.Om+qoS noS loS l loSoSoS loS n n n loS l l goF.xX4Oz+:+povXi.*oX+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+;+;XO+*+*+*+#+D M m l l n noHoSoS loSoS loSoS l l noSoZOj 5X0+J+,X<XO+;+;XO+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*oP+&Ow.6 l loSoSoS l loSoS n l lOwOu l+ at +1+*X0+J+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+7XZO)X]O4.8Or noB goB+9+9+<Xq+M.K.BOS+GXX+*X0+J+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+7OHoyoy &XW.gX(otokOq.;Xoop.Lo'XC+^od 4o3oK+*X0+J+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*X.o/ w 4 4 4 4o5X_.c+Q.j+Y+UOGXLo+oy 4 4 4 4OKo1X0+J+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+)oYX#X4OO.#X,X; 7or 4o8+C f bXsX2+L f 4 4 4 4o8+PX%O6 ~ @OZ+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+r.y -o_ J.A.Y.Y.Y * k yOk.IX5.mOP.Y.IoGox 4 4o8XGOMO(.Y.YO(O(+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*.3o^ $OIOYXtOVX/o|o oa 4+`+-OTOY+bo&X:.P+xoa 4XDOM.Q+g+!Oy+0.Y+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*X#.<.GXt.W++ +or 4 4 4 4o{.MO}+8 4o{.M.`oV sX*.!+F+e `XX %OL+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+I.nO+X&+*.}o!XQ t 4 4+nXp+. x 4+nXpo4+uoxOdO`.|o#XO+*X0Oc+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+I+W.bOt+*+*+*.:on+z+/oTOl+. boi VOl+.ouXS+%O}XYXO+*+*X0+J+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+I+W.bOt+*+*+*+*+*+;.'o:On+:.=O<.,.p eoOX+O2._.X+rOpOp+5Xx+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+I+W.bOt+*+*+*+*+*+*+*X0+J+,+5XO+p+J+,X<+=.9.TO^O{O5O5O at .Y+,X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+).H.v+3+*+*+*+*+*+*+*X4OI+2X<+*X4OI+2X<+*X# .+6.(o<o<.(O`+2X<+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*X#X'O'+*+*+*+*+*+*+*+*+* > #+*+*+* > #+*+*+*+*O[X!X!X!XEX} #+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*",
+"+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*"
+};
diff --git a/doc/user/01_intro/history.html b/doc/user/01_intro/history.html
index dfbb89c..43cd001 100644
--- a/doc/user/01_intro/history.html
+++ b/doc/user/01_intro/history.html
@@ -1,6 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
 	<link rel="stylesheet" type="text/css" href="../default.css">
 </head>
 <body>
@@ -8,31 +10,27 @@
 <p>pcb-rnd is a rapid moving independent project that originated as a fork of the
 Pcb codebase.
 
-<pre>
-	From the pcb.html documentation:
-<i>
-<p>	<code>Pcb</code> was first written by Thomas Nau for an
+<p>
+From the pcb.html documentation:
+<pre><i>
+	<code>Pcb</code> was first written by Thomas Nau for an
 	Atari ST in 1990 and ported to <code>UNIX</code> and <code>X11</code> in
 	1994.  It was not intended as a professional layout system, but as a tool
 	which supports people who do some home-developing of hardware.
-
-<p>	Release history and credits for <code>Pcb</code> can be found in
+	Release history and credits for <code>Pcb</code> can be found in
 	the documentation files in mainline <code>Pcb</code>, and currently as of this writing at
 	<a href="http://pcb.geda-project.org/manual.html">http://pcb.geda-project.org/manual.html</a>
-</i>
-</pre>
+</i></pre>
 
 <p>In Fall 2013, Tibor Palinkas started an unofficial fork of Pcb to make and
 share changes and improvements, and over the following years the fork was
 officially announced, adopted additional users, and reached various <a href="milestones.html">milestones</a>
-<pre>
-<i>
+<pre><i>
 	15:39 < Igor2> $ svn log -r 1 svn://repo.hu/pcb-rnd
 	15:39 < Igor2>
 	------------------------------------------------------------------------
 	15:39 < Igor2> r1 | igor2 | 2013-08-30 17:33:06 +0200 (Fri, 30 Aug 2013) | 2
 	lines
 	15:39 < Igor2> -Add: trunk
-</i>
-</pre>
+</i></pre>
 </body>
diff --git a/doc/user/01_intro/index.html b/doc/user/01_intro/index.html
index 48fec38..c591faa 100644
--- a/doc/user/01_intro/index.html
+++ b/doc/user/01_intro/index.html
@@ -1,6 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
 	<link rel="stylesheet" type="text/css" href="../default.css">
 </head>
 <body>
@@ -32,8 +34,8 @@ formats making it easy to print boards, publish them on web pages, and include
 them in documentation.
 <p>
 The typical workflows are:
-<b>
-<img src="flow.svg">
+<p>
+<img src="flow.svg" alt="[workflow diagram showing pcb-rnd interacting with schematics editor, fabrication, and others]">
 <p>
 Black flows are the most commonly used; grey flows are possible, fully
 supported but less often used in practice.
diff --git a/doc/user/02_model/index.html b/doc/user/02_model/index.html
index b32b6b2..b459d33 100644
--- a/doc/user/02_model/index.html
+++ b/doc/user/02_model/index.html
@@ -1,6 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
 	<link rel="stylesheet" type="text/css" href="../default.css">
 </head>
 <body>
@@ -13,7 +15,7 @@ how pcb-rnd represents reality (e.g. copper shapes) in memory.
 
 <h3> 2.1. board </h3>
 <p>
-Each design pcb-rnd handles is a board. The has global properties and hosts
+Each design pcb-rnd handles is a <i>board</i>. The board has global properties and hosts
 layers. Most drawing primitives (objects) are on layers. This section describes
 the most important global properties.
 <p>
@@ -43,9 +45,22 @@ layer contains drawing primitives (objects) placed by the user. The user has
 full control over an explicit layer: objects can be added or removed or
 changed any time. A virtual layer has no such flexibility: pcb-rnd computes
 its content from explicit layers and there's no way to change the result
-directly. A layer has a type and a location.
+directly. A layer is always part of a <i>layer group</i>.
+
+<h3> 2.3. layer groups </h3>
+<p>
+One or more explicit layers form a <i>layer group</i>. All pcb-rnd layers
+of a layer group will end up on the same physical layer. The visibility of
+layers in a layer group are toggled together. The main use of layer groups
+is to exploit that layers have different drawing color on screen: there
+can be a signal and a gnd layers with different color in the same layer group,
+on the same physical layer.
+<p>
+Since <i>layer groups</i> donate the physical layers, a board stack-up
+is built of layer groups. Substrates are layer groups without drawable
+layers in them.
 <p>
-Layer types are:
+Layer group types are:
 <ul>
 	<li> copper for signal layers
 	<li> silk for silkscreen layers
@@ -54,19 +69,17 @@ Layer types are:
 	<li> (paste for solder paste - this is a virtual layer)
 </ul>
 <p>
-Note: pcb-rnd does not model substrate layers.
-<p>
-Layer locations are:
+Layer group locations are:
 <ul>
 	<li> top (used to be the "component side" in the age of thru-hole components)
 	<li> bottom (used to be the "solder side" in the age of thru-hole components)
-	<li> internal (sandwiched between other layers)
+	<li> intern (sandwiched between other layers)
 	<li> global (affects all physical layers, thus has no specific location)
 </ul>
 <p>
-Not all combination of type and location are supported, for example an internal
-silk layer does not make much sense. The table below lists whether a
-combination is supported or not.
+Not all combination of type and location are supported, for an outline layer
+is always global. The table below lists whether a combination is supported
+or not.
 <p>
 <table border=1>
 	<tr><th>   <th> top <th> bottom <th> intern <th> global
@@ -77,21 +90,12 @@ combination is supported or not.
 	<tr><th> paste  <td> yes <td> yes    <td> no     <td> no
 </table>
 
-<h3> 2.3. layer groups </h3>
-<p>
-One or more explicit layers form a <i>layer group</i>. All pcb-rnd layers
-of a layer group will end up on the same physical layer. The visibility of
-layers in a layer group are toggled together. The main use of layer groups
-is to exploit that layers have different drawing color on screen: there
-can be a signal and a gnd layers with different color in the same layer group,
-on the same physical layer.
-
 <h3> 2.4. Basic drawing objects </h3>
 <p>
 Pcb-rnd supports a small number of basic drawing objects, from which complex
 objects can be build. The following figure demonstrates all basic objects:
 <p>
-<img src="objects_basic.png">
+<img src="objects_basic.png" alt="[Arc, Line, Polygon, Pin, Via]">
 <p>
 Objects have flags that control their behavior. The following flags are common
 to all objects:
@@ -115,10 +119,10 @@ lines with random angle.
 <p>
 A line is specified by its two endpoints, width and clearance:
 <p>
-<img src="obj_line.png">
+<img src="obj_line.png" alt="[Line interacting with a polygon]">
 <p>
-A <i>clearance</i> is the gap between a line and the sorrounding polygon
-in the same layer group. The gap is made only if the sorrounding polygon has
+A <i>clearance</i> is the gap between a line and the surrounding polygon
+in the same layer group. The gap is made only if the surrounding polygon has
 the "clearpoly" flag set and the line has the "clearline" flag set. If either
 of these flags is not set, no gap is made - or in pcb-rnd terminology,
 the line is joined to the polygon.
@@ -135,7 +139,7 @@ Extra object flags:
 Arcs are round ended circular arcs with trace width and clearance. They
 behave like lines in all respects.
 <p>
-<img src="obj_arc.png">
+<img src="obj_arc.png" alt="[Arc interacting with a polygon]">
 <p>
 Although the arc is described with it's center, radius, start and end
 angles, the user interface may offer drawing arcs by endpoints.
@@ -170,7 +174,7 @@ with the "clearline" flag set will clear all "clearpolys" it is over -
 if there are multiple such polygons overlapping under the objects (on
 the same layer group), all such polygons get the clearance cutout.
 <p>
-If a polygyn is cut into multiple islands, the behaviour depends on the
+If a polygon is cut into multiple islands, the behaviour depends on the
 "fullpoly" flag of the polygon. If it is not set (default), only the largest
 island is kept, else all islands are kept. In the "fullpoly" mode islands
 will have no galvanic connection (unless the user adds vias and connect them
@@ -212,26 +216,26 @@ a hole always punches all layers; there's no pad stack support, the copper
 ring around the hole on each layer have the same sizes.
 <p>
 A copper ring also has a per layer property whether or how it connects to
-the sorrounding polygon on the given layer; this is called the thermal style
+the surrounding polygon on the given layer; this is called the thermal style
 of the via. The following options are available:
 <table border=1>
 	<tr><th>thermal style <th> appearance
-	<tr><td>no connection <td> <img src=TODO>
-	<tr><td>solid        <td> <img src=TODO>
-	<tr><td>round x 90   <td> <img src=TODO>
-	<tr><td>round x 45   <td> <img src=TODO>
-	<tr><td>sharp x 90   <td> <img src=TODO>
-	<tr><td>sharp x 45   <td> <img src=TODO>
+	<tr><td>no connection <td> <img src=TODO alt="TODO">
+	<tr><td>solid        <td> <img src=TODO alt="TODO">
+	<tr><td>round x 90   <td> <img src=TODO alt="TODO">
+	<tr><td>round x 45   <td> <img src=TODO alt="TODO">
+	<tr><td>sharp x 90   <td> <img src=TODO alt="TODO">
+	<tr><td>sharp x 45   <td> <img src=TODO alt="TODO">
 </table>
 <p>
 The shape of the copper annulus (the ring) is also selectable from a predefined
 set of symmetrical and asymmetrical set:
 <table border=1>
 	<tr><th>shape          <th> appearance
-	<tr><td>ring (default) <td> <img src=TODO>
-	<tr><td>square         <td> <img src=TODO>
-	<tr><td>octagon        <td> <img src=TODO>
-	<tr><td>asymmetrical   <td> <img src=TODO>
+	<tr><td>ring (default) <td> <img src=TODO alt="TODO">
+	<tr><td>square         <td> <img src=TODO alt="TODO">
+	<tr><td>octagon        <td> <img src=TODO alt="TODO">
+	<tr><td>asymmetrical   <td> <img src=TODO alt="TODO">
 </table>
 
 <h4> 2.4.6. element objects and footprints </h4>
@@ -244,7 +248,7 @@ board or loaded into a paste buffer.
 In the footprint form the construct is small and flexible. It describes
 all the physical parts, like pins, pads, silk lines. In the same time a
 footprint leaves many details blank, e.g. it doesn't specify exact layers,
-it doesn't a have font and the refdes is random.
+it doesn't have font and the refdes is random.
 
 <p>
 When the footprint is loaded, it becomes an element. The element inherits all
@@ -396,7 +400,7 @@ process is called "forward annotation".
 <p>
 It is also possible to make changes to the netlist from within pcb-rnd:
 pins can be swapped, element packages replaced using <i>back annotation
-actions</b>. Such actions will keep a list of intended netlist and element
+actions</i>. Such actions will keep a list of intended netlist and element
 changes, called the netlist patch. Pcb-rnd will keep these changes even
 if a new version of the netlist is imported. It is possible to export the
 netlist patch that can be imported in the schematics editor to change the
diff --git a/doc/user/04_invoc/index.html b/doc/user/04_invoc/index.html
index 2b44d83..368b975 100644
--- a/doc/user/04_invoc/index.html
+++ b/doc/user/04_invoc/index.html
@@ -1,6 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
 	<link rel="stylesheet" type="text/css" href="../default.css">
 </head>
 <body>
@@ -8,7 +10,6 @@
 
 <h2> 5.1 User Invocation (aka running pcb-rnd)</h2>
 <p>
-<ul>
 pcb-rnd is typically run by invoking it from the shell after installation 
 <p>
 <code>
@@ -23,5 +24,5 @@ pcb-rnd --help
 </code>
 <p>
 And at this time, choose alternative guis (Gtk, lesstif, remote)
-
-
+</body>
+</html>
diff --git a/doc/user/05_ui/01_gtk/index.html b/doc/user/05_ui/01_gtk/index.html
index 5184ba2..1aa47c2 100644
--- a/doc/user/05_ui/01_gtk/index.html
+++ b/doc/user/05_ui/01_gtk/index.html
@@ -1,6 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
 	<link rel="stylesheet" type="text/css" href="../../default.css">
 </head>
 <body>
@@ -33,13 +35,12 @@ pcb-rnd comes with a default graphical hid using GTK+
 </ol>
 <p>
 
-<h3><a name="main_window">Main Window<p></a></h3>
+<h3><a name="main_window">Main Window</a></h3>
 <br>
 <img src=base_window_highlight_main.png alt="Main layout window highlighted">
 <p>
 The main window in pcb-rnd is a drawing area for your layout. 
-</ul>
-<h3><a name="menus">Menus<p></a></h3>
+<h3><a name="menus">Menus</a></h3>
 <br>
 <img src=base_window_highlight_menus.png alt="Menus highlighted">
 <p>
@@ -57,36 +58,38 @@ menus:
 <li>Info - Generate reports and get keybindings
 <li>Window - open a auxiliary window (dialog)
 </ul>
-<h3><a name="operations_toolbar">Operations Toolbar<p></a></h3>
+<h3><a name="operations_toolbar">Operations Toolbar</a></h3>
 <br>
 <img src=base_window_highlight_workops.png alt="Operations toolbar highlighted">
 <p>
 Add to and edit your layout
-<h3><a name="layer_controller">Layer Controller<p></a></h3>
+<h3><a name="layer_controller">Layer Controller</a></h3>
 <br>
 <img src=base_window_layerops.png alt="Layer controls highlighted">
 <p>
 Change layer visibility 
-<h3><a name="coordinates_readout">Coordinates Readout<p></a></h3>
+<h3><a name="coordinates_readout">Coordinates Readout</a></h3>
 <br>
 <img src=base_window_highlight_coordsreadout.png alt="Coordinate readout highlighted">
 <p>
 Readouts give live info for the user: 
 Obtain absolute and relative coordinate information
-<h3><a name="route_styles">Route Styles<p></a></h3>
+<h3><a name="route_styles">Route Styles</a></h3>
 <br>
 <img src=base_window_highlight_routestyle.png alt="Route styles area highlighted">
 <p>
 Access route style dialog and alter existing route style 
-<h3><a name="ops_readout">Ops Readout<p></a></h3>
+<h3><a name="ops_readout">Ops Readout</a></h3>
 <br>
 <img src=base_window_highlight_opsreadout.png alt="Operations readout highlighted">
 <p>
 Readouts provide live info for the user
 Obtain view grid line drawing style reporter, via size, clearance value, text
 size, buffer number
-<h3><a name="key_commands">Key Commands<p></a></h3>
+<h3><a name="key_commands">Key Commands</a></h3>
 pcb-rnd key command standard...
 Quick Keys
-<h3><a name="gui_cli">Gui Command Line Interface <p></a></h3>
+<h3><a name="gui_cli">Gui Command Line Interface</a></h3>
 Enter the command line interface by typing :
+</body>
+</html>
diff --git a/doc/user/05_ui/02_cli/index.html b/doc/user/05_ui/02_cli/index.html
index 46dafbf..a193cd3 100644
--- a/doc/user/05_ui/02_cli/index.html
+++ b/doc/user/05_ui/02_cli/index.html
@@ -1,6 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
 	<link rel="stylesheet" type="text/css" href="../default.css">
 </head>
 <body>
@@ -8,7 +10,6 @@
 
 <h2> 5.2 Actions and Command Line Interface </h2>
 <p>
-<ul>
 pcb-rnd actions can be listed
 
 <p>
@@ -18,9 +19,11 @@ pcb-rnd actions can be listed
 
 <p>
 Uses for CLI:
+<ul>
 <li>format translation (with additional plugins active)
 <li>export (with additional plugins)
 <li>agnostic version control (use with git/mercurial/svn)
 </ul>
 <p>
-
+</body>
+</html>
diff --git a/doc/user/05_ui/index.html b/doc/user/05_ui/index.html
index b1aca9c..4d3d583 100644
--- a/doc/user/05_ui/index.html
+++ b/doc/user/05_ui/index.html
@@ -1,6 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
 	<link rel="stylesheet" type="text/css" href="../default.css">
 </head>
 <body>
@@ -16,10 +18,11 @@ The following sections describe all the existing pcb-rnd UI plugins. We start
 with the section on GTK+ because it is the most commonly used HID
 <p>
 <ul class="toc">
-	<li><a href="01_gtk/index.html">  4.1 GTK 
-	<li><a href="02_cli/index.html">  4.2 Actions and Command Line Interface
-	<li><a href="03_lesstif/">   4.3 lesstif
-	<li><a href="04_remote/">   4.4 remote
-	<li><a href="05_batch/">  4.5 batch
+	<li><a href="01_gtk/index.html"> 4.1 GTK </a>
+	<li><a href="02_cli/index.html"> 4.2 Actions and Command Line Interface </a>
+	<li><a href="03_lesstif/"> 4.3 lesstif </a>
+	<li><a href="04_remote/"> 4.4 remote </a>
+	<li><a href="05_batch/"> 4.5 batch </a>
 </ul>
-
+</body>
+</html>
diff --git a/doc/user/06_feature/gpmi/index.html b/doc/user/06_feature/gpmi/index.html
index e2b21c5..b4d56e1 100644
--- a/doc/user/06_feature/gpmi/index.html
+++ b/doc/user/06_feature/gpmi/index.html
@@ -1,4 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
+<head>
+	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+</head>
 <body>
 <H1> pcb-rnd GPMI scripting - TOC </H1>
 
diff --git a/doc/user/06_feature/gpmi/packages/layout_ref.html b/doc/user/06_feature/gpmi/packages/layout_ref.html
index 87a6432..77eb5b6 100644
--- a/doc/user/06_feature/gpmi/packages/layout_ref.html
+++ b/doc/user/06_feature/gpmi/packages/layout_ref.html
@@ -198,11 +198,6 @@
 <pre>
  return the theoretical number of layers supported by PCB 
 </pre>
-<a id="layout_get_max_copper_layer">
-<H4>  int layout_get_max_copper_layer()  </H4>
-<pre>
- return the actual number of copper layers on the current design 
-</pre>
 <a id="layout_get_max_layer">
 <H4>  int layout_get_max_layer()  </H4>
 <pre>
diff --git a/doc/user/06_feature/gpmi/scripting_intro.html b/doc/user/06_feature/gpmi/scripting_intro.html
index 390adf4..366164d 100644
--- a/doc/user/06_feature/gpmi/scripting_intro.html
+++ b/doc/user/06_feature/gpmi/scripting_intro.html
@@ -1,4 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
+<head>
+	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+</head>
 <body>
 <H1> Scripting intro </H1>
 This document is an introduction to GPMI for pcb-rnd users. It focuses on
@@ -15,7 +20,7 @@ described in other documents.
 Since scripts are glued to pcb-rnd internals, scripters need to know
 the basic concepts of how pcb-rnd is structured.
 
-<H3> 1.1 pcb-rnd, HIDs, plugins and GPMI </h2>
+<H3> 1.1 pcb-rnd, HIDs, plugins and GPMI </H3>
 pcb-rnd consists of:
 <ul>
 	<li> a <b>core</b> that handles the file format, data structures, UI and exporter logics
@@ -45,7 +50,7 @@ of the user, can be:
 	<li> compiled as buildin - becomes part of the pcb-rnd executable so that scripting is always available
 </ul>
 
-<H3> 1.2. Actions, menus, exporters </h2>
+<H3> 1.2. Actions, menus, exporters </H3>
 The core implements actions. An action is a command with custom arguments,
 e.g. Delete(Selected). These actions are the commands on the default command
 line in pcb-rnd. In batch mode the command language uses these actions as well.
@@ -72,7 +77,7 @@ steps:
 	     to draw the design layer by layer, object by object.
 </ol>
 
-<H3> 1.3. How a script can interact with the user </h2>
+<H3> 1.3. How a script can interact with the user </H3>
 <ul>
 	<li> The script may register <i>actions</i> - these actions are instantly accessible from the GUI command line, on stdin with --listen and in batch mode
 	<li> The script may <i>create menus</i> and bind them to actions - when the menu is selected, the action is executed
@@ -95,7 +100,7 @@ The glue layer comes in two kinds:
 	<li> gpmi package: dynamic lib, provides C functions the script can directly call; package functions then know how to deal with PCB internals
 </ul>
 Arrows drawn with dashed line represents a slow, <i>string based communication</i>.
-<td><img src="gpmi_flow.png"></table>
+<td><img src="gpmi_flow.png" alt="[gpmi HID interacting with pcb-rnd and other components]"></table>
 
 <H3> 2.2. Module, script, script context, packages </H3>
 <table border=0 width="100%"><tr><td valign=top>
@@ -126,7 +131,7 @@ Step 1. The green arrows represent this path: the script executes PkgLoad()
 which in turns loads other package(s) into the GPMI hid.
 <p>
 Packages are loaded only once and are globally accessible for multiple modules.
-<td><img src="gpmi_flow_load.png"></table>
+<td><img src="gpmi_flow_load.png" alt="[same diagram as before, with pacakge load flow highlighted]"></table>
 
 <H3> 2.3. Binding events, registering actions, creating menus </H3>
 <table border=0 width="100%"><tr><td valign=top>
@@ -146,7 +151,7 @@ is generated. This has two implications:
 	<li> a script that registers actions needs to bind the ACTE_action event to serve the action requests
 	<li> if a script registers multiple actions, in the event handler it needs to check which action triggered the event (e.g. with a switch()-like construction on the event name)
 </ul>
-<td><img src="gpmi_flow_reg.png"></table>
+<td><img src="gpmi_flow_reg.png" alt="[same diagram as before, with action registration flow highlighted]"></table>
 
 <table border=0 width="100%"><tr><td valign=top>
 Menus are created using the create_menu() call. <b>Menus can be
@@ -158,7 +163,7 @@ On the map to the right the red arrows represent the path of ACTE_gui_init;
 the green arrows represent the reaction of the script, creating the new
 menu.
 <p>
-<td><img src="gpmi_flow_menu.png"></table>
+<td><img src="gpmi_flow_menu.png" alt="[same diagram as before, with menu setup flow highlighted]"></table>
 
 <H3> 2.4. Exporting </H3>
 <table border=0 width="100%"><tr><td valign=top>
@@ -169,7 +174,7 @@ package. The following map shows this process with red arrows:
 When the user chooses to use the exporter, among the green arrows,
 a series of events are triggered and the script can generate output
 directly to a file from event handlers bound to these exporting events.
-<td><img src="gpmi_flow_exp.png"></table>
+<td><img src="gpmi_flow_exp.png" alt="[same diagram as before, with exporter flow highlighted]"></table>
 
 <H3> 2.5. Making modifications on the design </H3>
 The purpose of a script might be to manipulate the objects in the current design.
diff --git a/doc/user/08_util/01_gsch2pcb-rnd.htm b/doc/user/08_util/01_gsch2pcb-rnd.htm
index 00fb9b6..48b17a8 100644
--- a/doc/user/08_util/01_gsch2pcb-rnd.htm
+++ b/doc/user/08_util/01_gsch2pcb-rnd.htm
@@ -1,6 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
 	<link rel="stylesheet" type="text/css" href="../default.css">
 </head>
 <body>
@@ -48,3 +50,5 @@ one of these by name, using the -m command line argument (e.g.
 		     .net of the pcb method. Pro: the user can update elements-only or
 		     nets-only. Con: requires two user actions to get a full impoty.
 </table>
+</body>
+</html>
diff --git a/doc/user/08_util/install_cgi.html b/doc/user/08_util/install_cgi.html
index 7d1b58d..ceba0d7 100644
--- a/doc/user/08_util/install_cgi.html
+++ b/doc/user/08_util/install_cgi.html
@@ -1,4 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
+<head>
+	<title> pcb-rnd user manual </title>
+	<meta http-equiv="Content-Type" content="text/html;charset=us-ascii">
+</head>
 <body>
 <h1> Installation of the footprint CGIs </h1>
 <h2> system requirements, 3rd party software </h2>
diff --git a/pcblib/Makefile b/pcblib/Makefile
index eb72121..04abf55 100644
--- a/pcblib/Makefile
+++ b/pcblib/Makefile
@@ -1,6 +1,8 @@
 # This Makefile is a plain old hand written one; all configuration settings
 # are included from ../Makefile.conf which is scconfig generated
 
+ROOT=..
+
 all:
 
 # NOTE: this rule is _not_ called from linstall
@@ -30,5 +32,5 @@ uninstall:
 
 clean:
 
-include ../Makefile.conf
+include $(ROOT)/Makefile.conf
 
diff --git a/scconfig/Makefile b/scconfig/Makefile
index 2c9c2b7..2e074f0 100644
--- a/scconfig/Makefile
+++ b/scconfig/Makefile
@@ -64,7 +64,7 @@ OBJS = $(USER_OBJS) hooks.o $(DEFAULT_NOMAIN_OBJS) $(SCRIPT_OBJS) $(PARSER_OBJS)
 CFLAGS = $(USER_CFLAGS) $(DEFAULT_CFLAGS) $(SCRIPT_CFLAGS) $(PARSER_CFLAGS) $(GENERATOR_CFLAGS) $(TMPASM_CFLAGS) $(C99_CFLAGS) $(PARSGEN_CFLAGS) $(MATH_CFLAGS) $(SOCKET_CFLAGS) $(USERPASS_CFLAGS) $(GUI_CFLAGS)  $(SUL_CFLAGS) $(MENULIB_CFLAGS) -Isrc/default
 LDFLAGS = $(USER_LDFLAGS) $(DEFAULT_LDFLAGS) $(SCRIPT_LDFLAGS) $(PARSER_LDFLAGS) $(GENERATOR_LDFLAGS) $(TMPASM_LDFLAGS) $(C99_LDFLAGS) $(PARSGEN_LDFLAGS) $(MATH_LDFLAGS) $(SOCKET_LDFLAGS) $(USERPASS_LDFLAGS) $(GUI_LDFLAGS) $(SUL_LDFLAGS) $(MENULIB_LDFLAGS)
 
-all: configure revtest
+all: configure revtest sccbox
 
 revtest: revtest.o
 	$(CC) -o revtest revtest.o
@@ -89,6 +89,11 @@ hooks.o: plugin_3state.h plugins.h Rev.h
 src/util/arg_auto_set.o: src/util/arg_auto_set.c src/util/arg_auto_set.h
 	$(CC) -c $(CFLAGS) -o src/util/arg_auto_set.o src/util/arg_auto_set.c
 
+src/util/sccbox.o: src/util/sccbox.c
+	$(CC) -c $(CFLAGS) -o src/util/sccbox.o src/util/sccbox.c
+
+sccbox: src/util/sccbox.o
+	$(CC) $(LDFLAGS) -o sccbox src/util/sccbox.o
 
 cquote: cquote.c
 
@@ -96,5 +101,5 @@ clean:
 	-rm $(OBJS) $(DEFAULT_MAIN_OBJS) configure revtest revtest.o cquote core
 
 distclean:
-	-rm ../config.h ../Makefile.conf ../src/Makefile ../util/gsch2pcb-rnd/Makefile ../src_3rd/gts/Makefile config.cache config.log Rev.stamp
+	-rm ../config.h ../Makefile.conf ../src/Makefile ../util/gsch2pcb-rnd/Makefile config.cache config.log Rev.stamp sccbox
 	-$(MAKE) clean
diff --git a/scconfig/Rev.h b/scconfig/Rev.h
index 33dd21f..7e55230 100644
--- a/scconfig/Rev.h
+++ b/scconfig/Rev.h
@@ -1 +1 @@
-static const int myrev = 5611;
+static const int myrev = 6813;
diff --git a/scconfig/Rev.tab b/scconfig/Rev.tab
index 92761ca..056ce48 100644
--- a/scconfig/Rev.tab
+++ b/scconfig/Rev.tab
@@ -1,3 +1,14 @@
+6813	configure	new import plugins
+6735	configure	gtk splitup
+6392	configure	draw cross section plugin (gtk and lesstif depend on it)
+6365	configure	gtk splitup
+6111	configure	layer vs. layer group code split
+6093	distclean,configure	hid API extension for the common Cursor action
+6087	configure	start splitting up hid_gtk: new plugin that hid_gtk depends on: lib_gtk_common
+6056	configure	gschp2pcb-rnd build deps bug
+6007	configure	switch over Makefiles to use sccbox
+6004	distclean,configure	scconfig compiles sccbox thast will ease portable clean and installation rules
+5982	make clean	gsch2pcb-rnd build fix
 5611	configure	new feature: UI layer
 5487	configure	layer cleanup: layer visibility in a new source file
 5472	configure	draw_fab config subtree
diff --git a/scconfig/hooks.c b/scconfig/hooks.c
index 7daa631..fc03aa3 100644
--- a/scconfig/hooks.c
+++ b/scconfig/hooks.c
@@ -10,7 +10,7 @@
 #include "util/arg_auto_set.h"
 #include "Rev.h"
 
-#define version "1.2.0"
+#define version "1.2.1"
 
 #include "plugin_3state.h"
 
@@ -281,8 +281,7 @@ int hook_detect_host()
 /* until we rewrite the generators in C */
 	require("fstools/awk",  0, 1);
 
-	if (istrue(get("/local/pcb/debug")))
-		require("cc/argstd/*", 0, 0);
+	require("cc/argstd/*", 0, 0);
 
 	require("cc/func_attr/unused/*", 0, 0);
 	require("cc/inline", 0, 0);
@@ -300,11 +299,12 @@ int safe_atoi(const char *s)
 /* Runs when things should be detected for the target system */
 int hook_detect_target()
 {
-	int want_glib = 0, want_gtk, want_gd, want_stroke, need_inl = 0;
+	int want_glib = 0, want_gtk, want_gd, want_stroke, need_inl = 0, want_cairo;
 
 	want_gtk    = plug_is_enabled("hid_gtk");
 	want_gd     = plug_is_enabled("export_png") ||  plug_is_enabled("export_nelma") ||  plug_is_enabled("export_gcode");
 	want_stroke = plug_is_enabled("stroke");
+	want_cairo  = plug_is_enabled("export_bboard");
 
 	require("cc/fpic",  0, 1);
 	require("signal/names/*",  0, 0);
@@ -365,8 +365,17 @@ int hook_detect_target()
 	if (want_gtk) {
 		require("libs/gui/gtk2/presents", 0, 0);
 		if (!istrue(get("libs/gui/gtk2/presents"))) {
-			report_repeat("WARNING: Since there's no libgtk2 found, disabling the gtk hid...\n");
+			report_repeat("WARNING: Since there's no libgtk2 found, disabling the gtk hid and lib_gtk_common...\n");
 			hook_custom_arg("Disable-hid_gtk", NULL);
+			hook_custom_arg("Disable-lib_gtk_common", NULL);
+		}
+	}
+
+	if (want_cairo) {
+		require("libs/gui/cairo/presents", 0, 0);
+		if (!istrue(get("libs/gui/cairo/presents"))) {
+			report_repeat("WARNING: Since there's no cairo found, disabling the export_bboard plugin...\n");
+			hook_custom_arg("Disable-export_bboard", NULL);
 		}
 	}
 
@@ -392,13 +401,6 @@ int hook_detect_target()
 	if (want_gtk)
 		want_glib = 1;
 
-	if (plug_is_enabled("toporouter")) {
-		put("/local/gts/enable", strue);
-		want_glib = 1;
-	}
-	else
-		put("/local/gts/enable", sfalse);
-
 	if (plug_is_enabled("export_dsn"))
 		want_glib = 1;
 
@@ -412,10 +414,6 @@ int hook_detect_target()
 				report_repeat("WARNING: Since GLIB is not found, disabling the GTK HID...\n");
 				hook_custom_arg("Disable-gtk", NULL);
 			}
-			if (plug_is_enabled("toporouter")) {
-				report_repeat("WARNING: Since GLIB is not found, disabling the toporouter...\n");
-				hook_custom_arg("Disable-toporouter", NULL);
-			}
 			if (plug_is_enabled("puller")) {
 				report_repeat("WARNING: Since GLIB is not found, disabling the puller...\n");
 				hook_custom_arg("Disable-puller", NULL);
@@ -665,11 +663,13 @@ static void plugin_stat(const char *header, const char *path, const char *name)
 	printf("   [%s]\n", name);
 }
 
-static void print_sum_setting(const char *node, const char *desc)
+static void print_sum_setting_or(const char *node, const char *desc, int or)
 {
 	const char *res, *state;
 	state = get(node);
-	if (istrue(state))
+	if (or)
+		res = "enabled (implicit)";
+	else if (istrue(state))
 		res = "enabled";
 	else if (isfalse(state))
 		res = "disabled";
@@ -678,6 +678,11 @@ static void print_sum_setting(const char *node, const char *desc)
 	printf("%-55s %s\n", desc, res);
 }
 
+static void print_sum_setting(const char *node, const char *desc)
+{
+	print_sum_setting_or(node, desc, 0);
+}
+
 static void print_sum_cfg_val(const char *node, const char *desc)
 {
 	const char *state = get(node);
@@ -702,7 +707,6 @@ int hook_generate()
 
 	printf("Generating Makefile.conf (%d)\n", generr |= tmpasm("..", "Makefile.conf.in", "Makefile.conf"));
 
-	printf("Generating gts/Makefile (%d)\n", generr |= tmpasm("../src_3rd/gts", "Makefile.in", "Makefile"));
 	printf("Generating pcb/Makefile (%d)\n", generr |= tmpasm("../src", "Makefile.in", "Makefile"));
 
 	/* Has to be after pcb/Makefile so that all the modules are loaded. */
@@ -726,7 +730,7 @@ int hook_generate()
 	print_sum_setting("/local/pcb/want_parsgen",   "Regenerating languages with bison & flex");
 	print_sum_setting("/local/pcb/want_nls",       "Internationalization with gettext");
 	print_sum_setting("/local/pcb/debug",          "Compilation for debugging");
-	print_sum_setting("/local/pcb/symbols",        "Include debug symbols");
+	print_sum_setting_or("/local/pcb/symbols",        "Include debug symbols", istrue(get("/local/pcb/debug")));
 	print_sum_setting("libs/sul/dmalloc/presents", "Compile with dmalloc");
 	print_sum_cfg_val("/local/pcb/coord_bits",     "Coordinate type bits");
 	print_sum_cfg_val("/local/pcb/dot_pcb_rnd",    ".pcb_rnd config dir under $HOME");
diff --git a/scconfig/plugins.h b/scconfig/plugins.h
index 8294393..f74ba5f 100644
--- a/scconfig/plugins.h
+++ b/scconfig/plugins.h
@@ -1,6 +1,7 @@
 plugin_header("\nLibrary plugins:\n")
 plugin_def("lib_gensexpr",    "#s-expression library",     sdisable, 0)
 plugin_def("lib_legacy_func", "legacy functions",          sbuildin, 1)
+plugin_def("lib_gtk_common",  "all-hid_gtk common code",   sdisable, 0)
 
 plugin_header("\nFeature plugins:\n")
 plugin_def("gpmi",            "GPMI scripting",            sbuildin, 1)
@@ -11,12 +12,12 @@ plugin_def("boardflip",       "flip board objects",        sdisable, 0)
 plugin_def("distalign",       "distribute and align objs", sbuildin, 1)
 plugin_def("distaligntext",   "distribute and align text", sbuildin, 1)
 plugin_def("draw_fab",        "fab layer in some exports", sbuildin, 1)
+plugin_def("draw_csect",      "draw cross-section (layers)",sdisable, 1)
 plugin_def("jostle",          "push lines out of the way", sbuildin, 1)
 plugin_def("polycombine",     "combine selected polygons", sbuildin, 1)
 plugin_def("polystitch",      "stitch polygon at cursor",  sdisable, 0)
 plugin_def("teardrops",       "draw teardrops on pins",    sbuildin, 1)
 plugin_def("smartdisperse",   "netlist based dispenser",   sbuildin, 1)
-plugin_def("toporouter",      "topological autorouter",    sdisable, 0)
 plugin_def("autoplace",       "auto place components",     sbuildin, 1)
 plugin_def("vendordrill",     "vendor drill mapping",      sbuildin, 1)
 plugin_def("puller",          "puller",                    sbuildin, 1)
@@ -43,8 +44,11 @@ plugin_header("\nImport plugins:\n")
 plugin_def("import_sch",      "import sch",                sbuildin, 1)
 plugin_def("import_edif",     "import edif",               sbuildin, 1)
 plugin_def("import_netlist",  "import netlist",            sbuildin, 1)
-plugin_def("import_dsn",      "specctra .dsn importer",    sdisable, 0)
+plugin_def("import_dsn",      "specctra .dsn importer",    sbuildin, 1)
 plugin_def("import_hyp",      "hyperlynx .hyp importer",   sdisable, 0)
+plugin_def("import_mucs",     "import mucs routing",       sbuildin, 1)
+plugin_def("import_ltspice",  "import ltspice .net+.asc",  sbuildin, 1)
+plugin_def("import_tinycad",  "import tinycad .net",       sbuildin, 1)
 
 plugin_header("\nExport plugins:\n")
 plugin_def("export_gcode",    "gcode pcb_exporter",            sbuildin, 1)
@@ -59,10 +63,11 @@ plugin_def("export_dxf",      "DXF pcb_exporter",              sdisable, 0)
 plugin_def("export_test",     "dummy test pcb_exporter",       sdisable, 1)
 plugin_def("export_bboard",   "breadboard pcb_exporter",       sdisable, 0)
 plugin_def("export_openscad", "openscad pcb_exporter",         sdisable, 0)
-plugin_def("export_dsn",      "specctra .dsn pcb_exporter",    sdisable, 0)
+plugin_def("export_dsn",      "specctra .dsn pcb_exporter",    sbuildin, 1)
 plugin_def("export_ipcd356",  "IPC-D-356 Netlist pcb_exporter",sdisable, 0)
 plugin_def("export_svg",      "SVG pcb_exporter",              sbuildin, 1)
-plugin_def("export_stat",     "exporter board statistics",     sbuildin, 1)
+plugin_def("export_stat",     "export board statistics",       sbuildin, 1)
+plugin_def("export_fidocadj", "FidoCadJ .fcd pcb_exporter ",   sdisable, 0)
 
 plugin_header("\nIO plugins (file formats):\n")
 plugin_def("io_lihata",       "lihata board format",       sbuildin, 1)
@@ -79,6 +84,9 @@ plugin_def("hid_remote",      "remote HID server",         sdisable, 1)
 plugin_dep("export_lpr", "export_ps")
 plugin_dep("export_xy", "export_bom")
 plugin_dep("io_kicad", "lib_gensexpr")
+plugin_dep("hid_gtk", "lib_gtk_common")
+plugin_dep("hid_gtk", "draw_csect")
+plugin_dep("hid_lesstif", "draw_csect")
 
 /* for the uniq name lib: */
 plugin_dep("io_kicad_legacy", "io_kicad")
diff --git a/scconfig/src/default/find_cc.c b/scconfig/src/default/find_cc.c
index 2ae1e89..12955e8 100644
--- a/scconfig/src/default/find_cc.c
+++ b/scconfig/src/default/find_cc.c
@@ -180,7 +180,7 @@ int find_cc_argstd(int logdepth, int fatal)
 {
 	char *test_c = "#include <stdio.h>\nint main() { printf(\"OK\\n\");\nreturn 0;}\n";
 	char *out = NULL;
-	char **flg, *flags[] = {"-ansi", "-pedantic", "-Wall", NULL};
+	char **flg, *flags[] = {"-ansi", "-pedantic", "-Wall", "-std=c99", NULL};
 
 	require("cc/cc", logdepth, fatal);
 
@@ -188,9 +188,12 @@ int find_cc_argstd(int logdepth, int fatal)
 	report("Checking for cc args for std... ");
 
 	for(flg = flags; *flg != NULL; flg++) {
-		char name[128];
+		char name[128], *end;
 		const char *found = "";
 		sprintf(name, "cc/argstd/%s", (*flg)+1);
+		end = strchr(name, '=');
+		if (end != NULL)
+			*end = '_';
 		if (compile_run(logdepth+1, test_c, NULL, *flg, "", &out) == 0) {
 			if (target_emu_fail(out) || (strncmp(out, "OK", 2) == 0)) {
 				found = *flg;
diff --git a/scconfig/src/default/find_libs.c b/scconfig/src/default/find_libs.c
index 7d04a24..6c7a685 100644
--- a/scconfig/src/default/find_libs.c
+++ b/scconfig/src/default/find_libs.c
@@ -151,7 +151,7 @@ int find_lib_ldl(int logdepth, int fatal)
 
 int find_lib_LoadLibrary(int logdepth, int fatal)
 {
-	char *s;
+	/*char *s;*/
 
 	char *test_c =
 		NL "#include <stdio.h>"
diff --git a/scconfig/src/default/lib_pkg_config.c b/scconfig/src/default/lib_pkg_config.c
index 63fd12f..1dc20d4 100644
--- a/scconfig/src/default/lib_pkg_config.c
+++ b/scconfig/src/default/lib_pkg_config.c
@@ -65,12 +65,60 @@ const char *pkg_config_name()
 	name = get("/arg/sys/pkg-config");
 	if (name != NULL)
 		return name;
-	return "pkg-config"; /* fallback */
+	return "pkg-config";					/* fallback */
+}
+
+/** run_pkg_config_modversion:
+    run `pkg-config` on @pkgname:
+    - with `--modversion` if @modversion is not NULL, storing the result in @modversion (malloc()'d)
+    Returns 0 on success.
+*/
+int run_pkg_config_modversion(int logdepth, const char *pkgname, char **modversion)
+{
+	char cmd[256];
+	const char *confname = pkg_config_name();
+
+	assert(strlen(pkgname) < sizeof(cmd) - 64);
+
+	if (modversion != NULL) {
+		sprintf(cmd, "%s --modversion %s", confname, pkgname);
+		if (run(logdepth, cmd, modversion) != 0) {
+			/*report("Module version not found: %s --modversion %s failed.", confname, pkgname);
+			logprintf(logdepth, "Module version not found: %s --modversion %s failed.\n", confname, pkgname); */
+			return -1;
+		}
+		zap(modversion);
+		strip(*modversion);
+	}
+
+	return 0;
+}
+
+/** run_pkg_config_modversion_db:
+    run `pkg-config --modversion` on @pkgname to find module (or package) version
+    and store the result in @node/modversion
+    Returns 0 on success.
+*/
+int run_pkg_config_modversion_db(int logdepth, const char *node, const char *pkgname /*, char **modversion */ )
+{
+	char *modversion;
+	char *tmp;
+
+	if (run_pkg_config_modversion(logdepth, pkgname, &modversion) != 0) {
+		return -1;
+	}
+	/* Store the module version in node */
+	tmp = str_concat("/", node, "modversion", NULL);
+	put(tmp, modversion);
+	free(tmp);
+	free(modversion);
+
+	return 0;
 }
 
 int run_pkg_config(int logdepth, const char *pkgname, char **cflags, char **ldflags)
 {
-	
+
 	return run_gen_config(logdepth, pkg_config_name(), pkgname, cflags, ldflags);
 }
 
@@ -88,7 +136,7 @@ void run_pkg_config_lst(int logdepth, const char *pkgpat, int *argc, char ***arg
 
 	if (pkg_cfg_cache == NULL) {
 		char *cmd = str_concat(" ", pkg_config_name(), "--list-all", NULL);
-		run(logdepth, cmd, (char **)&pkg_cfg_cache);
+		run(logdepth, cmd, (char **) &pkg_cfg_cache);
 		free(cmd);
 		if (pkg_cfg_cache == NULL) {
 			pkg_cfg_cache = &no_pkg_cfg;
@@ -100,15 +148,16 @@ void run_pkg_config_lst(int logdepth, const char *pkgpat, int *argc, char ***arg
 		goto error;
 
 	s = list = strdup(pkg_cfg_cache);
-	for(;;) {
-		while(isspace(*s)) s++;
+	for (;;) {
+		while (isspace(*s))
+			s++;
 		if (*s == '\0')
 			break;
 		next = strpbrk(s, "\r\n");
 		if (next != NULL)
 			*next = '\0';
 		if (re_exec(s)) {
-			if ((n+2) >= a) { /* n+2: make sure there's always room for the NULL at the end */
+			if ((n + 2) >= a) {				/* n+2: make sure there's always room for the NULL at the end */
 				a += 16;
 				sf = realloc(sf, sizeof(char *) * a);
 			}
@@ -117,11 +166,11 @@ void run_pkg_config_lst(int logdepth, const char *pkgpat, int *argc, char ***arg
 				*end = '\0';
 
 			sf[n] = strclone(s);
-			sf[n+1] = re_subs_dup("");
-/*			report("\ns='%s' sf='%s'\n", s, sf[n]);*/
-			n+=2;
+			sf[n + 1] = re_subs_dup("");
+/*      report("\ns='%s' sf='%s'\n", s, sf[n]);*/
+			n += 2;
 		}
-		s = next+1;
+		s = next + 1;
 	}
 
 	if (sf != NULL)
diff --git a/scconfig/src/default/lib_try.c b/scconfig/src/default/lib_try.c
index 5fda2cd..cdb460b 100644
--- a/scconfig/src/default/lib_try.c
+++ b/scconfig/src/default/lib_try.c
@@ -24,7 +24,7 @@ static int try_icl_(int logdepth, const char *prefix, const char *test_c_in, con
 	else
 		test_c = test_c_in;
 
-	logprintf(logdepth, "trying '%s' and '%s' and '%s', %s\n", includes == NULL ? "" : includes, cflags, ldflags, run ? "with a run" : "with no run");
+	logprintf(logdepth, "trying '%s' and '%s' and '%s', %s\n", str_null(includes), str_null(cflags), str_null(ldflags), run ? "with a run" : "with no run");
 
 	if (run)
 		compres = compile_run(logdepth+1, test_c, NULL, cflags, ldflags, &out);
@@ -81,11 +81,11 @@ static int try_icl_(int logdepth, const char *prefix, const char *test_c_in, con
 			}
 
 			if (inc != NULL) {
-				report("OK ('%s', '%s' and '%s')\n", inc, cflags, ldflags);
+				report("OK ('%s', '%s' and '%s')\n", str_null(inc), str_null(cflags), str_null(ldflags));
 				free(inc);
 			}
 			else
-				report("OK ('%s' and '%s')\n", cflags, ldflags);
+				report("OK ('%s' and '%s')\n", str_null(cflags), str_null(ldflags));
 
 			sprintf(tmp, "%s/presents", prefix);
 			put(tmp, strue);
diff --git a/scconfig/src/default/libs.h b/scconfig/src/default/libs.h
index b732a0c..dc9287f 100644
--- a/scconfig/src/default/libs.h
+++ b/scconfig/src/default/libs.h
@@ -1,8 +1,8 @@
 #define NL "\n"
 
 /* main.c */
-extern int no_autodetect_sys; /* set this to 1 to suppress system and cross detection */
-extern int no_save_cache;     /* set this to 1 to avoid saving config.cache */
+extern int no_autodetect_sys;		/* set this to 1 to suppress system and cross detection */
+extern int no_save_cache;				/* set this to 1 to avoid saving config.cache */
 
 /* lib_try.c: try to compile and run a test code; save results under prefix, if worked */
 /* include, compile-flags, link-flags;
@@ -11,31 +11,35 @@ extern int no_save_cache;     /* set this to 1 to avoid saving config.cache */
    the test code has to print "OK" if it worked. If prefix is NULL, do not
    modify the db or announce the output, silently return 0 or 1.
    Returns 1 if worked, 0 if not */
-int try_icl(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags);
+int try_icl(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags,
+						const char *ldflags);
 
 /* same as try_icl(), but does not execute the code, only compiles. Useful
    for test programs with undesirable side effects (e.g. gtk: would open a window) */
-int try_icl_norun(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags);
+int try_icl_norun(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags,
+									const char *ldflags);
 
 /* use try_icl() on a list of packages found by pkg-config. Stick to the version
    required if reqver is non-NULL, else try them in the order pkg-config returned
    them. */
-int try_icl_pkg_config(int logdepth, const char *prefix, const char *test_c, char *includes, const char *pkgpat, const char *reqver);
+int try_icl_pkg_config(int logdepth, const char *prefix, const char *test_c, char *includes, const char *pkgpat,
+											 const char *reqver);
 
 /* call this when failed to find the feature (after multiple try_*() calls);
    always returns 1 (so that return try_fail() does the Right Thing) */
 int try_fail(int logdepth, const char *prefix);
 
 /* lib_compile.c */
-extern int cross_blind; /* 1 if crosscompiling is blind (no emulator to test with) */
+extern int cross_blind;					/* 1 if crosscompiling is blind (no emulator to test with) */
 
-char *shell_escape_dup(const char *in); /* strdup in and escape any special char for the shell */
+char *shell_escape_dup(const char *in);	/* strdup in and escape any special char for the shell */
 
 int compile_file(int logdepth, const char *fn_input, char **fn_output, const char *cc, const char *cflags, const char *ldflags);
 int compile_code(int logdepth, const char *testcode, char **fn_output, const char *cc, const char *cflags, const char *ldflags);
 int run(int logdepth, const char *cmd_, char **stdout_saved);
 int run_shell(int logdepth, const char *cmd_, char **stdout_saved);
-int compile_run(int logdepth, const char *testcode, const char *cc, const char *cflags, const char *ldflags, char **stdout_saved);
+int compile_run(int logdepth, const char *testcode, const char *cc, const char *cflags, const char *ldflags,
+								char **stdout_saved);
 int run_script(int logdepth, const char *interpreter, const char *script, const char *suffix, char **out);
 
 /* lib_file.c */
@@ -48,9 +52,9 @@ int is_dir(const char *path);
 int is_file(const char *path);
 int exists(const char *path);
 int exists_in(const char *dir, const char *file);
-char *file_name(const char *path); /* returns malloc'd buffer */
-char *dir_name(const char *path);  /* returns malloc'd buffer */
-char *tempfile_new_noabort(const char *suffix); /* for internal use - returns NULL instead of aborting when temp file can not be created */
+char *file_name(const char *path);	/* returns malloc'd buffer */
+char *dir_name(const char *path);	/* returns malloc'd buffer */
+char *tempfile_new_noabort(const char *suffix);	/* for internal use - returns NULL instead of aborting when temp file can not be created */
 int touch_file(const char *path);
 
 /* lib_filelist.c */
@@ -59,30 +63,33 @@ void filelist_free(int *argc, char ***argv);
 
 /* lib_pkg_config.c */
 
-/* run pkg config on pkgname:
-    - with --cflags if cflags is not NULL, storing the result in cflags (malloc()'d)
-    - with --libs if ldflags is not NULL, storing the result in ldflags (malloc()'d)
+/** run pkg config on @pkgname:
+    - with `--cflags` if cflags  is not NULL, storing the result in cflags  (malloc()'d)
+    - with `--libs`   if ldflags is not NULL, storing the result in ldflags (malloc()'d)
    Returns 0 on success.
 */
 int run_pkg_config(int logdepth, const char *pkgname, char **cflags, char **ldflags);
 
-/* same as run_pkg_config, but runs a generic config tool (e.g. gdconfig)
-   passed in confname */
+/** same as run_pkg_config(), but runs a generic config tool (e.g. gdconfig)
+    passed in confname */
 int run_gen_config(int logdepth, const char *confname, const char *pkgname, char **cflags, char **ldflags);
 
-/* run pkg-config --list-all and keep lines matching regex pkgpat.
+int run_pkg_config_modversion(int logdepth, const char *pkgname, char **modversion);
+int run_pkg_config_modversion_db(int logdepth, const char *node, const char *pkgname);
 
-   argc/argv is a filelist output, each item pair is package name returned by
-   pkg_config (odd items are full package names, even items are suffixes:
-   pkgpath match removed)
+/** run pkg-config --list-all and keep lines matching regex pkgpat.
+
+    argc/argv is a filelist output, each item pair is package name returned by
+    pkg_config (odd items are full package names, even items are suffixes:
+    pkgpath match removed)
 */
 void run_pkg_config_lst(int logdepth, const char *pkgpat, int *argc, char ***argv);
 
 
 /* lib_uniqinc.c */
-char **uniq_inc_arr(const char *includes, int indirect, const char *sep, int *numlines); /* split includes by sep; includes is a list of nodes to get() if indirect is non-zero; return a NULL-terminated array of unique include strings and set *numlines if numlines is not NULL */
-void uniq_inc_free(char **arr); /* free an array returned by uniq_inc_arr() */
-char *uniq_inc_str(const char *includes, const char *isep, const char *osep, int sort); /* take a long list of includes separated by isep and emit an uniq list separated by osep */
+char **uniq_inc_arr(const char *includes, int indirect, const char *sep, int *numlines);	/* split includes by sep; includes is a list of nodes to get() if indirect is non-zero; return a NULL-terminated array of unique include strings and set *numlines if numlines is not NULL */
+void uniq_inc_free(char **arr);	/* free an array returned by uniq_inc_arr() */
+char *uniq_inc_str(const char *includes, const char *isep, const char *osep, int sort);	/* take a long list of includes separated by isep and emit an uniq list separated by osep */
 
 /* str.c */
 char *strclone(const char *str);
@@ -91,10 +98,10 @@ char *trim_right(char *str);
 char *strip(char *str);
 char *str_chr(char *str, char c);
 char *str_rchr(char *str, char c);
-char *str_subsn(const char *str); /* advanced strdup that also interprets \n */
-char *str_concat(const char *sep, ...); /* concat a list of strings into a newly allocated buffer, putting sep between them */
+char *str_subsn(const char *str);	/* advanced strdup that also interprets \n */
+char *str_concat(const char *sep, ...);	/* concat a list of strings into a newly allocated buffer, putting sep between them */
 char *esc_interpret(const char *str);
-int chr_inset(char c, const char *set); /* returns whether c is in set */
+int chr_inset(char c, const char *set);	/* returns whether c is in set */
 
 /* srctree.c */
 
@@ -109,3 +116,4 @@ char *svn_info(int logdepth, const char *dir, const char *key);
 #define target_emu_fail(out) ((isblind(db_cwd)) && (out == NULL))
 
 #define safeNULL(s)  ((s) == NULL ? "(NULL)" : (s))
+#define str_null(s)  ((s) == NULL ? "" : (s))
diff --git a/scconfig/src/gui/Makefile.plugin b/scconfig/src/gui/Makefile.plugin
index d8d4fcf..35fa415 100644
--- a/scconfig/src/gui/Makefile.plugin
+++ b/scconfig/src/gui/Makefile.plugin
@@ -1,9 +1,11 @@
 GUI_CFLAGS = -DPLUGIN_GUI
 GUI_OBJS = \
   $(BIN)/gui/find_gtk2.o \
+  $(BIN)/gui/find_gtk3.o \
   $(BIN)/gui/find_lesstif2.o \
   $(BIN)/gui/find_x.o \
   $(BIN)/gui/find_gd.o \
+  $(BIN)/gui/find_cairo.o \
   $(BIN)/gui/find_misc.o \
   $(BIN)/gui/gui.o
 
@@ -12,6 +14,9 @@ GUI_OBJS = \
 $(BIN)/gui/find_gtk2.o: $(SRC)/gui/find_gtk2.c
 	$(CC) $(CFLAGS) -c $(SRC)/gui/find_gtk2.c -o $(BIN)/gui/find_gtk2.o
 
+$(BIN)/gui/find_gtk3.o: $(SRC)/gui/find_gtk3.c
+	$(CC) $(CFLAGS) -c $(SRC)/gui/find_gtk3.c -o $(BIN)/gui/find_gtk3.o
+
 $(BIN)/gui/find_lesstif2.o: $(SRC)/gui/find_lesstif2.c
 	$(CC) $(CFLAGS) -c $(SRC)/gui/find_lesstif2.c -o $(BIN)/gui/find_lesstif2.o
 
diff --git a/scconfig/src/gui/find_cairo.c b/scconfig/src/gui/find_cairo.c
new file mode 100644
index 0000000..6da1462
--- /dev/null
+++ b/scconfig/src/gui/find_cairo.c
@@ -0,0 +1,70 @@
+/*
+    scconfig - gui lib detection - cairo
+    Copyright (C) 2017  Tibor Palinkas
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+		Project page: http://repo.hu/projects/scconfig
+		Contact via email: scconfig [at] igor2.repo.hu
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "libs.h"
+#include "log.h"
+#include "db.h"
+#include "dep.h"
+
+int find_cairo(int logdepth, int fatal)
+{
+	const char *test_c =
+		NL "#include <stdlib.h>"
+		NL "#include <stdio.h>"
+		NL "#include \"cairo.h\""
+		NL "int main() {"
+		NL "	cairo_t *ctx;"
+		NL "	cairo_surface_t *surf;"
+		NL
+		NL "	if (cairo_image_surface_create(CAIRO_FORMAT_RGB24, 100, 100) != NULL)"
+		NL "		puts(\"OK\");"
+		NL "	return 0;"
+		NL "}"
+		NL;
+	const char *node = "libs/gui/cairo";
+	char *cflags = NULL;
+	char *ldflags = NULL;
+
+	if (require("cc/cc", logdepth, fatal))
+		return try_fail(logdepth, node);
+
+	report("Checking for cairo... ");
+	logprintf(logdepth, "find_cairo: running pkg-config...\n");
+	logdepth++;
+
+	if (run_pkg_config(logdepth, "cairo", &cflags, &ldflags) == 0) {
+		if (try_icl(logdepth, node, test_c, NULL, cflags, ldflags) != 0)
+			goto success;
+	}
+
+	return try_fail(logdepth, node);
+
+	success:;
+	if (cflags != NULL)
+		free(cflags);
+	if (ldflags != NULL)
+		free(ldflags);
+	return 0;
+}
+
diff --git a/scconfig/src/gui/find_cairo.h b/scconfig/src/gui/find_cairo.h
new file mode 100644
index 0000000..742eefc
--- /dev/null
+++ b/scconfig/src/gui/find_cairo.h
@@ -0,0 +1,2 @@
+int find_cairo(int logdepth, int fatal);
+
diff --git a/scconfig/src/gui/find_gtk2.c b/scconfig/src/gui/find_gtk2.c
index 3e22fc7..1e724c6 100644
--- a/scconfig/src/gui/find_gtk2.c
+++ b/scconfig/src/gui/find_gtk2.c
@@ -27,6 +27,9 @@
 #include "db.h"
 #include "dep.h"
 
+static const char *node = "libs/gui/gtk2";
+static const char *pkgname = "gtk+-2.0";
+
 int find_gtk2(int logdepth, int fatal, const char *call, const char *arg)
 {
 	const char *test_c =
@@ -43,11 +46,10 @@ int find_gtk2(int logdepth, int fatal, const char *call, const char *arg)
 		NL "	gtk_main();"
 		NL "	return EXIT_SUCCESS;"
 		NL "}";
-	const char *node = "libs/gui/gtk2";
 	char *cflags;
 	char *ldflags;
-	(void) call;  /* not used */
-	(void) arg;  /* not used */
+	(void) call;									/* not used */
+	(void) arg;										/* not used */
 
 	if (require("cc/cc", logdepth, fatal))
 		return try_fail(logdepth, node);
@@ -56,11 +58,10 @@ int find_gtk2(int logdepth, int fatal, const char *call, const char *arg)
 	logprintf(logdepth, "find_gtk2: running pkg-config...\n");
 	logdepth++;
 
-	if (run_pkg_config(logdepth, "gtk+-2.0", &cflags, &ldflags) != 0) {
+	if (run_pkg_config(logdepth, pkgname, &cflags, &ldflags) != 0) {
 		return try_fail(logdepth, node);
 	}
 
-
 	if (try_icl_norun(logdepth, node, test_c, NULL, cflags, ldflags) == 0) {
 		free(cflags);
 		free(ldflags);
@@ -71,3 +72,12 @@ int find_gtk2(int logdepth, int fatal, const char *call, const char *arg)
 	free(ldflags);
 	return 0;
 }
+
+int find_gtk2_modversion(int logdepth, int fatal)
+{
+	if (run_pkg_config_modversion_db(logdepth, node, pkgname) != 0)
+		return try_fail(logdepth, node);
+	return 0;
+}
+
+
diff --git a/scconfig/src/gui/find_gtk2.h b/scconfig/src/gui/find_gtk2.h
index 334c8e8..5d05365 100644
--- a/scconfig/src/gui/find_gtk2.h
+++ b/scconfig/src/gui/find_gtk2.h
@@ -1,2 +1,2 @@
 int find_gtk2(int logdepth, int fatal);
-
+int find_gtk2_modversion(int logdepth, int fatal);
diff --git a/scconfig/src/gui/find_gtk3.c b/scconfig/src/gui/find_gtk3.c
new file mode 100644
index 0000000..cd84a21
--- /dev/null
+++ b/scconfig/src/gui/find_gtk3.c
@@ -0,0 +1,88 @@
+/*
+    scconfig - gui lib detection - gtk3
+    Copyright (C) 2017  Alain Vigne
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+		Project page: http://repo.hu/projects/scconfig
+		Contact via email: scconfig [at] igor2.repo.hu
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "libs.h"
+#include "log.h"
+#include "db.h"
+#include "dep.h"
+
+int find_gtk3(int logdepth, int fatal, const char *call, const char *arg)
+{
+	const char *test_c =
+		NL "#include <gtk/gtk.h>"
+		NL
+		NL "static void"
+		NL "activate (GtkApplication* app,"
+		NL "          gpointer        user_data)"
+		NL "{"
+		NL "  GtkWidget *window;"
+		NL
+		NL "  window = gtk_application_window_new (app);"
+		NL "  gtk_window_set_title (GTK_WINDOW (window), \"Window\");"
+		NL "  gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);"
+		NL "  gtk_widget_show_all (window);"
+		NL "}"
+		NL
+		NL "int"
+		NL "main (int    argc,"
+		NL "      char **argv)"
+		NL "{"
+		NL "  GtkApplication *app;"
+		NL "  int status;"
+		NL
+		NL "  app = gtk_application_new (\"org.gtk.example\", G_APPLICATION_FLAGS_NONE);"
+		NL "  g_signal_connect (app, \"activate\", G_CALLBACK (activate), NULL);"
+		NL "  status = g_application_run (G_APPLICATION (app), argc, argv);"
+		NL "  g_object_unref (app);"
+		NL
+		NL "  return status;"
+		NL "}";
+	const char *node = "libs/gui/gtk3";
+	const char *pkgname = "gtk+-3.0";
+	char *cflags;
+	char *ldflags;
+	(void) call;									/* not used */
+	(void) arg;										/* not used */
+
+	if (require("cc/cc", logdepth, fatal))
+		return try_fail(logdepth, node);
+
+	report("Checking for gtk+3... ");
+	logprintf(logdepth, "find_gtk3: running pkg-config...\n");
+	logdepth++;
+
+	if (run_pkg_config(logdepth, pkgname, &cflags, &ldflags) != 0) {
+		return try_fail(logdepth, node);
+	}
+
+	if (try_icl_norun(logdepth, node, test_c, NULL, cflags, ldflags) == 0) {
+		free(cflags);
+		free(ldflags);
+		return try_fail(logdepth, node);
+	}
+
+	free(cflags);
+	free(ldflags);
+	return 0;
+}
diff --git a/scconfig/src/gui/find_gtk3.h b/scconfig/src/gui/find_gtk3.h
new file mode 100644
index 0000000..ccb8abc
--- /dev/null
+++ b/scconfig/src/gui/find_gtk3.h
@@ -0,0 +1,2 @@
+int find_gtk3(int logdepth, int fatal);
+
diff --git a/scconfig/src/gui/gui.c b/scconfig/src/gui/gui.c
index d88df40..a2ef30a 100644
--- a/scconfig/src/gui/gui.c
+++ b/scconfig/src/gui/gui.c
@@ -5,8 +5,10 @@
 
 #include "find_x.h"
 #include "find_gtk2.h"
+#include "find_gtk3.h"
 #include "find_lesstif2.h"
 #include "find_gd.h"
+#include "find_cairo.h"
 #include "find_misc.h"
 
 void deps_gui_init()
@@ -14,10 +16,13 @@ void deps_gui_init()
 	dep_add("libs/gui/xinerama/*",          find_xinerama);
 	dep_add("libs/gui/xrender/*",           find_xrender);
 	dep_add("libs/gui/gtk2/*",              find_gtk2);
+	dep_add("libs/gui/gtk2/modversion",     find_gtk2_modversion);
+	dep_add("libs/gui/gtk3/*",              find_gtk3);
 	dep_add("libs/gui/lesstif2/*",          find_lesstif2);
 	dep_add("libs/gui/libstroke/*",         find_libstroke);
 	dep_add("libs/gui/gd/gdImagePng/*",     find_gdimagepng);
 	dep_add("libs/gui/gd/gdImageGif/*",     find_gdimagegif);
 	dep_add("libs/gui/gd/gdImageJpeg/*",    find_gdimagejpeg);
 	dep_add("libs/gui/gd/*",                find_gd);
+	dep_add("libs/gui/cairo/*",             find_cairo);
 }
diff --git a/scconfig/src/util/Makefile b/scconfig/src/util/Makefile
new file mode 100644
index 0000000..8b67dc9
--- /dev/null
+++ b/scconfig/src/util/Makefile
@@ -0,0 +1,7 @@
+#CC=i586-mingw32msvc-gcc
+#CFLAGS = -Wall -g
+
+sccbox: sccbox.c Makefile
+	$(CC) $(CFLAGS) sccbox.c -o sccbox
+
+
diff --git a/scconfig/src/util/sccbox.c b/scconfig/src/util/sccbox.c
new file mode 100644
index 0000000..2649631
--- /dev/null
+++ b/scconfig/src/util/sccbox.c
@@ -0,0 +1,645 @@
+/*
+    scconfig - sccbox: portable copy, link, mkdir and remove
+    Copyright (C) 2016  Tibor Palinkas
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+		Project page: http://repo.hu/projects/scconfig
+		Contact via email: scconfig [at] igor2.repo.hu
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+/*********************** DOCUMENTATION **************************/
+
+static void help_generic(const char *prg)
+{
+	printf("sccbox - Makefile helper\n\n");
+	printf("Invocation: %s cmd [switches] [paths]\n\n", prg);
+	printf("sccbox and provides a basic set of file-system utilities as a single,\n");
+	printf("static linkable executable with dependency only on libc. It is implemented\n");
+	printf("in C89 and uses only a very thin layer of non-C89 OS calls that trace\n");
+	printf("back to early BSD days and are widely available on all platforms.\n\n");
+	printf("The intention is to replace 'mkdir -p' and 'rm -f' and similar,\n");
+	printf("non-portable commands with a less efficient, but more portable local\n");
+	printf("implementation. Using sccbox for mkdir/install/uninstall exclusively also\n");
+	printf("simplifies the Makefile rules because the semantics of uninstall\n");
+	printf("matches the semantics of install and the same list of source files\n");
+	printf("and destination can be passed and source files are not removed.\n\n");
+	printf("For more info read the following help topics using --help topic:\n");
+	printf("  error       error handling\n");
+	printf("  rm          remove files (e.g. for make clean)\n");
+	printf("  mkdir       create directories (e.g. for make *install)\n");
+	printf("  ln          create symlink (e.g. for make *install)\n");
+	printf("  install     copy-install files (e.g. for make install)\n");
+	printf("  linstall    symlink-install files (e.g. for make linstall)\n");
+	printf("  uninstall   remove files (e.g. for make uninstall)\n");
+	printf("\n");
+}
+
+static void help_error(const char *prg)
+{
+	printf("sccbox - error handling (all commands)\n\n");
+	printf("Any sccbox command by default will try to carry out the requested\n");
+	printf("operation assuming no errors, e.g. an mkdir will assume the target\n");
+	printf("directory does not exists but all parent directories are in place.\n");
+	printf("If such a command fails, the exit status is non-zero and error messages\n");
+	printf("are printed to stderr.\n\n");
+	printf("If the --quiet switch is specified, the command will try to do the same\n");
+	printf("but never prints error messages and always returns 0. This is useful\n");
+	printf("in situations when failure is expected (note: 2>/dev/null is not portable)\n\n");
+	printf("If the --force switch is specified, the command will make extre efforts,\n");
+	printf("sometimes even destructive ones, to fulfill the request. If it fails,\n");
+	printf("error messages are printed (unless --quiet).\n\n");
+}
+
+static void help_rm_common(void)
+{
+	printf("  --quiet  don't print error messages and set exit status to 0\n");
+	printf("  --force  a non-existing file is not an error\n");
+}
+
+static void help_rm(const char *prg)
+{
+	printf("sccbox rm [switches] paths\n\n");
+	printf("Remove one or more paths from the file system. Paths can be\n");
+	printf("files, symlinks and empty directories. Recursive removal is not\n");
+	printf("supported. If multiple paths specified, attempt to remove them all\n");
+	printf("even if some can not be removed.\n\n");
+	printf("Switches:\n");
+	help_rm_common();
+	printf("\n");
+}
+
+static void help_mkdir(const char *prg)
+{
+	printf("sccbox mkdir [switches] paths\n\n");
+	printf("Create one or more directories.\n\n");
+	printf("Switches:\n");
+	printf("  --quiet  don't print error messages and set exit status to 0\n");
+	printf("  --force  ignored (there's nothing to force)\n");
+	printf("  -p       create parent directories automatically\n");
+	printf("  -u       do not do anyhting, exit 0\n");
+	printf("  -r       do not do anyhting, exit 0\n\n");
+}
+
+static void help_ln_common(void)
+{
+	printf("  --quiet     don't print error messages and set exit status to 0\n");
+	printf("  --force     attempt to remove target if it exists\n");
+}
+
+static void help_ln(const char *prg)
+{
+	printf("sccbox mkdir [switches] existing new\n");
+	printf("sccbox mkdir [switches] existing1 existing2 ... dir\n\n");
+	printf("Create one or more simlinks. Intended for linking installed paths\n");
+	printf("to other installed paths.\n\n");
+	printf("Switches:\n");
+	help_ln_common();
+	printf("  --absolute  convert existing paths to absolute paths\n\n");
+}
+
+static void help_install(const char *prg)
+{
+	printf("sccbox install [switches] src_file dst_file\n");
+	printf("sccbox install [switches] src_file1 src_file2 ... dir\n\n");
+	printf("Copies (or links or removes) one or more files. Intended to install\n");
+	printf("files from the source or build tree to the installation root.\n\n");
+	printf("Switches:\n");
+	printf("  --quiet     don't print error messages and set exit status to 0\n");
+	printf("  --force     install: attempt to remove destination\n");
+	printf("  --absolute  convert existing paths to absolute paths\n");
+	printf("  -i          install (copy) files\n");
+	printf("  -c          install (copy) files\n");
+	printf("  -u          uninstall (remove) files - see --help uninstall\n");
+	printf("  -r          uninstall (remove) files - see --help uninstall\n");
+	printf("  -l          linstall (symlink) files - see --help linstall\n\n");
+}
+
+static void help_linstall(const char *prg) {
+	printf("sccbox linstall [switches] src_file dst_file\n");
+	printf("sccbox linstall [switches] src_file1 src_file2 ... dir\n\n");
+	printf("Installs (a) file(s) using symlinks. Automatically convert src_file\n");
+	printf("paths to absolute paths. Intended for developers: if a package is\n");
+	printf("symlink-installed, it can be run from the installation after a\n");
+	printf("recompilation without needing to reinstall.\n\n");
+	printf("Switches:\n");
+	help_ln_common();
+	printf("  --preserve  do not convert source paths to absolute\n\n");
+}
+
+static void help_uninstall(const char *prg) {
+	printf("sccbox uninstall [switches] src_file dst_file\n");
+	printf("sccbox uninstall [switches] src_file1 src_file2 ... dir\n\n");
+	printf("Remove (an) installed file(s). In the first form, src_file is ignored.\n");
+	printf("In the second form dir is used to calculate destination paths.\n\n");
+	printf("The purpose of this command is to unify install and uninstall rules:\n");
+	printf("unlike cp and rm, an 'sccbox install' and 'sccbox uninstall' can\n");
+	printf("be used with the same parameter list to install and uninstall a set of files\n\n");
+	printf("Switches:\n");
+	help_rm_common();
+	printf("\n");
+}
+
+static int help(const char *prg, const char *topic)
+{
+	if (topic == NULL) help_generic(prg);
+	else if (strcmp(topic, "error") == 0) help_error(prg);
+	else if (strcmp(topic, "rm") == 0) help_rm(prg);
+	else if (strcmp(topic, "mkdir") == 0) help_mkdir(prg);
+	else if (strcmp(topic, "ln") == 0) help_ln(prg);
+	else if (strcmp(topic, "install") == 0) help_install(prg);
+	else if (strcmp(topic, "linstall") == 0) help_linstall(prg);
+	else if (strcmp(topic, "uninstall") == 0) help_uninstall(prg);
+	else {
+		printf("No such help topic: %s\n", topic);
+		return 1;
+	}
+	return 0;
+}
+
+
+
+/*********************** IMPLEMENTATION: low level **************************/
+#ifdef PATH_MAX
+#	define MY_PATH_MAX PATH_MAX
+#else
+#	define MY_PATH_MAX 32768
+#endif
+
+typedef enum {
+	INSTALL,     /* install with cp */
+	LINSTALL,    /* install with symlinks */
+	UNINSTALL    /* remove installed files */
+} scc_mode_t;
+
+#define kill_flag  argv[n] = NULL
+
+#define load_flags(code) \
+	do { \
+		int n, flags = 1; \
+		for(n = 1; n < argc; n++) { \
+			char *arg = argv[n]; \
+			if ((*arg == '-') && (flags)) { \
+				if ((arg[1] == '-') && (arg[2] == '\0')) { \
+					kill_flag; \
+					flags = 0; \
+					continue; \
+				} \
+				while(*arg == '-') arg++; \
+				{ code; } \
+			} \
+		} \
+	} while(0) \
+
+#define load_args_minus(delta, code) \
+	do { \
+		int n; \
+		for(n = 1; n < argc-delta; n++) {\
+			char *arg = argv[n]; \
+			if (arg != NULL) \
+				{ code; } \
+		} \
+	} while(0);
+
+#define load_args(code) load_args_minus(0, code)\
+
+
+static int safe_isdir(const char *path)
+{
+	struct stat st;
+
+	if (stat(path, &st) != 0)
+		return 0;
+	
+	return S_ISDIR(st.st_mode);
+}
+
+static int safe_remove(const char *src, int need_existing_fd, int quiet)
+{
+	struct stat st;
+	int exists;
+
+	if (quiet)
+		return remove(src);
+
+	exists = stat(src, &st) == 0;
+	if ((need_existing_fd) && (!exists)) {
+		fprintf(stderr, "sccbox: Can't remove %s: no such file or directory\n", src);
+		return 1;
+	}
+	
+
+	if (exists && (remove(src) != 0)) {
+		perror("sccbox");
+		fprintf(stderr, "sccbox: Can't remove %s\n", src);
+		return 1;
+	}
+	return 0;
+}
+
+static char *my_basename(const char *path)
+{
+	const char *s = path + strlen(path);
+	for(s--; s >= path; s--) {
+		if ((*s == '/') || (*s == '\\'))
+			return (char *)s+1;
+	}
+	return (char *)path;
+}
+
+static int path_concat(char *out, size_t out_len, const char *dir, const char *file)
+{
+	char *bn = my_basename(file);
+	size_t dlen = strlen(dir), blen = strlen(bn);
+
+	if (dlen+blen+2 > out_len)
+		return 1;
+
+	memcpy(out, dir, dlen);
+	out[dlen] = '/'; dlen++;
+	memcpy(out+dlen, bn, blen+1);
+	return 0;
+}
+
+static int safe_copy(const char *src, const char *dst, int force, int quiet)
+{
+	char buff[16384], dst2[MY_PATH_MAX];
+	const char *dst_name = NULL;
+	FILE *fd, *fs;
+	struct stat st;
+	int err = 0;
+
+	if (stat(src, &st) != 0) {
+		if (!quiet)
+			fprintf(stderr, "sccbox: can't stat %s\n", src);
+		return 1;
+	}
+
+	fs = fopen(src, "rb");
+	if (fs == NULL) {
+		if (!quiet)
+			fprintf(stderr, "sccbox: can't copy %s to %s: can not open source for write\n", src, dst2);
+		return 1;
+	}
+
+	if (force)
+		remove(dst);
+
+	fd = fopen(dst, "wb");
+
+	if (fd == NULL) {
+		/* no luck opening the dest file, maybe dst is a directory, try to create a file under it */
+		if (path_concat(dst2, sizeof(dst2), dst, src) != 0) {
+			if (!quiet)
+				fprintf(stderr, "sccbox: can't copy %s to %s: resulting path is too long\n", src, dst);
+			fclose(fs);
+			return 1;
+		}
+
+
+		fd = fopen(dst2, "wb");
+		if ((fd == NULL) && (force)) {
+			remove(dst2);
+			fd = fopen(dst2, "wb");
+			if (fd == NULL) {
+				/* dest was not a directory or couldn't host our new file; if force, try to
+				   overwrite whatever dst was */
+				remove(dst);
+				fd = fopen(dst, "wb");
+				if (fd == NULL) {
+					if (!quiet)
+						fprintf(stderr, "sccbox: can't copy %s to %s: destination can not be overwritten\n", src, dst2);
+					fclose(fs);
+					return 1;
+				}
+				dst_name = dst;
+			}
+		}
+		if (fd == NULL) {
+			if (!quiet)
+				fprintf(stderr, "sccbox: can't copy %s to %s: can not open destination for write\n", src, dst2);
+			fclose(fs);
+			return 1;
+		}
+		if (dst_name == NULL)
+			dst_name = dst2;
+	}
+	else
+		dst_name = dst;
+
+	/* manual copy - the only portable way */
+	for(;;) {
+		size_t len = fread(buff, 1, sizeof(buff), fs);
+		if (len == 0)
+			break;
+		if (fwrite(buff, 1, len, fd) != len) {
+			if (!quiet) {
+				perror("sccbox");
+				fprintf(stderr, "sccbox: can't copy %s to %s\n", src, dst_name);
+			}
+			err = 1;
+			if (!force)
+				break;
+		}
+	}
+
+	chmod(dst_name, st.st_mode); /* this may fail on windows or on strange FS, don't check the return value */
+
+	fclose(fs);
+	fclose(fd);
+	return err;
+}
+
+static const char *safe_get_pwd(int quiet)
+{
+	static char pwd_buff[MY_PATH_MAX];
+	static int valid = 0;
+	if (!valid) {
+		FILE *f;
+		char *end;
+		f = popen("pwd", "r");
+
+		if (f == NULL) {
+			if (!quiet)
+				perror("sccbox: running pwd");
+			return NULL;
+		}
+		if (fgets(pwd_buff, sizeof(pwd_buff), f) == NULL) {
+			if (!quiet)
+				perror("sccbox: reading pwd's output");
+			pclose(f);
+			return NULL;
+		}
+		pclose(f);
+		end = pwd_buff + strlen(pwd_buff) - 1;
+		while((end >= pwd_buff) && ((*end == '/') || (*end == '\n')  || (*end == '\r'))) {
+			*end = '\0';
+			end--;
+		}
+		if (*pwd_buff != '/') {
+			if (!quiet)
+				fprintf(stderr, "sccbox: invalid pwd: '%s'\n", pwd_buff);
+			return NULL;
+		}
+		valid = 1;
+	}
+	return pwd_buff;
+}
+
+/* create a symlink - needs to work only on UNIX but needs to compile on win32,
+   so use system("ln -s") and avoid link-related syscalls */
+static int safe_link(const char *src, const char *dst, int absolute, int force, int quiet)
+{
+	char cmd[MY_PATH_MAX*2+16], full_src_tmp[MY_PATH_MAX];
+	const char *full_src, *supp;
+
+	if ((absolute) && (*src != '/')) {
+		/* fix up relative source paths */
+		const char *pwd = safe_get_pwd(quiet);
+		if (pwd == NULL) {
+			if (!quiet)
+				fprintf(stderr, "sccbox: can't figure current working directory for relative symlink %s to %s\n", src, dst);
+			return 1;
+		}
+		if (path_concat(full_src_tmp, sizeof(full_src_tmp), pwd, src) != 0) {
+			if (!quiet)
+				fprintf(stderr, "sccbox: can't copy %s to %s: resulting path is too long\n", src, dst);
+			return 1;
+		}
+		full_src = full_src_tmp;
+	}
+	else
+		full_src = src;
+
+	if (force)
+		remove(dst);
+
+	supp = quiet ? " 2>/dev/null" : "";
+
+	sprintf(cmd, "ln -s \"%s\" \"%s\"%s", full_src, dst, supp);
+	return system(cmd);
+}
+
+static int safe_mkdir_p(const char *path)
+{
+	char *curr, *next, *s;
+	int res = 1, len = strlen(path);
+	char *p = malloc(len+1);
+	memcpy(p, path, len+1);
+	struct stat st;
+
+	/* do not create existing directories */
+	if (safe_isdir(path))
+			return 0;
+
+	curr = p;
+	if ((isalpha(p[0]) && (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))) {
+		/* windows special case: c:\ */
+		curr += 3;
+	}
+
+	/* remove trailing path separators so we don't create empty dirs at the end */
+	s = p+len-1;
+	while((s >= p) && ((*s == '/') || (*s == '\\'))) {
+		*s = '\0';
+		s--;
+	}
+
+	for(next = curr; next != NULL; curr = next) {
+		char old;
+		next = strpbrk(curr, "/\\");
+		if (next != NULL) {
+			old = *next;
+			*next = '\0';
+		}
+		res = mkdir(p, 0755);
+		if (next != NULL) {
+			*next = old;
+			next++;
+		}
+	}
+
+	if (res != 0) {
+		perror("sccbox");
+		fprintf(stderr, "sccbox: failed to make directory with parents: %s\n", path);
+	}
+
+	free(p);
+	return res; /* return the result of the last mkdir only, previous failures probably meant existing parents */
+}
+
+/*********************** IMPLEMENTATION: high level **************************/
+int cmd_rm(int argc, char *argv[])
+{
+	int err = 0, quiet = 0, need_existing_fd = 1;
+	load_flags(
+		switch(*arg) {
+			case 'f': need_existing_fd = 0; kill_flag; break; /* nop: can't do more than remove() */
+			case 'q': quiet = 1; kill_flag; break;
+		}
+	);
+	load_args(
+		err |= safe_remove(arg, need_existing_fd, quiet);
+	);
+	
+
+	if (quiet)
+		return 0;
+
+	return err;
+}
+
+
+int cmd_install(int argc, char *argv[], scc_mode_t mode, int absolute)
+{
+	int force = 0, err = 0, quiet = 0, dst_is_dir;
+	const char *last;
+
+	load_flags(
+		switch(*arg) {
+			case 'c': /* --copy */
+			case 'i': /* --install */
+				mode = INSTALL;
+				kill_flag;
+				break;
+			case 'l': /* --ln or --linstall */
+				mode = LINSTALL;
+				kill_flag;
+				break;
+			case 'r': /* --rm */
+			case 'u': /* --uninstall */
+				mode = UNINSTALL;
+				kill_flag;
+				break;
+			case 'f': /* --force */
+				force = 1;
+				kill_flag;
+				break;
+			case 'q': /* --quiet */
+				quiet = 1;
+				kill_flag;
+				break;
+			case 'p': /* --preserve */
+				absolute = 0;
+				kill_flag;
+				break;
+			case 'a': /* --absolute */
+				absolute = 1;
+				kill_flag;
+				break;
+		}
+	);
+
+	last = argv[argc-1];
+	dst_is_dir = safe_isdir(last);
+
+	load_args_minus(1,
+		switch(mode) {
+			case INSTALL:   err |= safe_copy(arg, last, force, quiet); break;
+			case LINSTALL:  err |= safe_link(arg, last, absolute, force, quiet); break;
+			case UNINSTALL:
+				if (dst_is_dir) {
+					char path[MY_PATH_MAX];
+					if (path_concat(path, sizeof(path), last, arg) != 0) {
+						if (!quiet) {
+							fprintf(stderr, "sccbox: can't remove %s/%s: resulting path is too long\n", last, arg);
+							err |= 1;
+						}
+					}
+					else
+						err |= safe_remove(path, !force, quiet);
+				}
+				break;
+		}
+		if ((mode == UNINSTALL) && (!dst_is_dir))
+			err |= safe_remove(last, !force, quiet);
+	);
+
+	if (quiet)
+		return 0;
+	return err;
+}
+
+int cmd_mkdir(int argc, char *argv[])
+{
+	int parents = 0, err = 0, quiet = 0;
+
+	load_flags(
+		switch(*arg) {
+			case 'q': /* --quiet */
+				quiet = 1; kill_flag; break;
+			case 'f':
+				kill_flag; break;
+			case 'r': /* --rm */
+			case 'u': /* --uninstall */
+				return 0; /* don't do anything for uninstall */
+			case 'p': parents = 1; kill_flag; break;
+		}
+	);
+
+	if (!parents) {
+		load_args(
+			if ((mkdir(arg, 0755) != 0) && (!quiet)) {
+				perror("sccbox");
+				fprintf(stderr, "sccbox: failed to make directory %s\n", arg);
+				err |= 1;
+			}
+		)
+	}
+	else {
+		load_args(
+			err |= safe_mkdir_p(arg);
+		);
+	}
+
+	if (quiet)
+		return 0;
+
+	return err;
+}
+
+int main(int argc, char *argv[])
+{
+	const char *prg = argv[0];
+	if (argc > 1) {
+		if (strstr(argv[0], "sccbox") != NULL) {
+			argv++;
+			argc--;
+		}
+
+		if (strcmp(argv[0], "--help") == 0) return help(prg, argv[1]);
+		if (strcmp(argv[0], "help") == 0)   return help(prg, argv[1]);
+		if (strcmp(argv[0], "-h") == 0)     return help(prg, argv[1]);
+
+		if (strcmp(argv[0], "rm") == 0)        return cmd_rm(argc, argv);
+		if (strcmp(argv[0], "install") == 0)   return cmd_install(argc, argv, INSTALL, 1);
+		if (strcmp(argv[0], "linstall") == 0)  return cmd_install(argc, argv, LINSTALL, 1);
+		if (strcmp(argv[0], "uninstall") == 0) return cmd_install(argc, argv, UNINSTALL, 1);
+		if (strcmp(argv[0], "mkdir") == 0)     return cmd_mkdir(argc, argv);
+		if (strcmp(argv[0], "ln") == 0)        return cmd_install(argc, argv, LINSTALL, 0);
+		fprintf(stderr, "sccbox: unknown command %s\n", argv[0]);
+	}
+	else
+		fprintf(stderr, "sccbox: need arguments\n");
+	fprintf(stderr, "sccbox: try --help\n");
+	return 1;
+}
diff --git a/scconfig/template/debug.tmpasm b/scconfig/template/debug.tmpasm
index 9da2385..61839a3 100644
--- a/scconfig/template/debug.tmpasm
+++ b/scconfig/template/debug.tmpasm
@@ -1,7 +1,7 @@
 # append debug or production flags to CFLAGS, depending on the global debug flag
 
 if /local/pcb/debug then
-	append /local/pcb/CFLAGS [@ -g -O0 @cc/argstd/Wall@ @]
+	append /local/pcb/CFLAGS [@ -g -O0 @?cc/argstd/Wall@ @]
 else
 	if /local/pcb/symbols then
 		append /local/pcb/CFLAGS [@ -g @]
diff --git a/src/Makefile.dep b/src/Makefile.dep
index d050268..6a46ba2 100644
--- a/src/Makefile.dep
+++ b/src/Makefile.dep
@@ -12,10 +12,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h layer.h layer_ui.h action_helper.h hid_actions.h plugins.h \
- conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h layer.h layer_ui.h action_helper.h hid_actions.h \
+ plugins.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
@@ -33,10 +33,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h hid.h rtree.h undo.h move.h draw.h polygon.h rtree.h plugins.h \
- obj_all.h box.h hid_actions.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h hid.h rtree.h undo.h move.h draw.h polygon.h \
+ rtree.h plugins.h obj_all.h box.h hid_actions.h dolists.h
 ../src_plugins/autoplace/action.o: ../src_plugins/autoplace/action.c \
  ../config.h ../src_plugins/autoplace/autoplace.h global_typedefs.h \
  pcb_bool.h unit.h plugins.h hid_actions.h hid.h error.h drc.h \
@@ -48,8 +48,9 @@
  obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
  obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
  ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h compat_nls.h board.h \
- const.h macro.h vtroutestyle.h ../src_3rd/genvector/genvector_impl.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ compat_nls.h board.h const.h macro.h vtroutestyle.h \
+ ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h library.h rats_patch.h board.h \
  font.h box.h math_helper.h move.h misc_util.h event.h dolists.h
 ../src_plugins/autoplace/autoplace.o: \
@@ -65,8 +66,8 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h ../src_plugins/autoplace/autoplace.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h ../src_plugins/autoplace/autoplace.h \
  global_typedefs.h box.h compat_misc.h compat_nls.h data.h crosshair.h \
  vtonpoint.h hid.h error.h drc.h buffer.h draw.h error.h layer.h \
  intersect.h rtree.h macro.h move.h rats.h netlist.h route_style.h \
@@ -84,9 +85,9 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h action_helper.h plugins.h hid_actions.h hid.h error.h \
- drc.h event.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h action_helper.h plugins.h hid_actions.h \
+ hid.h error.h drc.h event.h dolists.h
 ../src_plugins/autoroute/autoroute.o: \
  ../src_plugins/autoroute/autoroute.c ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -104,7 +105,7 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h macro.h \
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h macro.h \
  ../src_plugins/autoroute/autoroute.h board.h const.h macro.h \
  vtroutestyle.h library.h rats_patch.h board.h font.h box.h math_helper.h \
  move.h misc_util.h box.h draw.h error.h find.h heap.h rtree.h \
@@ -133,10 +134,11 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h rats.h netlist.h route_style.h polygon.h rtree.h \
- data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h hid.h \
- rtree.h undo.h plugins.h obj_all.h hid_actions.h compat_misc.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h rats.h netlist.h route_style.h \
+ polygon.h rtree.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h hid.h rtree.h undo.h plugins.h obj_all.h hid_actions.h \
+ compat_misc.h dolists.h
 ../src_plugins/dbus/dbus-pcbmain.o: ../src_plugins/dbus/dbus-pcbmain.c \
  ../config.h ../src_plugins/dbus/dbus-pcbmain.h hid.h error.h drc.h \
  unit.h global_typedefs.h pcb_bool.h attrib.h layer.h globalconst.h \
@@ -148,7 +150,7 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h
+ obj_rat.h layer_grp.h
 ../src_plugins/dbus/dbus.o: ../src_plugins/dbus/dbus.c \
  ../src_plugins/dbus/dbus-pcbmain.h ../src_plugins/dbus/dbus-introspect.h \
  board.h ../config.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
@@ -162,10 +164,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h plugins.h hid_actions.h event.h compat_misc.h hid.h \
- compat_lrealpath.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h plugins.h hid_actions.h event.h compat_misc.h \
+ hid.h compat_lrealpath.h dolists.h
 ../src_plugins/diag/diag.o: ../src_plugins/diag/diag.c ../config.h \
  board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
  vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
@@ -178,10 +180,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h layer.h ../src_plugins/diag/diag_conf.h action_helper.h \
- hid_actions.h plugins.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h layer.h ../src_plugins/diag/diag_conf.h \
+ action_helper.h hid_actions.h plugins.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -210,11 +212,11 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h hid.h rtree.h undo.h rats.h netlist.h route_style.h error.h \
- move.h draw.h plugins.h action_helper.h hid_actions.h compat_misc.h \
- dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h hid.h rtree.h undo.h rats.h netlist.h \
+ route_style.h error.h move.h draw.h plugins.h action_helper.h \
+ hid_actions.h compat_misc.h dolists.h
 ../src_plugins/distaligntext/distaligntext.o: \
  ../src_plugins/distaligntext/distaligntext.c ../config.h board.h const.h \
  macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -228,15 +230,16 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h hid.h rtree.h undo.h rats.h netlist.h route_style.h error.h \
- move.h draw.h plugins.h action_helper.h hid_actions.h conf_core.h conf.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h box.h compat_misc.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h hid.h rtree.h undo.h rats.h netlist.h \
+ route_style.h error.h move.h draw.h plugins.h action_helper.h \
+ hid_actions.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ box.h compat_misc.h dolists.h
 ../src_plugins/djopt/djopt.o: ../src_plugins/djopt/djopt.c ../config.h \
  conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -253,13 +256,30 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h remove.h move.h draw.h undo.h \
- flag_str.h find.h layer.h pcb-printf.h compat_misc.h plugins.h \
- hid_flags.h hid_actions.h ../src_plugins/djopt/djopt_conf.h conf.h \
- obj_line.h obj_pinvia.h event.h dolists.h \
- ../src_plugins/djopt/djopt_conf_fields.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h remove.h \
+ move.h draw.h undo.h flag_str.h find.h layer.h pcb-printf.h \
+ compat_misc.h plugins.h hid_flags.h hid_actions.h \
+ ../src_plugins/djopt/djopt_conf.h conf.h obj_line.h obj_pinvia.h event.h \
+ dolists.h ../src_plugins/djopt/djopt_conf_fields.h
+../src_plugins/draw_csect/draw_csect.o: \
+ ../src_plugins/draw_csect/draw_csect.c ../config.h board.h const.h \
+ macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h draw.h plugins.h stub_draw_csect.h compat_misc.h \
+ hid_actions.h obj_text_draw.h obj_line_draw.h dolists.h
 ../src_plugins/draw_fab/draw_fab.o: ../src_plugins/draw_fab/draw_fab.c \
  ../config.h board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
  vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
@@ -272,16 +292,17 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h build_run.h data.h crosshair.h vtonpoint.h hid.h \
- error.h drc.h buffer.h draw.h ../src_plugins/draw_fab/../report/drill.h \
- obj_all.h plugins.h stub_draw_fab.h \
- ../src_plugins/draw_fab/draw_fab_conf.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
- conf.h obj_text_draw.h ../src_plugins/draw_fab/draw_fab_conf_fields.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h build_run.h data.h crosshair.h \
+ vtonpoint.h hid.h error.h drc.h buffer.h draw.h \
+ ../src_plugins/draw_fab/../report/drill.h obj_all.h plugins.h \
+ stub_draw_fab.h ../src_plugins/draw_fab/draw_fab_conf.h conf.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h conf.h obj_text_draw.h \
+ ../src_plugins/draw_fab/draw_fab_conf_fields.h
 ../src_plugins/export_bboard/bboard.o: \
  ../src_plugins/export_bboard/bboard.c ../config.h math_helper.h board.h \
  const.h macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h \
@@ -295,11 +316,11 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h error.h buffer.h layer.h plugins.h compat_misc.h compat_fs.h \
- misc_util.h obj_all.h hid.h hid_attrib.h hid_nogui.h hid_draw_helpers.h \
- hid_init.h hid_helper.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h buffer.h layer.h layer_grp.h plugins.h \
+ compat_misc.h compat_fs.h misc_util.h obj_all.h hid.h hid_attrib.h \
+ hid_nogui.h hid_draw_helpers.h hid_init.h hid_helper.h
 ../src_plugins/export_bom/bom.o: ../src_plugins/export_bom/bom.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -317,10 +338,11 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h error.h pcb-printf.h plugins.h \
- compat_misc.h hid.h hid_nogui.h hid_attrib.h hid_helper.h hid_init.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h error.h \
+ pcb-printf.h plugins.h compat_misc.h hid.h hid_nogui.h hid_attrib.h \
+ hid_helper.h hid_init.h
 ../src_plugins/export_dsn/dsn.o: ../src_plugins/export_dsn/dsn.c \
  ../config.h board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
  vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
@@ -333,13 +355,13 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h error.h rats.h netlist.h route_style.h buffer.h change.h draw.h \
- undo.h pcb-printf.h ../src_3rd/genvector/gds_char.h polygon.h rtree.h \
- compat_misc.h layer.h hid.h hid_draw_helpers.h hid_nogui.h hid_actions.h \
- hid_init.h hid_attrib.h hid_helper.h plugins.h obj_line.h obj_pinvia.h \
- dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h rats.h netlist.h route_style.h buffer.h \
+ change.h draw.h undo.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ polygon.h rtree.h compat_misc.h layer.h hid.h hid_draw_helpers.h \
+ hid_nogui.h hid_actions.h hid_init.h hid_attrib.h hid_helper.h plugins.h \
+ obj_line.h obj_pinvia.h dolists.h
 ../src_plugins/export_dxf/dxf.o: ../src_plugins/export_dxf/dxf.c \
  ../config.h math_helper.h macro.h board.h const.h macro.h \
  global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -353,9 +375,9 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h error.h draw.h hid_draw_helpers.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h draw.h hid_draw_helpers.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h compat_misc.h layer.h hid_attrib.h \
  hid_flags.h hid_helper.h hid.h hid_init.h plugins.h obj_pinvia.h
 ../src_plugins/export_gcode/curve.o: ../src_plugins/export_gcode/curve.c \
@@ -386,11 +408,12 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h error.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h rats.h netlist.h route_style.h \
- hid_helper.h layer.h compat_misc.h hid.h hid_nogui.h hid_draw_helpers.h \
- ../src_plugins/export_gcode/gcode.h ../src_plugins/export_gcode/bitmap.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ error.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
+ rats.h netlist.h route_style.h hid_helper.h layer.h compat_misc.h hid.h \
+ hid_nogui.h hid_draw_helpers.h ../src_plugins/export_gcode/gcode.h \
+ ../src_plugins/export_gcode/bitmap.h \
  ../src_plugins/export_gcode/potracelib.h \
  ../src_plugins/export_gcode/curve.h \
  ../src_plugins/export_gcode/auxiliary.h \
@@ -416,9 +439,9 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h error.h draw.h layer.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h draw.h layer.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h plugins.h hid_helper.h compat_misc.h \
  hid.h hid_nogui.h hid_draw_helpers.h hid_init.h hid_attrib.h hid_flags.h \
  conf_core.h conf.h pcb-printf.h ../src_3rd/liblihata/lihata.h \
@@ -438,15 +461,16 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h rats.h netlist.h route_style.h error.h find.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h netlist.h conf_core.h conf.h \
- pcb-printf.h ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h obj_pinvia.h hid.h hid_nogui.h \
- hid_helper.h hid_attrib.h hid_init.h plugins.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h rats.h netlist.h route_style.h error.h find.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h netlist.h conf_core.h \
+ conf.h pcb-printf.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ obj_pinvia.h hid.h hid_nogui.h hid_helper.h hid_attrib.h hid_init.h \
+ plugins.h
 ../src_plugins/export_lpr/lpr.o: ../src_plugins/export_lpr/lpr.c \
  ../config.h data.h globalconst.h global_typedefs.h pcb_bool.h unit.h \
  layer.h attrib.h obj_all_list.h obj_arc_list.h obj_common.h \
@@ -458,8 +482,8 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- plugins.h compat_misc.h hid.h \
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h plugins.h compat_misc.h hid.h \
  ../src_plugins/export_lpr/../export_ps/ps.h hid_nogui.h hid_init.h \
  hid_attrib.h hid_actions.h
 ../src_plugins/export_nelma/nelma.o: ../src_plugins/export_nelma/nelma.c \
@@ -474,10 +498,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h error.h data.h crosshair.h vtonpoint.h hid.h error.h \
- drc.h buffer.h layer.h rats.h netlist.h route_style.h plugins.h \
- hid_helper.h hid.h hid_nogui.h hid_draw_helpers.h hid_init.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h error.h data.h crosshair.h vtonpoint.h \
+ hid.h error.h drc.h buffer.h layer.h rats.h netlist.h route_style.h \
+ plugins.h hid_helper.h hid.h hid_nogui.h hid_draw_helpers.h hid_init.h \
  hid_attrib.h hid_flags.h hid_color.h dolists.h
 ../src_plugins/export_openscad/scad.o: \
  ../src_plugins/export_openscad/scad.c ../config.h board.h const.h \
@@ -492,15 +516,16 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h math_helper.h data.h crosshair.h vtonpoint.h hid.h \
- error.h drc.h buffer.h error.h buffer.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
- layer.h plugins.h hid.h hid_draw_helpers.h hid_nogui.h hid_init.h \
- hid_attrib.h hid_helper.h ../src_plugins/export_openscad/scad.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h math_helper.h data.h crosshair.h \
+ vtonpoint.h hid.h error.h drc.h buffer.h error.h buffer.h conf_core.h \
+ conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h layer.h plugins.h hid.h \
+ hid_draw_helpers.h hid_nogui.h hid_init.h hid_attrib.h hid_helper.h \
+ ../src_plugins/export_openscad/scad.h
 ../src_plugins/export_openscad/scadcomp.o: \
  ../src_plugins/export_openscad/scadcomp.c ../config.h board.h const.h \
  macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -514,9 +539,9 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h error.h buffer.h misc_util.h hid.h hid_nogui.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h buffer.h misc_util.h hid.h hid_nogui.h \
  hid_draw_helpers.h hid_init.h ../src_plugins/export_openscad/scad.h
 ../src_plugins/export_openscad/scadproto.o: \
  ../src_plugins/export_openscad/scadproto.c ../config.h data.h \
@@ -530,9 +555,9 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- error.h buffer.h hid.h hid_nogui.h hid_draw_helpers.h hid_init.h \
- ../src_plugins/export_openscad/scad.h
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h error.h buffer.h hid.h hid_nogui.h hid_draw_helpers.h \
+ hid_init.h ../src_plugins/export_openscad/scad.h
 ../src_plugins/export_png/png.o: ../src_plugins/export_png/png.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -550,12 +575,12 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h error.h layer.h misc_util.h \
- compat_misc.h plugins.h hid.h hid_nogui.h hid_draw_helpers.h \
- ../src_plugins/export_png/png.h hid_init.h hid_attrib.h hid_color.h \
- hid_helper.h hid_flags.h dolists.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h error.h \
+ layer.h misc_util.h compat_misc.h plugins.h hid.h hid_nogui.h \
+ hid_draw_helpers.h ../src_plugins/export_png/png.h hid_init.h \
+ hid_attrib.h hid_color.h hid_helper.h hid_flags.h dolists.h
 ../src_plugins/export_ps/eps.o: ../src_plugins/export_ps/eps.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -573,11 +598,12 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h layer.h pcb-printf.h hid.h \
- hid_nogui.h hid_draw_helpers.h ../src_plugins/export_ps/ps.h hid_init.h \
- hid_attrib.h hid_helper.h hid_flags.h hid_color.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h layer.h \
+ pcb-printf.h hid.h hid_nogui.h hid_draw_helpers.h \
+ ../src_plugins/export_ps/ps.h hid_init.h hid_attrib.h hid_helper.h \
+ hid_flags.h hid_color.h
 ../src_plugins/export_ps/ps.o: ../src_plugins/export_ps/ps.c ../config.h \
  math_helper.h board.h const.h macro.h global_typedefs.h pcb_bool.h \
  unit.h vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
@@ -590,9 +616,9 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h layer.h error.h draw.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h layer.h error.h draw.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h plugins.h hid_helper.h hid.h hid_nogui.h \
  hid_draw_helpers.h ../src_plugins/export_ps/ps.h hid_init.h hid_attrib.h \
  hid_flags.h hid_actions.h conf_core.h conf.h pcb-printf.h \
@@ -618,11 +644,12 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h plugins.h pcb-printf.h \
- compat_misc.h plug_io.h hid.h hid_nogui.h hid_draw_helpers.h hid_init.h \
- hid_attrib.h hid_color.h hid_helper.h hid_flags.h dolists.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h plugins.h \
+ pcb-printf.h compat_misc.h plug_io.h hid.h hid_nogui.h \
+ hid_draw_helpers.h hid_init.h hid_attrib.h hid_color.h hid_helper.h \
+ hid_flags.h dolists.h
 ../src_plugins/export_svg/svg.o: ../src_plugins/export_svg/svg.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -640,11 +667,12 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h error.h layer.h misc_util.h \
- compat_misc.h plugins.h hid.h hid_nogui.h hid_draw_helpers.h hid_init.h \
- hid_attrib.h hid_color.h hid_helper.h hid_flags.h dolists.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h error.h \
+ layer.h misc_util.h compat_misc.h plugins.h hid.h hid_nogui.h \
+ hid_draw_helpers.h hid_init.h hid_attrib.h hid_color.h hid_helper.h \
+ hid_flags.h dolists.h
 ../src_plugins/export_test/export_test.o: \
  ../src_plugins/export_test/export_test.c ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -662,10 +690,11 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h error.h pcb-printf.h plugins.h \
- hid.h hid_nogui.h hid_attrib.h hid_helper.h hid_init.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h error.h \
+ pcb-printf.h plugins.h hid.h hid_nogui.h hid_attrib.h hid_helper.h \
+ hid_init.h
 ../src_plugins/export_xy/xy.o: ../src_plugins/export_xy/xy.c ../config.h \
  conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -682,11 +711,11 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h error.h pcb-printf.h plugins.h \
- compat_misc.h obj_pinvia.h hid.h hid_nogui.h hid_attrib.h hid_helper.h \
- hid_init.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h error.h \
+ pcb-printf.h plugins.h compat_misc.h obj_pinvia.h hid.h hid_nogui.h \
+ hid_attrib.h hid_helper.h hid_init.h
 ../src_plugins/fontmode/fontmode.o: ../src_plugins/fontmode/fontmode.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -704,11 +733,11 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h draw.h flag.h layer.h move.h \
- remove.h rtree.h flag_str.h undo.h pcb-printf.h plugins.h hid_actions.h \
- compat_misc.h event.h dolists.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h \
+ flag.h layer.h move.h remove.h rtree.h flag_str.h undo.h pcb-printf.h \
+ plugins.h hid_actions.h compat_misc.h event.h dolists.h
 ../src_plugins/fp_fs/fp_fs.o: ../src_plugins/fp_fs/fp_fs.c ../config.h \
  data.h globalconst.h global_typedefs.h pcb_bool.h unit.h layer.h \
  attrib.h obj_all_list.h obj_arc_list.h obj_common.h \
@@ -720,10 +749,10 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- paths.h ../src_3rd/genvector/gds_char.h plugins.h plug_footprint.h \
- vtlibrary.h compat_fs.h compat_misc.h error.h conf.h pcb-printf.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h paths.h ../src_3rd/genvector/gds_char.h plugins.h \
+ plug_footprint.h vtlibrary.h compat_fs.h compat_misc.h error.h conf.h \
+ pcb-printf.h ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
  ../src_3rd/genvector/vtp0.h list_conf.h conf.h conf_core.h compat_nls.h \
@@ -756,106 +785,48 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h hid.h error.h drc.h data.h crosshair.h vtonpoint.h \
- hid.h buffer.h layer.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- plugins.h compat_misc.h event.h hid_draw_helpers.h hid_nogui.h \
- hid_actions.h hid_init.h dolists.h
-../src_plugins/hid_gtk/ghid-cell-renderer-visibility.o: \
- ../src_plugins/hid_gtk/ghid-cell-renderer-visibility.c ../config.h \
- ../src_plugins/hid_gtk/gtkhid.h conf_hid.h conf.h global_typedefs.h \
- pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h hid.h error.h drc.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h layer.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h plugins.h compat_misc.h event.h \
+ hid_draw_helpers.h hid_nogui.h hid_actions.h hid_init.h dolists.h
+../src_plugins/hid_gtk/colors.o: ../src_plugins/hid_gtk/colors.c \
+ ../src_plugins/hid_gtk/gui.h ../config.h board.h const.h macro.h \
+ global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
  ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h error.h ../src_plugins/hid_gtk/gui.h \
- board.h const.h macro.h vtroutestyle.h attrib.h layer.h globalconst.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
  obj_all_list.h obj_arc_list.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
- obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
- ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- drc.h hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h \
- hid_cfg.h data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h compat_nls.h \
- ../src_plugins/hid_gtk/ghid-cell-renderer-visibility.h
-../src_plugins/hid_gtk/ghid-coord-entry.o: \
- ../src_plugins/hid_gtk/ghid-coord-entry.c ../config.h \
- ../src_plugins/hid_gtk/gtkhid.h conf_hid.h conf.h global_typedefs.h \
- pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h error.h ../src_plugins/hid_gtk/gui.h \
- board.h const.h macro.h vtroutestyle.h attrib.h layer.h globalconst.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
- obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
- ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- drc.h hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h \
- hid_cfg.h data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h pcb-printf.h compat_nls.h
-../src_plugins/hid_gtk/ghid-layer-selector.o: \
- ../src_plugins/hid_gtk/ghid-layer-selector.c ../config.h \
- ../src_plugins/hid_gtk/gtkhid.h conf_hid.h conf.h global_typedefs.h \
- pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h hid.h error.h drc.h hid_cfg.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h error.h ../src_plugins/hid_gtk/gui.h \
- board.h const.h macro.h vtroutestyle.h attrib.h layer.h globalconst.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
- obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
- ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- drc.h hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h \
- hid_cfg.h data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h pcb-printf.h \
- ../src_plugins/hid_gtk/ghid-cell-renderer-visibility.h
+ ../src_3rd/liblihata/genht/ht.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h conf_core.h \
+ conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ event.h compat_misc.h ../src_plugins/hid_gtk/colors.h \
+ ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h
 ../src_plugins/hid_gtk/ghid-main-menu.o: \
  ../src_plugins/hid_gtk/ghid-main-menu.c ../src_3rd/liblihata/tree.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../config.h ../src_plugins/hid_gtk/gtkhid.h conf_hid.h conf.h \
+ ../config.h ../src_plugins/hid_gtk/gtkhid-main.h conf_hid.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
@@ -868,109 +839,21 @@
  obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- drc.h hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h \
- hid_cfg.h data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h pcb-printf.h misc_util.h \
- error.h ../src_plugins/hid_gtk/gschem_accel_label.h
-../src_plugins/hid_gtk/ghid-propedit.o: \
- ../src_plugins/hid_gtk/ghid-propedit.c ../config.h \
- ../src_plugins/hid_gtk/gui.h board.h const.h macro.h global_typedefs.h \
- pcb_bool.h unit.h vtroutestyle.h attrib.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
- obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
- obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h hid.h error.h drc.h hid_cfg.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h hid_cfg_input.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ library.h rats_patch.h board.h font.h box.h math_helper.h move.h \
+ misc_util.h hid.h drc.h hid_cfg.h hid_cfg_input.h \
  ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
- vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-coord-entry.h \
- unit.h ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/genvector/vtp0.h list_conf.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h compat_nls.h polygon.h \
- rtree.h obj_all.h
-../src_plugins/hid_gtk/ghid-route-style-selector.o: \
- ../src_plugins/hid_gtk/ghid-route-style-selector.c ../config.h \
- conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h globalconst.h \
- ../src_plugins/hid_gtk/gtkhid.h conf_hid.h error.h \
- ../src_plugins/hid_gtk/gui.h board.h const.h macro.h vtroutestyle.h \
- attrib.h layer.h obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
- obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
- ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- drc.h hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h \
- hid_cfg.h data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h pcb-printf.h compat_nls.h
-../src_plugins/hid_gtk/ghid-search.o: \
- ../src_plugins/hid_gtk/ghid-search.c ../src_3rd/genlist/gendlist.h \
- ../config.h ../src_plugins/hid_gtk/gui.h board.h const.h macro.h \
- global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h flag.h obj_arc.h \
- ../src_3rd/genlist/gentdlist_impl.h ../src_3rd/genlist/gendlist.h \
- ../src_3rd/genlist/gentdlist_undef.h obj_elem_list.h obj_elem.h \
- obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
- obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- error.h drc.h hid_cfg.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h \
- crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/genvector/vtp0.h list_conf.h event.h compat_misc.h \
+ vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h conf_core.h \
+ event.h compat_misc.h ../src_plugins/hid_gtk/colors.h \
  ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
- ../src_plugins/hid_gtk/ghid-search.h ../src_plugins/hid_gtk/win_place.h \
- hid_actions.h compat_nls.h misc_util.h \
- ../src_plugins/hid_gtk/ghid-search-tab.h
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h pcb-printf.h misc_util.h \
+ error.h ../src_plugins/hid_gtk/gschem_accel_label.h
 ../src_plugins/hid_gtk/gschem_accel_label.o: \
  ../src_plugins/hid_gtk/gschem_accel_label.c ../config.h \
  ../src_plugins/hid_gtk/gschem_accel_label.h compat_nls.h
@@ -1003,19 +886,22 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h clip.h layer.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h clip.h layer.h \
  ../src_plugins/hid_gtk/gui.h board.h const.h macro.h vtroutestyle.h \
  library.h rats_patch.h board.h font.h box.h math_helper.h move.h \
  misc_util.h hid.h hid_cfg.h hid_cfg_input.h \
  ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
  ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h hid_draw_helpers.h \
- hid_attrib.h hid_helper.h hid_color.h
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
+ ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h hid_draw_helpers.h hid_attrib.h \
+ hid_helper.h hid_color.h
 ../src_plugins/hid_gtk/gtkhid-main.o: \
  ../src_plugins/hid_gtk/gtkhid-main.c ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -1033,22 +919,43 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h error.h draw.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h error.h draw.h \
  ../src_plugins/hid_gtk/gui.h board.h const.h macro.h vtroutestyle.h \
  library.h rats_patch.h board.h font.h box.h math_helper.h move.h \
  misc_util.h hid.h hid_cfg.h hid_cfg_input.h \
  ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
  ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h hid_nogui.h \
- hid_draw_helpers.h pcb-printf.h plugins.h hid_attrib.h hid_init.h \
- hid_flags.h hid_actions.h plug_footprint.h vtlibrary.h plug_io.h \
- misc_util.h layer.h ../src_plugins/hid_gtk/ghid-search.h compat_nls.h \
- layer_vis.h ../src_plugins/hid_gtk/gtkhid.h conf_hid.h dolists.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
+ ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h hid_nogui.h hid_draw_helpers.h \
+ pcb-printf.h plugins.h hid_attrib.h hid_init.h hid_flags.h hid_actions.h \
+ plug_footprint.h vtlibrary.h plug_io.h misc_util.h layer.h compat_nls.h \
+ layer_vis.h ../src_plugins/hid_gtk/gtkhid-main.h conf_hid.h \
+ ../src_plugins/lib_gtk_common/act_fileio.h \
+ ../src_plugins/lib_gtk_common/act_print.h \
+ ../src_plugins/lib_gtk_common/bu_status_line.h \
+ ../src_plugins/lib_gtk_common/util_block_hook.h \
+ ../src_plugins/lib_gtk_common/util_timer.h \
+ ../src_plugins/lib_gtk_common/util_watch.h \
+ ../src_plugins/lib_gtk_common/dlg_about.h \
+ ../src_plugins/lib_gtk_common/dlg_attribute.h \
+ ../src_plugins/lib_gtk_common/dlg_confirm.h \
+ ../src_plugins/lib_gtk_common/dlg_export.h \
+ ../src_plugins/lib_gtk_common/dlg_file_chooser.h \
+ ../src_plugins/lib_gtk_common/util_str.h \
+ ../src_plugins/lib_gtk_common/dlg_input.h \
+ ../src_plugins/lib_gtk_common/dlg_message.h \
+ ../src_plugins/lib_gtk_common/dlg_print.h \
+ ../src_plugins/lib_gtk_common/dlg_progress.h \
+ ../src_plugins/lib_gtk_common/dlg_report.h \
+ ../src_plugins/lib_gtk_common/dlg_pinout.h obj_elem.h \
+ ../src_plugins/lib_gtk_common/dlg_search.h dolists.h \
  ../src_plugins/hid_gtk/hid_gtk_conf_fields.h
 ../src_plugins/hid_gtk/gui-command-window.o: \
  ../src_plugins/hid_gtk/gui-command-window.c ../config.h conf_core.h \
@@ -1067,18 +974,23 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid.h error.h drc.h \
- hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h crosshair.h hid_actions.h \
- compat_nls.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
+ error.h drc.h hid_cfg.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
+ ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h crosshair.h hid_actions.h \
+ compat_nls.h ../src_plugins/lib_gtk_common/bu_text_view.h \
+ ../src_plugins/lib_gtk_common/bu_status_line.h \
+ ../src_plugins/lib_gtk_common/util_str.h
 ../src_plugins/hid_gtk/gui-config.o: ../src_plugins/hid_gtk/gui-config.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -1096,79 +1008,36 @@
  obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- error.h drc.h hid_cfg.h hid_cfg_input.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ library.h rats_patch.h board.h font.h box.h math_helper.h move.h \
+ misc_util.h hid.h error.h drc.h hid_cfg.h hid_cfg_input.h \
  ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
- vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-coord-entry.h \
- unit.h ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
+ vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
  ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
- ../src_plugins/hid_gtk/win_place.h ../src_plugins/hid_gtk/gtkhid.h \
- conf_hid.h action_helper.h change.h plug_io.h error.h draw.h \
- pcb-printf.h hid_attrib.h misc_util.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/hid_gtk/gtkhid-main.h conf_hid.h action_helper.h change.h \
+ plug_io.h error.h draw.h pcb-printf.h hid_attrib.h misc_util.h \
  ../src_plugins/hid_gtk/gtk_conf_list.h paths.h plug_footprint.h \
- vtlibrary.h compat_nls.h fptr_cast.h ../src_3rd/liblihata/tree.h
-../src_plugins/hid_gtk/gui-dialog-print.o: \
- ../src_plugins/hid_gtk/gui-dialog-print.c ../config.h conf_core.h conf.h \
- global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h globalconst.h ../src_plugins/hid_gtk/gui.h \
- board.h const.h macro.h vtroutestyle.h attrib.h layer.h obj_all_list.h \
- obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
- ../src_3rd/genlist/gendlist.h flag.h obj_arc.h obj_elem_list.h \
- obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
- obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid.h error.h drc.h \
- hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h pcb-printf.h hid_attrib.h \
- hid_init.h misc_util.h compat_nls.h
-../src_plugins/hid_gtk/gui-dialog.o: ../src_plugins/hid_gtk/gui-dialog.c \
- ../config.h compat_misc.h compat_nls.h build_run.h plug_io.h library.h \
- global_typedefs.h pcb_bool.h unit.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h data.h globalconst.h layer.h attrib.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
- obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
- ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h ../src_plugins/hid_gtk/gui.h \
- board.h const.h macro.h vtroutestyle.h rats_patch.h board.h font.h box.h \
- math_helper.h move.h misc_util.h hid.h hid_cfg.h hid_cfg_input.h \
- ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h event.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h
+ vtlibrary.h stub_draw_csect.h compat_nls.h fptr_cast.h \
+ ../src_3rd/liblihata/tree.h ../src_plugins/lib_gtk_common/util_str.h \
+ ../src_plugins/lib_gtk_common/wt_preview.h obj_elem.h layer.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h \
+ ../src_plugins/lib_gtk_common/bu_box.h \
+ ../src_plugins/lib_gtk_common/bu_entry.h \
+ ../src_plugins/lib_gtk_common/wt_coord_entry.h \
+ ../src_plugins/lib_gtk_common/bu_notebook.h \
+ ../src_plugins/lib_gtk_common/bu_text_view.h \
+ ../src_plugins/lib_gtk_common/bu_check_button.h \
+ ../src_plugins/lib_gtk_common/bu_status_line.h \
+ ../src_plugins/lib_gtk_common/win_place.h \
+ ../src_plugins/lib_gtk_common/bu_spin_button.h
 ../src_plugins/hid_gtk/gui-drc-window.o: \
  ../src_plugins/hid_gtk/gui-drc-window.c ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -1186,53 +1055,26 @@
  obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h misc_util.h draw.h \
- hid.h error.h drc.h layer.h pcb-printf.h undo.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ misc_util.h draw.h hid.h error.h drc.h layer.h pcb-printf.h undo.h \
  ../src_plugins/hid_gtk/gui.h board.h const.h macro.h rats_patch.h \
  board.h font.h box.h math_helper.h move.h hid.h hid_cfg.h \
  hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h \
- crosshair.h vtonpoint.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
+ crosshair.h vtonpoint.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
  ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
- ../src_plugins/hid_gtk/win_place.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
  ../src_plugins/hid_gtk/gui-drc-window.h hid_actions.h compat_nls.h \
  obj_all.h obj_pinvia_draw.h obj_pad_draw.h obj_rat_draw.h \
- obj_line_draw.h obj_arc_draw.h obj_poly_draw.h layer_vis.h
-../src_plugins/hid_gtk/gui-keyref-window.o: \
- ../src_plugins/hid_gtk/gui-keyref-window.c ../config.h \
- ../src_plugins/hid_gtk/gui.h board.h const.h macro.h global_typedefs.h \
- pcb_bool.h unit.h vtroutestyle.h attrib.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
- obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
- obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h hid.h error.h drc.h hid_cfg.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h hid_cfg_input.h \
- ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
- vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-coord-entry.h \
- unit.h ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/genvector/vtp0.h list_conf.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
- ../src_plugins/hid_gtk/win_place.h compat_nls.h
+ obj_line_draw.h obj_arc_draw.h obj_poly_draw.h layer_vis.h \
+ ../src_plugins/lib_gtk_common/util_str.h \
+ ../src_plugins/lib_gtk_common/win_place.h
 ../src_plugins/hid_gtk/gui-library-window.o: \
  ../src_plugins/hid_gtk/gui-library-window.c ../config.h conf_core.h \
  conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -1250,19 +1092,25 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid.h error.h drc.h \
- hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
+ error.h drc.h hid_cfg.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
  ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
- ../src_plugins/hid_gtk/win_place.h buffer.h plug_footprint.h vtlibrary.h \
- compat_nls.h ../src_plugins/hid_gtk/gui-library-window.h
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h buffer.h plug_footprint.h \
+ vtlibrary.h compat_nls.h ../src_plugins/lib_gtk_common/bu_box.h \
+ ../src_plugins/lib_gtk_common/wt_preview.h obj_elem.h layer.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h \
+ ../src_plugins/lib_gtk_common/win_place.h \
+ ../src_plugins/hid_gtk/gui-library-window.h
 ../src_plugins/hid_gtk/gui-log-window.o: \
  ../src_plugins/hid_gtk/gui-log-window.c ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -1280,49 +1128,23 @@
  obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- drc.h hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h \
- hid_cfg.h data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
- ../src_plugins/hid_gtk/win_place.h pcb-printf.h hid_actions.h \
- compat_nls.h
-../src_plugins/hid_gtk/gui-misc.o: ../src_plugins/hid_gtk/gui-misc.c \
- ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h globalconst.h math_helper.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h attrib.h layer.h obj_all_list.h \
- obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
- ../src_3rd/genlist/gendlist.h flag.h obj_arc.h obj_elem_list.h \
- obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
- obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h data.h crosshair.h buffer.h \
- action_helper.h pcb-printf.h misc_util.h compat_nls.h \
- ../src_plugins/hid_gtk/gui.h board.h const.h macro.h vtroutestyle.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
  library.h rats_patch.h board.h font.h box.h math_helper.h move.h \
- misc_util.h hid.h hid_cfg.h hid_cfg_input.h \
- ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h
+ misc_util.h hid.h drc.h hid_cfg.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
+ ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h pcb-printf.h hid_actions.h \
+ compat_nls.h ../src_plugins/hid_gtk/gtkhid-main.h \
+ ../src_plugins/lib_gtk_common/win_place.h \
+ ../src_plugins/lib_gtk_common/bu_text_view.h
 ../src_plugins/hid_gtk/gui-netlist-window.o: \
  ../src_plugins/hid_gtk/gui-netlist-window.c ../config.h conf_core.h \
  conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -1333,27 +1155,34 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  ../src_3rd/genvector/vtp0.h list_conf.h \
  ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h globalconst.h \
- ../src_plugins/hid_gtk/win_place.h ../src_plugins/hid_gtk/gui.h board.h \
- const.h macro.h vtroutestyle.h attrib.h layer.h obj_all_list.h \
- obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
- ../src_3rd/genlist/gendlist.h flag.h obj_arc.h obj_elem_list.h \
- obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
- obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid.h error.h drc.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h data.h layer.h attrib.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h draw.h error.h \
+ find.h rats.h netlist.h library.h route_style.h vtroutestyle.h remove.h \
+ search.h rats.h misc_util.h select.h operation.h undo.h hid_actions.h \
+ compat_nls.h obj_all.h ../src_plugins/hid_gtk/gui.h board.h const.h \
+ macro.h rats_patch.h board.h font.h box.h math_helper.h move.h hid.h \
  hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
  ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h draw.h error.h find.h \
- rats.h netlist.h route_style.h remove.h search.h rats.h select.h \
- operation.h undo.h hid_actions.h compat_nls.h obj_all.h
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
+ ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/util_str.h \
+ ../src_plugins/lib_gtk_common/win_place.h \
+ ../src_plugins/lib_gtk_common/bu_text_view.h \
+ ../src_plugins/lib_gtk_common/bu_box.h \
+ ../src_plugins/lib_gtk_common/bu_check_button.h
 ../src_plugins/hid_gtk/gui-output-events.o: \
  ../src_plugins/hid_gtk/gui-output-events.c ../config.h conf_core.h \
  conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -1371,52 +1200,29 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid.h error.h drc.h \
- hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
+ error.h drc.h hid_cfg.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
  ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
- ../src_plugins/hid_gtk/gtkhid.h conf_hid.h action_helper.h crosshair.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h action_helper.h crosshair.h \
  draw.h error.h layer.h find.h search.h rats.h netlist.h route_style.h \
- rats.h
-../src_plugins/hid_gtk/gui-pinout-preview.o: \
- ../src_plugins/hid_gtk/gui-pinout-preview.c ../config.h conf_core.h \
- conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h globalconst.h ../src_plugins/hid_gtk/gui.h \
- board.h const.h macro.h vtroutestyle.h attrib.h layer.h obj_all_list.h \
- obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
- ../src_3rd/genlist/gendlist.h flag.h obj_arc.h obj_elem_list.h \
- obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
- obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid.h error.h drc.h \
- hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h copy.h draw.h move.h \
- rotate.h obj_all.h
-../src_plugins/hid_gtk/gui-pinout-window.o: \
- ../src_plugins/hid_gtk/gui-pinout-window.c ../config.h conf_core.h \
- conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ rats.h ../src_plugins/hid_gtk/gtkhid-main.h conf_hid.h \
+ ../src_plugins/lib_gtk_common/bu_dwg_tooltip.h \
+ ../src_plugins/lib_gtk_common/bu_status_line.h \
+ ../src_plugins/lib_gtk_common/in_keyboard.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h
+../src_plugins/hid_gtk/gui-top-window.o: \
+ ../src_plugins/hid_gtk/gui-top-window.c ../config.h conf_core.h conf.h \
+ global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
@@ -1431,113 +1237,36 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid.h error.h drc.h \
- hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
- ../src_plugins/hid_gtk/win_place.h copy.h draw.h move.h rotate.h
-../src_plugins/hid_gtk/gui-top-window.o: \
- ../src_plugins/hid_gtk/gui-top-window.c ../config.h conf_core.h conf.h \
- global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h globalconst.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- vtroutestyle.h attrib.h ../src_plugins/hid_gtk/gtkhid.h conf_hid.h \
- error.h ../src_plugins/hid_gtk/gui.h board.h const.h macro.h layer.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
- obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
- ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
  rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h hid.h \
- drc.h hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h \
- hid_cfg.h data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h hid_cfg_action.h \
+ error.h drc.h hid_cfg.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-main-menu.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h event.h \
+ compat_misc.h ../src_plugins/hid_gtk/colors.h \
+ ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h hid_cfg_action.h \
  action_helper.h buffer.h change.h copy.h crosshair.h draw.h error.h \
  plug_io.h find.h insert.h layer.h move.h pcb-printf.h polygon.h rtree.h \
  rats.h netlist.h route_style.h remove.h rotate.h search.h rats.h \
  select.h operation.h undo.h free_atexit.h paths.h \
  ../src_plugins/hid_gtk/gui-icons-mode-buttons.data \
- ../src_plugins/hid_gtk/gui-icons-misc.data \
- ../src_plugins/hid_gtk/win_place.h hid_attrib.h hid_actions.h \
- hid_flags.h compat_nls.h obj_line.h layer_vis.h
-../src_plugins/hid_gtk/gui-utils.o: ../src_plugins/hid_gtk/gui-utils.c \
- ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- ../src_3rd/genvector/vtp0.h list_conf.h \
- ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h globalconst.h ../src_plugins/hid_gtk/gui.h \
- board.h const.h macro.h vtroutestyle.h attrib.h layer.h obj_all_list.h \
- obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
- ../src_3rd/genlist/gendlist.h flag.h obj_arc.h obj_elem_list.h \
- obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
- obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid.h error.h drc.h \
- hid_cfg.h hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
- data.h crosshair.h vtonpoint.h hid.h buffer.h \
- ../src_plugins/hid_gtk/ghid-coord-entry.h unit.h \
- ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h
-../src_plugins/hid_gtk/menu_lht.o: ../src_plugins/hid_gtk/menu_lht.c
-../src_plugins/hid_gtk/win_place.o: ../src_plugins/hid_gtk/win_place.c \
- ../config.h ../src_plugins/hid_gtk/win_place.h \
- ../src_plugins/hid_gtk/gui.h board.h const.h macro.h global_typedefs.h \
- pcb_bool.h unit.h vtroutestyle.h attrib.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
- obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
- obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h hid.h error.h drc.h hid_cfg.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h hid_cfg_input.h \
- ../src_3rd/liblihata/genht/htip.h hid_cfg.h data.h crosshair.h \
- vtonpoint.h hid.h buffer.h ../src_plugins/hid_gtk/ghid-coord-entry.h \
- unit.h ../src_plugins/hid_gtk/ghid-main-menu.h \
- ../src_plugins/hid_gtk/ghid-layer-selector.h \
- ../src_plugins/hid_gtk/ghid-route-style-selector.h route_style.h \
- ../src_plugins/hid_gtk/gui-pinout-preview.h \
- ../src_plugins/hid_gtk/ghid-propedit.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/genvector/vtp0.h list_conf.h event.h compat_misc.h \
- ../src_plugins/hid_gtk/hid_gtk_conf.h conf.h
+ ../src_plugins/hid_gtk/gui-icons-misc.data hid_attrib.h hid_actions.h \
+ hid_flags.h compat_nls.h obj_line.h layer_vis.h \
+ ../src_plugins/hid_gtk/gtkhid-main.h conf_hid.h \
+ ../src_plugins/lib_gtk_common/bu_box.h \
+ ../src_plugins/lib_gtk_common/bu_status_line.h \
+ ../src_plugins/lib_gtk_common/dlg_route_style.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h \
+ ../src_plugins/lib_gtk_common/util_str.h \
+ ../src_plugins/lib_gtk_common/in_keyboard.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h \
+ ../src_plugins/lib_gtk_common/win_place.h
 ../src_plugins/hid_lesstif/dialogs.o: \
  ../src_plugins/hid_lesstif/dialogs.c \
  ../src_plugins/hid_lesstif/xincludes.h ../config.h conf_core.h conf.h \
@@ -1556,8 +1285,9 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h build_run.h crosshair.h layer.h \
- pcb-printf.h hid.h ../src_plugins/hid_lesstif/lesstif.h hid_cfg_input.h \
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h build_run.h \
+ crosshair.h layer.h pcb-printf.h hid.h \
+ ../src_plugins/hid_lesstif/lesstif.h hid_cfg_input.h \
  ../src_3rd/liblihata/genht/htip.h hid_cfg.h compat_nls.h board.h const.h \
  macro.h vtroutestyle.h library.h rats_patch.h board.h font.h box.h \
  math_helper.h move.h misc_util.h hid_attrib.h hid_actions.h hid_init.h \
@@ -1580,7 +1310,7 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h buffer.h vtptr.h \
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h buffer.h vtptr.h \
  plug_footprint.h vtlibrary.h hid.h ../src_plugins/hid_lesstif/lesstif.h \
  hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h compat_nls.h \
  board.h const.h macro.h vtroutestyle.h library.h rats_patch.h board.h \
@@ -1603,15 +1333,17 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h crosshair.h \
- layer.h pcb-printf.h clip.h event.h error.h plugins.h hid.h hid_nogui.h \
- hid_draw_helpers.h hid_cfg.h ../src_plugins/hid_lesstif/lesstif.h \
- hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h hid_cfg.h compat_nls.h \
- board.h const.h macro.h vtroutestyle.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h hid_attrib.h hid_helper.h \
- hid_init.h hid_color.h hid_extents.h hid_flags.h hid_actions.h \
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h action_helper.h \
+ crosshair.h layer.h pcb-printf.h clip.h event.h error.h plugins.h hid.h \
+ hid_nogui.h hid_draw_helpers.h hid_cfg.h \
+ ../src_plugins/hid_lesstif/lesstif.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h compat_nls.h board.h const.h \
+ macro.h vtroutestyle.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h hid_attrib.h hid_helper.h hid_init.h \
+ hid_color.h hid_extents.h hid_flags.h hid_actions.h \
  ../src_plugins/hid_lesstif/stdarg.h misc_util.h compat_misc.h \
- layer_vis.h dolists.h
+ layer_vis.h ../src_plugins/hid_lesstif/dlg_preview.c stub_draw_csect.h \
+ dolists.h
 ../src_plugins/hid_lesstif/menu.o: ../src_plugins/hid_lesstif/menu.c \
  ../src_plugins/hid_lesstif/xincludes.h ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
@@ -1629,13 +1361,13 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h error.h pcb-printf.h layer.h \
- hid.h hid_cfg.h hid_cfg_action.h hid_cfg.h hid_cfg_input.h \
- ../src_3rd/liblihata/genht/htip.h ../src_plugins/hid_lesstif/lesstif.h \
- compat_nls.h board.h const.h macro.h vtroutestyle.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
- paths.h hid_actions.h hid_flags.h ../src_plugins/hid_lesstif/stdarg.h \
- event.h compat_misc.h layer_vis.h
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h error.h \
+ pcb-printf.h layer.h hid.h hid_cfg.h hid_cfg_action.h hid_cfg.h \
+ hid_cfg_input.h ../src_3rd/liblihata/genht/htip.h \
+ ../src_plugins/hid_lesstif/lesstif.h compat_nls.h board.h const.h \
+ macro.h vtroutestyle.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h paths.h hid_actions.h hid_flags.h \
+ ../src_plugins/hid_lesstif/stdarg.h event.h compat_misc.h layer_vis.h
 ../src_plugins/hid_lesstif/menu_lht.o: \
  ../src_plugins/hid_lesstif/menu_lht.c
 ../src_plugins/hid_lesstif/netlist.o: \
@@ -1651,11 +1383,11 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- find.h rats.h netlist.h library.h route_style.h vtroutestyle.h select.h \
- operation.h undo.h remove.h crosshair.h draw.h obj_all.h event.h hid.h \
- hid_actions.h ../src_plugins/hid_lesstif/lesstif.h hid_cfg_input.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h find.h rats.h netlist.h library.h route_style.h vtroutestyle.h \
+ select.h operation.h undo.h remove.h crosshair.h draw.h obj_all.h \
+ event.h hid.h hid_actions.h ../src_plugins/hid_lesstif/lesstif.h \
+ hid_cfg_input.h ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/htip.h \
  hid_cfg.h compat_nls.h board.h const.h macro.h rats_patch.h board.h \
@@ -1681,7 +1413,7 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h pcb-printf.h hid.h \
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h pcb-printf.h hid.h \
  ../src_plugins/hid_lesstif/lesstif.h hid_cfg_input.h \
  ../src_3rd/liblihata/genht/htip.h hid_cfg.h compat_nls.h board.h const.h \
  macro.h vtroutestyle.h library.h rats_patch.h board.h font.h box.h \
@@ -1705,7 +1437,7 @@
  obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
  obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
  ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h layer.h
 ../src_plugins/hid_remote/remote.o: ../src_plugins/hid_remote/remote.c \
  ../config.h board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
  vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
@@ -1718,13 +1450,16 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h hid.h error.h drc.h data.h crosshair.h vtonpoint.h \
- hid.h buffer.h layer.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- plugins.h compat_misc.h event.h ../src_plugins/hid_remote/proto.h \
- hid_draw_helpers.h hid_nogui.h hid_actions.h hid_init.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h hid.h error.h drc.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h layer.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h plugins.h compat_misc.h event.h \
+ ../src_plugins/hid_remote/proto.h hid_draw_helpers.h hid_nogui.h \
+ hid_actions.h hid_init.h dolists.h
 ../src_plugins/import_dsn/dsn.o: ../src_plugins/import_dsn/dsn.c \
- ../config.h board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
+ ../config.h ../src_3rd/gensexpr/gsxl.h \
+ ../src_3rd/gensexpr/gensexpr_impl.h ../src_3rd/gensexpr/gsx_parse.h \
+ board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
  vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
  obj_all_list.h obj_arc_list.h obj_common.h \
@@ -1735,13 +1470,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h error.h rats.h netlist.h route_style.h buffer.h change.h draw.h \
- undo.h pcb-printf.h ../src_3rd/genvector/gds_char.h polygon.h rtree.h \
- compat_misc.h compat_nls.h obj_pinvia.h obj_rat.h action_helper.h hid.h \
- hid_draw_helpers.h hid_nogui.h hid_actions.h hid_init.h hid_attrib.h \
- hid_helper.h plugins.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h polygon.h rtree.h action_helper.h hid.h plugins.h \
+ dolists.h
 ../src_plugins/import_edif/edif.o: ../src_plugins/import_edif/edif.c \
  math_helper.h board.h ../config.h const.h macro.h global_typedefs.h \
  pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -1755,9 +1487,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h library.h error.h plugins.h compat_misc.h compat_nls.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h library.h error.h plugins.h compat_misc.h \
+ compat_nls.h
 ../src_plugins/import_edif/import_edif.o: \
  ../src_plugins/import_edif/import_edif.c ../config.h board.h const.h \
  macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -1771,9 +1504,9 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h plugins.h plug_import.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h plugins.h plug_import.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -1793,8 +1526,8 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h
 ../src_plugins/import_hyp/hyp_y.o: ../src_plugins/import_hyp/hyp_y.c \
  ../src_plugins/import_hyp/parser.h pcb_bool.h board.h ../config.h \
  const.h macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h \
@@ -1808,8 +1541,8 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h
 ../src_plugins/import_hyp/import_hyp.o: \
  ../src_plugins/import_hyp/import_hyp.c ../config.h action_helper.h \
  global_typedefs.h pcb_bool.h unit.h compat_nls.h hid.h error.h drc.h \
@@ -1821,10 +1554,11 @@
  obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
  obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
  ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h hid_draw_helpers.h \
- hid_nogui.h hid_actions.h hid.h hid_init.h hid_attrib.h hid_helper.h \
- plugins.h ../src_plugins/import_hyp/parser.h pcb_bool.h board.h const.h \
- macro.h vtroutestyle.h ../src_3rd/genvector/genvector_impl.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ hid_draw_helpers.h hid_nogui.h hid_actions.h hid.h hid_init.h \
+ hid_attrib.h hid_helper.h plugins.h ../src_plugins/import_hyp/parser.h \
+ pcb_bool.h board.h const.h macro.h vtroutestyle.h \
+ ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h library.h rats_patch.h board.h \
  font.h box.h math_helper.h move.h misc_util.h dolists.h
 ../src_plugins/import_hyp/parser.o: ../src_plugins/import_hyp/parser.c \
@@ -1840,11 +1574,48 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h ../src_plugins/import_hyp/hyp_l.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h ../src_plugins/import_hyp/hyp_l.h \
  ../src_plugins/import_hyp/hyp_y.h error.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h obj_all.h flag_str.h layer.h data.h \
- crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h
+ ../src_3rd/genvector/gds_char.h obj_all.h flag_str.h polygon.h rtree.h \
+ layer.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
+ search.h rats.h netlist.h route_style.h compat_misc.h
+../src_plugins/import_ltspice/ltspice.o: \
+ ../src_plugins/import_ltspice/ltspice.c ../config.h \
+ ../src_3rd/qparse/qparse.h board.h const.h macro.h global_typedefs.h \
+ pcb_bool.h unit.h vtroutestyle.h attrib.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h compat_misc.h action_helper.h \
+ hid_actions.h plugins.h hid.h dolists.h
+../src_plugins/import_mucs/mucs.o: ../src_plugins/import_mucs/mucs.c \
+ ../config.h board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
+ vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h compat_misc.h action_helper.h \
+ hid_actions.h plugins.h dolists.h
 ../src_plugins/import_netlist/import_netlist.o: \
  ../src_plugins/import_netlist/import_netlist.c ../config.h board.h \
  const.h macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h \
@@ -1858,8 +1629,8 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h plugins.h plug_io.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h plugins.h plug_io.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -1883,14 +1654,33 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h change.h \
- error.h undo.h plugins.h compat_fs.h pcb-printf.h remove.h rats.h \
- netlist.h route_style.h hid_actions.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
+ action_helper.h change.h error.h undo.h plugins.h compat_fs.h \
+ pcb-printf.h remove.h rats.h netlist.h route_style.h hid_actions.h \
  ../src_plugins/import_sch/import_sch_conf.h conf.h misc_util.h \
  compat_nls.h compat_misc.h obj_rat.h dolists.h \
  ../src_plugins/import_sch/import_sch_conf_fields.h
+../src_plugins/import_tinycad/tinycad.o: \
+ ../src_plugins/import_tinycad/tinycad.c ../config.h \
+ ../src_3rd/qparse/qparse.h board.h const.h macro.h global_typedefs.h \
+ pcb_bool.h unit.h vtroutestyle.h attrib.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h compat_misc.h action_helper.h \
+ hid_actions.h plugins.h hid.h dolists.h
 ../src_plugins/io_kicad/io_kicad.o: ../src_plugins/io_kicad/io_kicad.c \
  ../config.h plugins.h plug_io.h library.h global_typedefs.h pcb_bool.h \
  unit.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -1909,7 +1699,7 @@
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
  obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h vtonpoint.h hid.h \
- error.h drc.h buffer.h ../src_plugins/io_kicad/read.h
+ error.h drc.h layer_grp.h buffer.h ../src_plugins/io_kicad/read.h
 ../src_plugins/io_kicad/read.o: ../src_plugins/io_kicad/read.c \
  ../src_3rd/gensexpr/gsxl.h ../src_3rd/gensexpr/gensexpr_impl.h \
  ../src_3rd/gensexpr/gsx_parse.h ../src_3rd/liblihata/genht/htsi.h \
@@ -1925,9 +1715,9 @@
  obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h plug_io.h conf.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ plug_io.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/genvector/vtp0.h \
@@ -1952,8 +1742,8 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h plug_io.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h plug_io.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -1981,7 +1771,7 @@
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
  obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h vtonpoint.h hid.h \
- error.h drc.h buffer.h
+ error.h drc.h layer_grp.h buffer.h
 ../src_plugins/io_kicad_legacy/write.o: \
  ../src_plugins/io_kicad_legacy/write.c ../config.h board.h const.h \
  macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -1995,8 +1785,8 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h plug_io.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h plug_io.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -2016,8 +1806,8 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- macro.h ../src_plugins/io_lihata/common.h
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h macro.h ../src_plugins/io_lihata/common.h
 ../src_plugins/io_lihata/io_lihata.o: \
  ../src_plugins/io_lihata/io_lihata.c ../config.h plugins.h plug_io.h \
  library.h global_typedefs.h pcb_bool.h unit.h conf.h pcb-printf.h \
@@ -2047,10 +1837,10 @@
  obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h plugins.h plug_io.h conf.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h plugins.h \
+ plug_io.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/genvector/vtp0.h list_conf.h \
  flag_str.h compat_misc.h macro.h error.h misc_util.h layer.h vtptr.h \
  ../src_plugins/io_lihata/common.h polygon.h rtree.h conf_core.h \
@@ -2070,10 +1860,10 @@
  obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h plugins.h plug_io.h conf.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h plugins.h \
+ plug_io.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/genvector/vtp0.h list_conf.h \
  flag_str.h compat_misc.h rats_patch.h hid_actions.h misc_util.h macro.h \
  layer.h ../src_plugins/io_lihata/common.h \
@@ -2102,8 +1892,9 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h compat_misc.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ compat_misc.h
 ../src_plugins/io_pcb/file.o: ../src_plugins/io_pcb/file.c ../config.h \
  conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -2120,7 +1911,7 @@
  obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
  obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h data.h crosshair.h buffer.h error.h \
+ obj_rat.h layer_grp.h data.h crosshair.h buffer.h error.h \
  ../src_plugins/io_pcb/file.h board.h const.h macro.h vtroutestyle.h \
  library.h rats_patch.h board.h font.h box.h math_helper.h move.h \
  misc_util.h plug_io.h hid.h layer.h move.h \
@@ -2138,87 +1929,612 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  ../src_3rd/genvector/vtp0.h list_conf.h \
  ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h ../src_plugins/io_pcb/file.h board.h \
- const.h macro.h vtroutestyle.h attrib.h layer.h globalconst.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/genlist/gendlist.h ../src_plugins/io_pcb/file.h board.h \
+ const.h macro.h vtroutestyle.h attrib.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h
+../src_plugins/io_pcb/parse_l.o: ../src_plugins/io_pcb/parse_l.c \
+ ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h flag_str.h flag.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h attrib.h layer.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h \
+ obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h data.h \
+ crosshair.h buffer.h error.h ../src_plugins/io_pcb/file.h board.h \
+ const.h macro.h vtroutestyle.h library.h rats_patch.h board.h font.h \
+ box.h math_helper.h move.h misc_util.h plug_io.h \
+ ../src_plugins/io_pcb/parse_common.h ../src_plugins/io_pcb/parse_y.h \
+ plug_footprint.h vtlibrary.h ../src_plugins/io_pcb/attribs.h \
+ compat_misc.h compat_cc.h obj_common.h paths.h
+../src_plugins/io_pcb/parse_y.o: ../src_plugins/io_pcb/parse_y.c \
+ ../config.h flag.h globalconst.h board.h const.h macro.h \
+ global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h obj_all_list.h \
+ obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
+ ../src_3rd/genlist/gendlist.h flag.h obj_arc.h \
+ ../src_3rd/genlist/gentdlist_impl.h ../src_3rd/genlist/gendlist.h \
+ ../src_3rd/genlist/gentdlist_undef.h obj_elem_list.h obj_elem.h \
+ obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
+ obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ library.h rats_patch.h board.h font.h box.h math_helper.h move.h \
+ misc_util.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ layer.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
+ error.h ../src_plugins/io_pcb/file.h plug_io.h \
+ ../src_plugins/io_pcb/parse_l.h polygon.h rtree.h remove.h rtree.h \
+ flag_str.h obj_pinvia_therm.h rats_patch.h route_style.h compat_misc.h \
+ obj_all.h ../src_plugins/io_pcb/parse_y.h
+../src_plugins/jostle/jostle.o: ../src_plugins/jostle/jostle.c \
+ ../config.h board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
+ vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h hid.h rtree.h undo.h rats.h netlist.h \
+ route_style.h polygon.h rtree.h remove.h error.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h plugins.h hid_actions.h layer.h \
+ conf_core.h conf.h pcb-printf.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ misc_util.h obj_line.h event.h dolists.h
+../src_plugins/lib_gensexpr/lib_gensexpr.o: \
+ ../src_plugins/lib_gensexpr/lib_gensexpr.c plugins.h
+../src_plugins/lib_gtk_common/act_fileio.o: \
+ ../src_plugins/lib_gtk_common/act_fileio.c ../config.h \
+ ../src_plugins/lib_gtk_common/act_fileio.h unit.h hid_actions.h hid.h \
+ error.h drc.h unit.h global_typedefs.h pcb_bool.h attrib.h layer.h \
+ globalconst.h obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ compat_nls.h plug_footprint.h vtlibrary.h compat_misc.h board.h const.h \
+ macro.h vtroutestyle.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h buffer.h \
+ ../src_plugins/lib_gtk_common/dlg_file_chooser.h plug_io.h \
+ ../src_plugins/lib_gtk_common/util_str.h
+../src_plugins/lib_gtk_common/act_print.o: \
+ ../src_plugins/lib_gtk_common/act_print.c ../config.h \
+ ../src_plugins/lib_gtk_common/act_print.h board.h const.h macro.h \
+ global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h hid.h error.h drc.h hid_init.h hid.h \
+ hid_attrib.h data.h crosshair.h vtonpoint.h buffer.h compat_nls.h \
+ ../src_plugins/lib_gtk_common/dlg_print.h
+../src_plugins/lib_gtk_common/bu_box.o: \
+ ../src_plugins/lib_gtk_common/bu_box.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_box.h \
+ ../src_plugins/lib_gtk_common/compat.h
+../src_plugins/lib_gtk_common/bu_check_button.o: \
+ ../src_plugins/lib_gtk_common/bu_check_button.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_check_button.h
+../src_plugins/lib_gtk_common/bu_cursor_pos.o: \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_cursor_pos.h conf_core.h conf.h \
+ global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h hid_actions.h hid.h error.h \
+ drc.h attrib.h layer.h obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ crosshair.h vtonpoint.h misc_util.h compat_nls.h math_helper.h
+../src_plugins/lib_gtk_common/bu_dwg_tooltip.o: \
+ ../src_plugins/lib_gtk_common/bu_dwg_tooltip.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_dwg_tooltip.h layer.h globalconst.h \
+ global_typedefs.h pcb_bool.h unit.h attrib.h obj_all_list.h \
+ obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
+ ../src_3rd/genlist/gendlist.h flag.h obj_arc.h \
+ ../src_3rd/genlist/gentdlist_impl.h ../src_3rd/genlist/gendlist.h \
+ ../src_3rd/genlist/gentdlist_undef.h obj_elem_list.h obj_elem.h \
+ obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
+ obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h search.h \
+ rats.h netlist.h library.h route_style.h vtroutestyle.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h layer_grp.h misc_util.h \
+ const.h find.h board.h const.h macro.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h
+../src_plugins/lib_gtk_common/bu_entry.o: \
+ ../src_plugins/lib_gtk_common/bu_entry.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_entry.h \
+ ../src_plugins/lib_gtk_common/wt_coord_entry.h unit.h conf_core.h conf.h \
+ global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h
+../src_plugins/lib_gtk_common/bu_notebook.o: \
+ ../src_plugins/lib_gtk_common/bu_notebook.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_notebook.h \
+ ../src_plugins/lib_gtk_common/bu_box.h
+../src_plugins/lib_gtk_common/bu_spin_button.o: \
+ ../src_plugins/lib_gtk_common/bu_spin_button.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_spin_button.h
+../src_plugins/lib_gtk_common/bu_status_line.o: \
+ ../src_plugins/lib_gtk_common/bu_status_line.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_status_line.h conf_core.h conf.h \
+ global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h compat_misc.h compat_nls.h \
+ board.h const.h macro.h vtroutestyle.h attrib.h layer.h obj_all_list.h \
+ obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
+ ../src_3rd/genlist/gendlist.h flag.h obj_arc.h obj_elem_list.h \
+ obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
+ obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h
+../src_plugins/lib_gtk_common/bu_text_view.o: \
+ ../src_plugins/lib_gtk_common/bu_text_view.c ../config.h \
+ ../src_plugins/lib_gtk_common/bu_text_view.h
+../src_plugins/lib_gtk_common/dlg_about.o: \
+ ../src_plugins/lib_gtk_common/dlg_about.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_about.h compat_nls.h build_run.h \
+ ../src_plugins/lib_gtk_common/dlg_report.h
+../src_plugins/lib_gtk_common/dlg_attribute.o: \
+ ../src_plugins/lib_gtk_common/dlg_attribute.c ../config.h conf_core.h \
+ conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h \
+ ../src_plugins/lib_gtk_common/dlg_attribute.h hid.h error.h drc.h \
+ attrib.h layer.h obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ pcb-printf.h hid_attrib.h hid.h hid_init.h misc_util.h compat_misc.h \
+ compat_nls.h ../src_plugins/lib_gtk_common/wt_coord_entry.h unit.h
+../src_plugins/lib_gtk_common/dlg_confirm.o: \
+ ../src_plugins/lib_gtk_common/dlg_confirm.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_confirm.h compat_nls.h board.h const.h \
+ macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h hid_actions.h hid.h error.h drc.h \
+ ../src_plugins/lib_gtk_common/dlg_message.h
+../src_plugins/lib_gtk_common/dlg_export.o: \
+ ../src_plugins/lib_gtk_common/dlg_export.c ../config.h conf_core.h \
+ conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h \
+ ../src_plugins/lib_gtk_common/dlg_export.h hid.h error.h drc.h attrib.h \
+ layer.h obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ ../src_plugins/lib_gtk_common/dlg_print.h pcb-printf.h hid_attrib.h \
+ hid.h hid_init.h misc_util.h compat_misc.h compat_nls.h
+../src_plugins/lib_gtk_common/dlg_file_chooser.o: \
+ ../src_plugins/lib_gtk_common/dlg_file_chooser.c ../config.h board.h \
+ const.h macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h \
+ attrib.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h hid.h error.h drc.h compat_misc.h \
+ ../src_plugins/lib_gtk_common/dlg_file_chooser.h compat_nls.h plug_io.h \
+ conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_plugins/lib_gtk_common/util_str.h
+../src_plugins/lib_gtk_common/dlg_input.o: \
+ ../src_plugins/lib_gtk_common/dlg_input.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_input.h
+../src_plugins/lib_gtk_common/dlg_message.o: \
+ ../src_plugins/lib_gtk_common/dlg_message.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_message.h compat_nls.h
+../src_plugins/lib_gtk_common/dlg_pinout.o: \
+ ../src_plugins/lib_gtk_common/dlg_pinout.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_pinout.h obj_elem.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ globalconst.h attrib.h global_typedefs.h pcb_bool.h unit.h \
+ obj_arc_list.h obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
+ obj_pinvia.h obj_text.h hid.h error.h drc.h layer.h obj_all_list.h \
+ obj_elem_list.h obj_elem.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ copy.h data.h crosshair.h vtonpoint.h hid.h buffer.h draw.h move.h \
+ rotate.h macro.h ../src_plugins/lib_gtk_common/wt_preview.h layer.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
+ ../src_plugins/lib_gtk_common/win_place.h
+../src_plugins/lib_gtk_common/dlg_print.o: \
+ ../src_plugins/lib_gtk_common/dlg_print.c ../config.h conf_core.h conf.h \
+ global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h \
+ ../src_plugins/lib_gtk_common/dlg_print.h hid.h error.h drc.h attrib.h \
+ layer.h obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ pcb-printf.h hid_attrib.h hid.h hid_init.h misc_util.h compat_misc.h \
+ compat_nls.h ../src_plugins/lib_gtk_common/dlg_attribute.h
+../src_plugins/lib_gtk_common/dlg_progress.o: \
+ ../src_plugins/lib_gtk_common/dlg_progress.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_progress.h pcb_bool.h compat_nls.h
+../src_plugins/lib_gtk_common/dlg_propedit.o: \
+ ../src_plugins/lib_gtk_common/dlg_propedit.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_propedit.h compat_misc.h compat_nls.h \
+ polygon.h flag.h globalconst.h rtree.h global_typedefs.h pcb_bool.h \
+ unit.h math_helper.h polyarea.h obj_all.h obj_arc.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h attrib.h \
+ obj_elem.h obj_arc_list.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
+ obj_pinvia.h obj_text.h obj_poly.h obj_rat.h board.h const.h macro.h \
+ vtroutestyle.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h obj_all_list.h \
+ obj_elem_list.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_text_list.h \
+ obj_rat_list.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h buffer.h \
+ ../src_plugins/lib_gtk_common/bu_box.h \
+ ../src_plugins/lib_gtk_common/compat.h
+../src_plugins/lib_gtk_common/dlg_report.o: \
+ ../src_plugins/lib_gtk_common/dlg_report.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_report.h \
+ ../src_plugins/lib_gtk_common/compat.h \
+ ../src_plugins/lib_gtk_common/bu_box.h
+../src_plugins/lib_gtk_common/dlg_route_style.o: \
+ ../src_plugins/lib_gtk_common/dlg_route_style.c ../config.h \
+ compat_misc.h compat_nls.h polygon.h flag.h globalconst.h rtree.h \
+ global_typedefs.h pcb_bool.h unit.h math_helper.h polyarea.h obj_all.h \
+ obj_arc.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
+ ../src_3rd/genlist/gendlist.h attrib.h obj_elem.h obj_arc_list.h \
+ ../src_3rd/genlist/gentdlist_impl.h ../src_3rd/genlist/gendlist.h \
+ ../src_3rd/genlist/gentdlist_undef.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ obj_poly.h obj_rat.h ../src_plugins/lib_gtk_common/bu_box.h \
+ ../src_plugins/lib_gtk_common/compat.h board.h const.h macro.h \
+ vtroutestyle.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h obj_all_list.h \
+ obj_elem_list.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_text_list.h \
+ obj_rat_list.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ move.h misc_util.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ error.h ../src_plugins/lib_gtk_common/dlg_route_style.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h \
+ ../src_plugins/lib_gtk_common/wt_coord_entry.h unit.h
+../src_plugins/lib_gtk_common/dlg_search.o: \
+ ../src_plugins/lib_gtk_common/dlg_search.c ../config.h \
+ ../src_plugins/lib_gtk_common/dlg_search.h ../src_3rd/genlist/gendlist.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h compat_misc.h hid_actions.h hid.h \
+ error.h drc.h unit.h global_typedefs.h pcb_bool.h attrib.h layer.h \
+ globalconst.h obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h flag.h obj_arc.h \
+ ../src_3rd/genlist/gentdlist_impl.h ../src_3rd/genlist/gendlist.h \
+ ../src_3rd/genlist/gentdlist_undef.h obj_elem_list.h obj_elem.h \
+ obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
+ obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ compat_nls.h misc_util.h pcb-printf.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_plugins/lib_gtk_common/win_place.h \
+ ../src_plugins/lib_gtk_common/wt_coord_entry.h unit.h \
+ ../src_plugins/lib_gtk_common/bu_box.h \
+ ../src_plugins/lib_gtk_common/dlg_search_tab.h
+../src_plugins/lib_gtk_common/in_keyboard.o: \
+ ../src_plugins/lib_gtk_common/in_keyboard.c ../config.h \
+ ../src_plugins/lib_gtk_common/in_keyboard.h hid_cfg_input.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h
+../src_plugins/lib_gtk_common/in_mouse.o: \
+ ../src_plugins/lib_gtk_common/in_mouse.c ../config.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h hid_cfg_input.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h const.h board.h const.h \
+ macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h \
+ ../src_plugins/lib_gtk_common/in_keyboard.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/bu_status_line.h
+../src_plugins/lib_gtk_common/lib_gtk_common.o: \
+ ../src_plugins/lib_gtk_common/lib_gtk_common.c plugins.h
+../src_plugins/lib_gtk_common/menu_lht.o: \
+ ../src_plugins/lib_gtk_common/menu_lht.c
+../src_plugins/lib_gtk_common/ui_zoompan.o: \
+ ../src_plugins/lib_gtk_common/ui_zoompan.c ../config.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h hid_cfg_input.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h action_helper.h \
+ global_typedefs.h pcb_bool.h unit.h error.h conf_core.h conf.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h board.h const.h macro.h \
+ vtroutestyle.h attrib.h layer.h obj_all_list.h obj_arc_list.h \
+ obj_common.h ../src_3rd/liblihata/genht/hash.h \
+ ../src_3rd/genlist/gendlist.h flag.h obj_arc.h obj_elem_list.h \
+ obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
+ obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ compat_misc.h compat_nls.h draw.h hid.h error.h drc.h data.h crosshair.h \
+ vtonpoint.h buffer.h layer_vis.h \
+ ../src_plugins/lib_gtk_common/bu_status_line.h
+../src_plugins/lib_gtk_common/util_block_hook.o: \
+ ../src_plugins/lib_gtk_common/util_block_hook.c ../config.h \
+ ../src_plugins/lib_gtk_common/util_block_hook.h hid.h error.h drc.h \
+ unit.h global_typedefs.h pcb_bool.h attrib.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h
+../src_plugins/lib_gtk_common/util_str.o: \
+ ../src_plugins/lib_gtk_common/util_str.c ../config.h \
+ ../src_plugins/lib_gtk_common/util_str.h
+../src_plugins/lib_gtk_common/util_timer.o: \
+ ../src_plugins/lib_gtk_common/util_timer.c ../config.h \
+ ../src_plugins/lib_gtk_common/util_timer.h hid.h error.h drc.h unit.h \
+ global_typedefs.h pcb_bool.h attrib.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h
+../src_plugins/lib_gtk_common/util_watch.o: \
+ ../src_plugins/lib_gtk_common/util_watch.c ../config.h \
+ ../src_plugins/lib_gtk_common/util_watch.h hid.h error.h drc.h unit.h \
+ global_typedefs.h pcb_bool.h attrib.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h ../src_plugins/lib_gtk_common/in_mouse.h \
+ hid_cfg_input.h ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/htip.h \
+ hid_cfg.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h
+../src_plugins/lib_gtk_common/win_place.o: \
+ ../src_plugins/lib_gtk_common/win_place.c ../config.h \
+ ../src_plugins/lib_gtk_common/win_place.h conf_core.h conf.h \
+ global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h
+../src_plugins/lib_gtk_common/wt_coord_entry.o: \
+ ../src_plugins/lib_gtk_common/wt_coord_entry.c ../config.h \
+ ../src_plugins/lib_gtk_common/wt_coord_entry.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h unit.h compat_nls.h
+../src_plugins/lib_gtk_common/wt_layer_selector.o: \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.c ../config.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h unit.h \
+ ../src_plugins/lib_gtk_common/wt_layer_selector_cr.h
+../src_plugins/lib_gtk_common/wt_layer_selector_cr.o: \
+ ../src_plugins/lib_gtk_common/wt_layer_selector_cr.c ../config.h \
+ compat_nls.h ../src_plugins/lib_gtk_common/wt_layer_selector_cr.h \
+ ../src_plugins/lib_gtk_common/util_str.h
+../src_plugins/lib_gtk_common/wt_preview.o: \
+ ../src_plugins/lib_gtk_common/wt_preview.c ../config.h conf_core.h \
+ conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h \
+ ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h \
+ ../src_plugins/lib_gtk_common/wt_preview.h obj_elem.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
- obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
+ attrib.h obj_arc_list.h obj_arc.h obj_line_list.h obj_line.h \
+ obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h hid.h \
+ error.h drc.h layer.h obj_all_list.h obj_elem_list.h obj_elem.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h
-../src_plugins/io_pcb/parse_l.o: ../src_plugins/io_pcb/parse_l.c \
- ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/genvector/genvector_impl.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h layer.h \
+ ../src_plugins/lib_gtk_common/ui_zoompan.h unit.h pcb_bool.h \
+ ../src_plugins/lib_gtk_common/in_mouse.h hid_cfg_input.h \
+ ../src_3rd/liblihata/genht/htip.h hid_cfg.h copy.h data.h crosshair.h \
+ vtonpoint.h hid.h buffer.h draw.h move.h rotate.h obj_all.h macro.h
+../src_plugins/lib_gtk_common/wt_route_style.o: \
+ ../src_plugins/lib_gtk_common/wt_route_style.c ../config.h conf_core.h \
+ conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  ../src_3rd/genvector/vtp0.h list_conf.h \
  ../src_3rd/genlist/gentdlist_undef.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h globalconst.h flag_str.h flag.h \
- crosshair.h vtonpoint.h hid.h error.h drc.h attrib.h layer.h \
+ ../src_3rd/genlist/gendlist.h globalconst.h \
+ ../src_plugins/lib_gtk_common/dlg_route_style.h \
+ ../src_plugins/lib_gtk_common/wt_route_style.h route_style.h \
+ vtroutestyle.h attrib.h pcb-printf.h board.h const.h macro.h layer.h \
  obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
  obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h data.h crosshair.h \
- buffer.h error.h ../src_plugins/io_pcb/file.h board.h const.h macro.h \
- vtroutestyle.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h plug_io.h ../src_plugins/io_pcb/parse_common.h \
- ../src_plugins/io_pcb/parse_y.h plug_footprint.h vtlibrary.h \
- ../src_plugins/io_pcb/attribs.h compat_misc.h compat_cc.h obj_common.h \
- paths.h
-../src_plugins/io_pcb/parse_y.o: ../src_plugins/io_pcb/parse_y.c \
- ../config.h flag.h globalconst.h board.h const.h macro.h \
- global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
- ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h layer.h obj_all_list.h \
- obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
- ../src_3rd/genlist/gendlist.h flag.h obj_arc.h \
- ../src_3rd/genlist/gentdlist_impl.h ../src_3rd/genlist/gendlist.h \
- ../src_3rd/genlist/gentdlist_undef.h obj_elem_list.h obj_elem.h \
- obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
- obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
- conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h layer.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h error.h \
- ../src_plugins/io_pcb/file.h plug_io.h ../src_plugins/io_pcb/parse_l.h \
- polygon.h rtree.h remove.h rtree.h flag_str.h obj_pinvia_therm.h \
- rats_patch.h route_style.h compat_misc.h obj_all.h \
- ../src_plugins/io_pcb/parse_y.h
-../src_plugins/jostle/jostle.o: ../src_plugins/jostle/jostle.c \
- ../config.h board.h const.h macro.h global_typedefs.h pcb_bool.h unit.h \
- vtroutestyle.h attrib.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
- obj_all_list.h obj_arc_list.h obj_common.h \
- ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
- obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
- ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
- obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
- obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
- obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h hid.h rtree.h undo.h rats.h netlist.h route_style.h polygon.h \
- rtree.h remove.h error.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- plugins.h hid_actions.h layer.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h misc_util.h obj_line.h event.h \
- dolists.h
-../src_plugins/lib_gensexpr/lib_gensexpr.o: \
- ../src_plugins/lib_gensexpr/lib_gensexpr.c plugins.h
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ library.h rats_patch.h board.h font.h box.h math_helper.h move.h \
+ misc_util.h compat_nls.h ../src_plugins/lib_gtk_common/bu_status_line.h
 ../src_plugins/lib_legacy_func/lib_legacy_func.o: \
  ../src_plugins/lib_legacy_func/lib_legacy_func.c \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -2232,8 +2548,8 @@
  obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
  ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h change.h \
- error.h undo.h library.h plugins.h
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h action_helper.h \
+ change.h error.h undo.h library.h plugins.h
 ../src_plugins/loghid/loghid.o: ../src_plugins/loghid/loghid.c \
  ../config.h conf.h global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -2250,8 +2566,9 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h change.h \
- error.h undo.h library.h plugins.h hid_init.h hid_attrib.h dolists.h
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h action_helper.h \
+ change.h error.h undo.h library.h plugins.h hid_init.h hid_attrib.h \
+ dolists.h
 ../src_plugins/mincut/pcb-mincut/graph.o: \
  ../src_plugins/mincut/pcb-mincut/graph.c \
  ../src_plugins/mincut/pcb-mincut/graph.h \
@@ -2273,8 +2590,8 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- draw.h error.h plug_io.h library.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h draw.h error.h plug_io.h library.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -2304,9 +2621,9 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h change.h \
- error.h undo.h library.h plugins.h hid_actions.h plug_footprint.h \
- vtlibrary.h dolists.h
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h action_helper.h \
+ change.h error.h undo.h library.h plugins.h hid_actions.h \
+ plug_footprint.h vtlibrary.h dolists.h
 ../src_plugins/polycombine/polycombine.o: \
  ../src_plugins/polycombine/polycombine.c ../config.h board.h const.h \
  macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -2320,11 +2637,11 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h macro.h remove.h hid.h error.h rtree.h polygon.h rtree.h \
- polyarea.h flag_str.h find.h draw.h undo.h plugins.h hid_actions.h \
- obj_poly.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h macro.h remove.h hid.h error.h rtree.h polygon.h \
+ rtree.h polyarea.h flag_str.h find.h draw.h undo.h plugins.h \
+ hid_actions.h obj_poly.h dolists.h
 ../src_plugins/polystitch/polystitch.o: \
  ../src_plugins/polystitch/polystitch.c ../config.h board.h const.h \
  macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -2338,10 +2655,11 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h macro.h remove.h hid.h error.h rtree.h draw.h polygon.h rtree.h \
- plugins.h hid_actions.h obj_poly.h obj_poly_draw.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h macro.h remove.h hid.h error.h rtree.h draw.h \
+ polygon.h rtree.h plugins.h hid_actions.h obj_poly.h obj_poly_draw.h \
+ dolists.h
 ../src_plugins/propedit/propedit.o: ../src_plugins/propedit/propedit.c \
  plugins.h ../config.h ../src_plugins/propedit/props.h global_typedefs.h \
  pcb_bool.h unit.h ../src_3rd/liblihata/genht/htsp.h \
@@ -2355,7 +2673,7 @@
  obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h error.h dolists.h
 ../src_plugins/propedit/props.o: ../src_plugins/propedit/props.c \
@@ -2372,7 +2690,7 @@
  ../src_3rd/genlist/gentdlist_undef.h obj_elem_list.h obj_elem.h \
  obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
  obj_pinvia.h obj_text.h ht_element.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
  ../src_3rd/liblihata/genht/ht.c
 ../src_plugins/propedit/propsel.o: ../src_plugins/propedit/propsel.c \
  ../config.h const.h data.h globalconst.h global_typedefs.h pcb_bool.h \
@@ -2385,8 +2703,8 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- ../src_plugins/propedit/props.h global_typedefs.h \
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h ../src_plugins/propedit/props.h global_typedefs.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
  ../src_plugins/propedit/propsel.h change.h misc_util.h compat_misc.h \
  undo.h library.h rotate.h
@@ -2407,11 +2725,11 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h draw.h move.h pcb-printf.h \
- remove.h rtree.h flag_str.h undo.h layer.h plugins.h hid_actions.h \
- misc_util.h obj_all.h compat_misc.h dolists.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h \
+ move.h pcb-printf.h remove.h rtree.h flag_str.h undo.h layer.h plugins.h \
+ hid_actions.h misc_util.h obj_all.h compat_misc.h dolists.h
 ../src_plugins/query/basic_fnc.o: ../src_plugins/query/basic_fnc.c \
  ../config.h data.h globalconst.h global_typedefs.h pcb_bool.h unit.h \
  layer.h attrib.h obj_all_list.h obj_arc_list.h obj_common.h \
@@ -2423,9 +2741,9 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- ../src_plugins/query/query_access.h ../src_plugins/query/query.h \
- obj_any.h ../src_3rd/liblihata/genht/htsi.h \
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h ../src_plugins/query/query_access.h \
+ ../src_plugins/query/query.h obj_any.h ../src_3rd/liblihata/genht/htsi.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/genregex/regex_se.h \
  ../src_3rd/genregex/regex_templ.h ../src_3rd/genregex/regex.h \
  ../src_plugins/query/fields_sphash.h ../src_plugins/query/query_exec.h
@@ -2447,8 +2765,8 @@
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h change.h \
- error.h undo.h library.h plugins.h hid_init.h hid_actions.h \
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h action_helper.h \
+ change.h error.h undo.h library.h plugins.h hid_init.h hid_actions.h \
  compat_misc.h ../src_plugins/query/query.h obj_any.h \
  ../src_3rd/genregex/regex_se.h ../src_3rd/genregex/regex_templ.h \
  ../src_3rd/genregex/regex.h ../src_plugins/query/fields_sphash.h \
@@ -2466,9 +2784,9 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h ../src_plugins/query/query_access.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h ../src_plugins/query/query_access.h \
  ../src_plugins/query/query.h obj_any.h ../src_3rd/liblihata/genht/htsi.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/genregex/regex_se.h \
  ../src_3rd/genregex/regex_templ.h ../src_3rd/genregex/regex.h \
@@ -2488,8 +2806,8 @@
  obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h select.h operation.h \
- board.h const.h macro.h vtroutestyle.h \
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h select.h \
+ operation.h board.h const.h macro.h vtroutestyle.h \
  ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h library.h rats_patch.h board.h \
  font.h box.h math_helper.h move.h misc_util.h macro.h dolists.h
@@ -2504,13 +2822,13 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- ../src_plugins/query/query.h obj_any.h ../src_3rd/liblihata/genht/htsi.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/genregex/regex_se.h \
- ../src_3rd/genregex/regex_templ.h ../src_3rd/genregex/regex.h \
- ../src_plugins/query/fields_sphash.h ../src_plugins/query/query_exec.h \
- ../src_plugins/query/query_access.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h ../src_plugins/query/query.h obj_any.h \
+ ../src_3rd/liblihata/genht/htsi.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genregex/regex_se.h ../src_3rd/genregex/regex_templ.h \
+ ../src_3rd/genregex/regex.h ../src_plugins/query/fields_sphash.h \
+ ../src_plugins/query/query_exec.h ../src_plugins/query/query_access.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h
 ../src_plugins/query/query_l.o: ../src_plugins/query/query_l.c unit.h \
  ../config.h ../src_plugins/query/query.h obj_any.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
@@ -2547,15 +2865,16 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h action_helper.h change.h error.h undo.h plugins.h hid_actions.h \
- conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h compat_misc.h compat_nls.h \
- netlist.h route_style.h pcb-printf.h dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h action_helper.h change.h error.h undo.h plugins.h \
+ hid_actions.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ compat_misc.h compat_nls.h netlist.h route_style.h pcb-printf.h \
+ dolists.h
 ../src_plugins/renumber/renumberblock.o: \
  ../src_plugins/renumber/renumberblock.c ../config.h board.h const.h \
  macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -2569,10 +2888,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h hid.h rtree.h undo.h error.h change.h conf_core.h conf.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h hid.h rtree.h undo.h error.h change.h conf_core.h \
+ conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
@@ -2588,8 +2907,8 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- ../src_plugins/report/drill.h macro.h obj_pinvia.h
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h ../src_plugins/report/drill.h macro.h obj_pinvia.h
 ../src_plugins/report/report.o: ../src_plugins/report/report.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -2608,9 +2927,9 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h board.h const.h macro.h \
- vtroutestyle.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h buffer.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h board.h const.h \
+ macro.h vtroutestyle.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h buffer.h \
  ../src_plugins/report/drill.h error.h search.h rats.h netlist.h \
  route_style.h rats.h rtree.h flag_str.h macro.h undo.h find.h draw.h \
  pcb-printf.h plugins.h action_helper.h hid_actions.h misc_util.h \
@@ -2631,11 +2950,16 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h error.h event.h undo.h operation.h rotate.h draw.h \
- obj_rat_draw.h obj_line_op.h operation.h obj_line_draw.h plugins.h \
- polygon.h rtree.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h error.h event.h undo.h operation.h rotate.h \
+ draw.h obj_rat_draw.h obj_line_op.h operation.h obj_line_draw.h \
+ plugins.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ layer_grp.h polygon.h rtree.h
 ../src_plugins/shand_cmd/command.o: ../src_plugins/shand_cmd/command.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -2653,12 +2977,12 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h build_run.h \
- action_helper.h buffer.h ../src_plugins/shand_cmd/command.h data.h \
- crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h error.h plug_io.h \
- rats.h netlist.h route_style.h plugins.h hid_actions.h compat_misc.h \
- misc_util.h dolists.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ build_run.h action_helper.h buffer.h ../src_plugins/shand_cmd/command.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h error.h \
+ plug_io.h rats.h netlist.h route_style.h plugins.h hid_actions.h \
+ compat_misc.h misc_util.h dolists.h
 ../src_plugins/smartdisperse/smartdisperse.o: \
  ../src_plugins/smartdisperse/smartdisperse.c \
  ../src_3rd/liblihata/genht/htpi.h ../src_3rd/liblihata/genht/ht.h \
@@ -2673,11 +2997,11 @@
  obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h hid.h rtree.h undo.h rats.h \
- netlist.h route_style.h error.h move.h draw.h plugins.h action_helper.h \
- hid_actions.h compat_nls.h dolists.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h hid.h \
+ rtree.h undo.h rats.h netlist.h route_style.h error.h move.h draw.h \
+ plugins.h action_helper.h hid_actions.h compat_nls.h dolists.h
 ../src_plugins/stroke/stroke.o: ../src_plugins/stroke/stroke.c \
  ../config.h math_helper.h board.h const.h macro.h global_typedefs.h \
  pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -2691,14 +3015,15 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h conf.h conf_core.h data.h \
- crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h crosshair.h \
- stub_stroke.h rotate.h undo.h error.h plugins.h compat_nls.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ conf.h conf_core.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h crosshair.h stub_stroke.h rotate.h undo.h error.h plugins.h \
+ compat_nls.h
 ../src_plugins/teardrops/teardrops.o: \
  ../src_plugins/teardrops/teardrops.c ../config.h math_helper.h board.h \
  const.h macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h \
@@ -2712,10 +3037,10 @@
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h board.h font.h box.h math_helper.h \
- move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h hid.h rtree.h undo.h plugins.h hid_actions.h obj_all.h \
- dolists.h
+ obj_rat.h layer_grp.h library.h rats_patch.h board.h font.h box.h \
+ math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h hid.h rtree.h undo.h plugins.h hid_actions.h \
+ obj_all.h dolists.h
 ../src_plugins/vendordrill/vendor.o: ../src_plugins/vendordrill/vendor.c \
  ../config.h conf_core.h conf.h global_typedefs.h pcb_bool.h unit.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -2735,11 +3060,11 @@
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h board.h \
- font.h box.h math_helper.h move.h misc_util.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h draw.h error.h undo.h \
- ../src_plugins/vendordrill/vendor.h stub_vendor.h plugins.h \
- action_helper.h hid_flags.h hid_actions.h hid_cfg.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h board.h font.h box.h math_helper.h move.h misc_util.h \
+ data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h \
+ error.h undo.h ../src_plugins/vendordrill/vendor.h stub_vendor.h \
+ plugins.h action_helper.h hid_flags.h hid_actions.h hid_cfg.h \
  ../src_plugins/vendordrill/vendor_conf.h conf.h compat_misc.h \
  compat_nls.h obj_pinvia.h event.h ../src_3rd/liblihata/tree.h dolists.h \
  ../src_plugins/vendordrill/vendor_conf_fields.h
@@ -2848,6 +3173,8 @@
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  ../src_3rd/liblihata/dom_internal.h ../src_3rd/liblihata/tree.h \
  ../src_3rd/liblihata/dom.h
+../src_3rd/qparse/qparse.o: ../src_3rd/qparse/qparse.c \
+ ../src_3rd/qparse/qparse.h
 action_act.o: action_act.c ../config.h action_helper.h global_typedefs.h \
  pcb_bool.h unit.h hid_actions.h hid.h error.h drc.h attrib.h layer.h \
  globalconst.h obj_all_list.h obj_arc_list.h obj_common.h \
@@ -2858,7 +3185,7 @@ action_act.o: action_act.c ../config.h action_helper.h global_typedefs.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h undo.h library.h compat_nls.h
+ obj_rat.h layer_grp.h undo.h library.h compat_nls.h
 action_helper.o: action_helper.c ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -2875,14 +3202,15 @@ action_helper.o: action_helper.c ../config.h conf_core.h conf.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h change.h copy.h data.h \
- crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h find.h \
- insert.h polygon.h rtree.h remove.h rotate.h search.h rats.h netlist.h \
- route_style.h select.h operation.h undo.h stub_stroke.h funchash_core.h \
- funchash.h funchash_core_list.h hid_actions.h compat_misc.h compat_nls.h \
- event.h obj_pinvia_draw.h obj_pad_draw.h obj_line_draw.h obj_arc_draw.h \
- obj_elem_draw.h obj_text_draw.h obj_rat_draw.h obj_poly_draw.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h change.h \
+ copy.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
+ draw.h find.h insert.h polygon.h rtree.h remove.h rotate.h search.h \
+ rats.h netlist.h route_style.h select.h operation.h undo.h stub_stroke.h \
+ funchash_core.h funchash.h funchash_core_list.h hid_actions.h \
+ compat_misc.h compat_nls.h event.h obj_pinvia_draw.h obj_pad_draw.h \
+ obj_line_draw.h obj_arc_draw.h obj_elem_draw.h obj_text_draw.h \
+ obj_rat_draw.h obj_poly_draw.h
 attrib.o: attrib.c ../config.h compat_misc.h attrib.h
 board.o: board.c ../config.h board.h const.h macro.h global_typedefs.h \
  pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -2896,14 +3224,14 @@ board.o: board.c ../config.h board.h const.h macro.h global_typedefs.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
  ../src_3rd/genvector/vtp0.h list_conf.h plug_io.h compat_misc.h \
- hid_actions.h paths.h rtree.h undo.h draw.h event.h
+ hid_actions.h paths.h rtree.h undo.h draw.h event.h defpcb_internal.c
 box.o: box.c ../config.h rotate.h global_typedefs.h pcb_bool.h unit.h \
  box.h math_helper.h macro.h move.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
@@ -2924,11 +3252,11 @@ buffer.o: buffer.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h copy.h data.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h plug_io.h polygon.h rtree.h rotate.h \
- remove.h select.h operation.h draw.h undo.h funchash_core.h funchash.h \
- funchash_core_list.h compat_misc.h compat_nls.h obj_all_op.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h copy.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h plug_io.h polygon.h rtree.h \
+ rotate.h remove.h select.h operation.h draw.h undo.h funchash_core.h \
+ funchash.h funchash_core_list.h compat_misc.h compat_nls.h obj_all_op.h \
  obj_arc_op.h obj_elem_op.h obj_line_op.h obj_pad_op.h obj_pinvia_op.h \
  obj_poly_op.h obj_text_op.h obj_rat_op.h
 build_run.o: build_run.c ../config.h ../src_3rd/genvector/gds_char.h \
@@ -2947,9 +3275,9 @@ build_run.o: build_run.c ../config.h ../src_3rd/genvector/gds_char.h \
  obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h library.h \
- rats_patch.h font.h box.h math_helper.h move.h misc_util.h build_run.h \
- hid_init.h hid.h error.h drc.h plug_io.h compat_misc.h
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ library.h rats_patch.h font.h box.h math_helper.h move.h misc_util.h \
+ build_run.h hid_init.h hid.h error.h drc.h plug_io.h compat_misc.h
 buildin.o: buildin.c plugins.h buildin.h
 change.o: change.c ../config.h conf_core.h conf.h global_typedefs.h \
  pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
@@ -2967,12 +3295,12 @@ change.o: change.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h draw.h select.h operation.h undo.h \
- hid_actions.h compat_nls.h obj_all_op.h obj_arc_op.h obj_elem_op.h \
- obj_line_op.h obj_pad_op.h obj_pinvia_op.h obj_poly_op.h obj_text_op.h \
- obj_rat_op.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h select.h \
+ operation.h undo.h hid_actions.h compat_nls.h obj_all_op.h obj_arc_op.h \
+ obj_elem_op.h obj_line_op.h obj_pad_op.h obj_pinvia_op.h obj_poly_op.h \
+ obj_text_op.h obj_rat_op.h
 change_act.o: change_act.c ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -2989,13 +3317,13 @@ change_act.o: change_act.c ../config.h conf_core.h conf.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h funchash_core.h funchash.h \
- funchash_core_list.h board.h const.h macro.h vtroutestyle.h library.h \
- rats_patch.h font.h box.h math_helper.h move.h misc_util.h \
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h funchash_core.h \
+ funchash.h funchash_core_list.h board.h const.h macro.h vtroutestyle.h \
+ library.h rats_patch.h font.h box.h math_helper.h move.h misc_util.h \
  action_helper.h hid_actions.h change.h draw.h search.h rats.h netlist.h \
  route_style.h undo.h event.h compat_misc.h compat_nls.h obj_rat_draw.h
 clip.o: clip.c ../config.h clip.h global_typedefs.h pcb_bool.h unit.h
-compat_dl.o: compat_dl.c ../config.h compat_dl.h compat_inc.h
+compat_dl.o: compat_dl.c ../config.h compat_dl.h compat_inc.h compat_cc.h
 compat_fs.o: compat_fs.c ../config.h compat_inc.h compat_fs.h \
  compat_misc.h compat_nls.h globalconst.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3028,8 +3356,8 @@ conf_act.o: conf_act.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h conf_core.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h conf_core.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3074,11 +3402,11 @@ copy.o: copy.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h draw.h select.h operation.h undo.h \
- obj_all_op.h obj_arc_op.h obj_elem_op.h obj_line_op.h obj_pad_op.h \
- obj_pinvia_op.h obj_poly_op.h obj_text_op.h obj_rat_op.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h select.h \
+ operation.h undo.h obj_all_op.h obj_arc_op.h obj_elem_op.h obj_line_op.h \
+ obj_pad_op.h obj_pinvia_op.h obj_poly_op.h obj_text_op.h obj_rat_op.h
 crosshair.o: crosshair.c ../config.h conf_core.h conf.h global_typedefs.h \
  pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3095,12 +3423,12 @@ crosshair.o: crosshair.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h crosshair.h vtonpoint.h hid.h \
- error.h drc.h data.h buffer.h draw.h search.h rats.h netlist.h \
- route_style.h polygon.h rtree.h hid_actions.h compat_misc.h compat_nls.h \
- find.h undo.h event.h action_helper.h obj_line_draw.h obj_arc_draw.h \
- obj_arc_ui.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h crosshair.h \
+ vtonpoint.h hid.h error.h drc.h data.h buffer.h draw.h search.h rats.h \
+ netlist.h route_style.h polygon.h rtree.h hid_actions.h compat_misc.h \
+ compat_nls.h find.h undo.h event.h action_helper.h obj_line_draw.h \
+ obj_arc_draw.h obj_arc_ui.h
 data.o: data.c ../config.h board.h const.h macro.h global_typedefs.h \
  pcb_bool.h unit.h vtroutestyle.h attrib.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3113,9 +3441,9 @@ data.o: data.c ../config.h board.h const.h macro.h global_typedefs.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- rtree.h list_common.h obj_all.h
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h rtree.h list_common.h obj_all.h layer_it.h
 draw.o: draw.c ../config.h conf_core.h conf.h global_typedefs.h \
  pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3132,12 +3460,12 @@ draw.o: draw.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h \
- drc.h buffer.h draw.h rotate.h rtree.h stub_draw_fab.h obj_all.h \
- layer_ui.h obj_pad_draw.h obj_pinvia_draw.h obj_elem_draw.h \
- obj_line_draw.h obj_arc_draw.h obj_rat_draw.h obj_poly_draw.h \
- obj_text_draw.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h move.h misc_util.h data.h crosshair.h \
+ vtonpoint.h hid.h error.h drc.h buffer.h draw.h rotate.h rtree.h \
+ stub_draw_fab.h stub_draw_csect.h obj_all.h layer_ui.h obj_pad_draw.h \
+ obj_pinvia_draw.h obj_elem_draw.h obj_line_draw.h obj_arc_draw.h \
+ obj_rat_draw.h obj_poly_draw.h obj_text_draw.h
 error.o: error.c ../config.h data.h globalconst.h global_typedefs.h \
  pcb_bool.h unit.h layer.h attrib.h obj_all_list.h obj_arc_list.h \
  obj_common.h ../src_3rd/liblihata/genht/hash.h \
@@ -3149,13 +3477,13 @@ error.o: error.c ../config.h data.h globalconst.h global_typedefs.h \
  ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
  vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- plug_io.h library.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h compat_misc.h compat_nls.h \
- conf_core.h
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h plug_io.h library.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ compat_misc.h compat_nls.h conf_core.h
 event.o: event.c ../config.h event.h unit.h error.h fptr_cast.h
 file_act.o: file_act.c ../config.h board.h const.h macro.h \
  global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -3169,8 +3497,8 @@ file_act.o: file_act.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h build_run.h conf_core.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h build_run.h conf_core.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3195,14 +3523,14 @@ find.o: find.c ../config.h const.h math_helper.h conf_core.h conf.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h draw.h find.h rtree.h polygon.h \
- search.h rats.h netlist.h library.h route_style.h vtroutestyle.h \
- misc_util.h undo.h plug_io.h hid_actions.h compat_misc.h event.h \
- layer_vis.h obj_all.h find_geo.c macro.h find_lookup.c compat_nls.h \
- board.h rats_patch.h font.h box.h move.h find_drc.c obj_arc_draw.h \
- obj_pad_draw.h obj_rat_draw.h obj_line_draw.h obj_elem_draw.h \
- obj_poly_draw.h obj_pinvia_draw.h find_misc.c find_clear.c find_debug.c \
- find_print.c
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h draw.h find.h \
+ rtree.h polygon.h search.h rats.h netlist.h library.h route_style.h \
+ vtroutestyle.h misc_util.h undo.h plug_io.h hid_actions.h compat_misc.h \
+ event.h layer_vis.h obj_all.h find_geo.c macro.h find_lookup.c \
+ compat_nls.h board.h rats_patch.h font.h box.h move.h find_drc.c \
+ obj_arc_draw.h obj_pad_draw.h obj_rat_draw.h obj_line_draw.h \
+ obj_elem_draw.h obj_poly_draw.h obj_pinvia_draw.h find_misc.c \
+ find_clear.c find_debug.c find_print.c
 find_act.o: find_act.c ../config.h board.h const.h macro.h \
  global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3215,8 +3543,8 @@ find_act.o: find_act.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h conf_core.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h conf_core.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3238,12 +3566,13 @@ font.o: font.c ../config.h font.h global_typedefs.h pcb_bool.h unit.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
- error.h plug_io.h paths.h compat_nls.h
+ obj_rat.h layer_grp.h library.h rats_patch.h conf_core.h conf.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h error.h plug_io.h paths.h \
+ compat_nls.h font_internal.c
 fptr_cast.o: fptr_cast.c ../config.h fptr_cast.h
 free_atexit.o: free_atexit.c ../config.h
 funchash.o: funchash.c ../src_3rd/liblihata/genht/htpi.h \
@@ -3262,8 +3591,8 @@ gui_act.o: gui_act.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h build_run.h conf_core.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h build_run.h conf_core.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3290,8 +3619,8 @@ hid_actions.o: hid_actions.c ../config.h conf_core.h conf.h \
  flag.h obj_arc.h obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
- polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h compat_misc.h \
- compat_nls.h
+ polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h \
+ compat_misc.h compat_nls.h
 hid_attrib.o: hid_attrib.c ../config.h hid_attrib.h hid.h error.h drc.h \
  unit.h global_typedefs.h pcb_bool.h attrib.h layer.h globalconst.h \
  obj_all_list.h obj_arc_list.h obj_common.h \
@@ -3302,8 +3631,8 @@ hid_attrib.o: hid_attrib.c ../config.h hid_attrib.h hid.h error.h drc.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h misc_util.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/genvector/genvector_impl.h \
+ obj_rat.h layer_grp.h misc_util.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h
 hid_cfg.o: hid_cfg.c ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/tree.h ../src_3rd/liblihata/dom.h \
@@ -3326,7 +3655,7 @@ hid_cfg_action.o: hid_cfg_action.c ../config.h hid_cfg_action.h hid_cfg.h \
  obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
  obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h
+ obj_rat.h layer_grp.h
 hid_cfg_input.o: hid_cfg_input.c ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/tree.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
@@ -3347,7 +3676,7 @@ hid_color.o: hid_color.c ../config.h hid_color.h hid.h error.h drc.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h compat_misc.h ../src_3rd/liblihata/genht/ht.c
+ obj_rat.h layer_grp.h compat_misc.h ../src_3rd/liblihata/genht/ht.c
 hid_draw_helpers.o: hid_draw_helpers.c ../config.h hid.h error.h drc.h \
  unit.h global_typedefs.h pcb_bool.h attrib.h layer.h globalconst.h \
  obj_all_list.h obj_arc_list.h obj_common.h \
@@ -3358,7 +3687,7 @@ hid_draw_helpers.o: hid_draw_helpers.c ../config.h hid.h error.h drc.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h polygon.h rtree.h math_helper.h macro.h
+ obj_rat.h layer_grp.h polygon.h rtree.h math_helper.h macro.h
 hid_extents.o: hid_extents.c ../config.h board.h const.h macro.h \
  global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3371,9 +3700,9 @@ hid_extents.o: hid_extents.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- hid_draw_helpers.h hid_extents.h
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h hid_draw_helpers.h hid_extents.h
 hid_flags.o: hid_flags.c ../config.h data.h globalconst.h \
  global_typedefs.h pcb_bool.h unit.h layer.h attrib.h obj_all_list.h \
  obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
@@ -3385,9 +3714,9 @@ hid_flags.o: hid_flags.c ../config.h data.h globalconst.h \
  ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
  vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- board.h const.h macro.h vtroutestyle.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h board.h const.h macro.h vtroutestyle.h library.h rats_patch.h \
+ font.h box.h math_helper.h move.h misc_util.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3405,9 +3734,14 @@ hid_helper.o: hid_helper.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- hid_helper.h hid_attrib.h compat_misc.h
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h hid_helper.h hid_attrib.h compat_misc.h plug_io.h conf.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h
 hid_init.o: hid_init.c ../config.h hid.h error.h drc.h unit.h \
  global_typedefs.h pcb_bool.h attrib.h layer.h globalconst.h \
  obj_all_list.h obj_arc_list.h obj_common.h \
@@ -3418,8 +3752,8 @@ hid_init.o: hid_init.c ../config.h hid.h error.h drc.h unit.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h hid_nogui.h compat_dl.h compat_inc.h plugins.h hid_attrib.h \
- hid_init.h misc_util.h conf_core.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h hid_nogui.h compat_dl.h compat_inc.h plugins.h \
+ hid_attrib.h hid_init.h misc_util.h conf_core.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
@@ -3436,8 +3770,9 @@ hid_nogui.o: hid_nogui.c ../config.h hid.h error.h drc.h unit.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h compat_misc.h compat_nls.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
+ obj_rat.h layer_grp.h compat_misc.h compat_nls.h conf_core.h conf.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3467,10 +3802,10 @@ insert.o: insert.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h select.h operation.h undo.h obj_line_op.h \
- obj_arc_op.h obj_rat_op.h obj_poly_op.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h select.h \
+ operation.h undo.h obj_line_op.h obj_arc_op.h obj_rat_op.h obj_poly_op.h
 intersect.o: intersect.c ../config.h intersect.h global_typedefs.h \
  pcb_bool.h unit.h box.h math_helper.h macro.h move.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
@@ -3487,14 +3822,29 @@ layer.o: layer.c ../config.h board.h const.h macro.h global_typedefs.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h hid_actions.h compat_misc.h \
- undo.h event.h layer_ui.h
+ ../src_3rd/genvector/vtp0.h list_conf.h compat_misc.h undo.h event.h \
+ layer_ui.h
+layer_grp.o: layer_grp.c ../config.h board.h const.h macro.h \
+ global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
+ ../src_3rd/genvector/genvector_impl.h \
+ ../src_3rd/genvector/genvector_undef.h layer.h globalconst.h \
+ obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h compat_misc.h event.h
 layer_ui.o: layer_ui.c ../config.h layer_ui.h layer.h globalconst.h \
  global_typedefs.h pcb_bool.h unit.h attrib.h obj_all_list.h \
  obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
@@ -3520,9 +3870,9 @@ layer_vis.o: layer_vis.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
@@ -3552,8 +3902,8 @@ main.o: main.c ../config.h board.h const.h macro.h global_typedefs.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h error.h plug_io.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h error.h plug_io.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3573,7 +3923,7 @@ main_act.o: main_act.c ../config.h hid_actions.h hid.h error.h drc.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h hid_init.h conf_core.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h hid_init.h conf_core.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
@@ -3599,12 +3949,12 @@ move.o: move.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h draw.h select.h operation.h undo.h event.h \
- hid_actions.h compat_misc.h obj_all_op.h obj_arc_op.h obj_elem_op.h \
- obj_line_op.h obj_pad_op.h obj_pinvia_op.h obj_poly_op.h obj_text_op.h \
- obj_rat_op.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h select.h \
+ operation.h undo.h event.h hid_actions.h compat_misc.h obj_all_op.h \
+ obj_arc_op.h obj_elem_op.h obj_line_op.h obj_pad_op.h obj_pinvia_op.h \
+ obj_poly_op.h obj_text_op.h obj_rat_op.h
 netlist.o: netlist.c ../config.h board.h const.h macro.h \
  global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3617,8 +3967,8 @@ netlist.o: netlist.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h error.h plug_io.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h error.h plug_io.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3637,14 +3987,15 @@ netlist_act.o: netlist_act.c ../config.h ../src_3rd/genregex/regex_sei.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
  obj_rat.h crosshair.h vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- board.h const.h macro.h vtroutestyle.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h plug_io.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
- hid_actions.h compat_nls.h compat_misc.h netlist.h route_style.h
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h board.h const.h macro.h vtroutestyle.h library.h rats_patch.h \
+ font.h box.h math_helper.h move.h misc_util.h plug_io.h conf.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h hid_actions.h compat_nls.h \
+ compat_misc.h netlist.h route_style.h
 obj_any.o: obj_any.c ../config.h obj_any.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
  globalconst.h attrib.h global_typedefs.h pcb_bool.h unit.h \
@@ -3662,14 +4013,15 @@ obj_arc.o: obj_arc.c ../config.h compat_nls.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- polygon.h rtree.h undo.h rotate.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
- compat_misc.h obj_arc_op.h operation.h draw.h obj_arc_draw.h
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h polygon.h rtree.h undo.h rotate.h conf_core.h conf.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h compat_misc.h obj_arc_op.h \
+ operation.h draw.h obj_arc_draw.h
 obj_arc_list.o: obj_arc_list.c obj_arc_list.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
  globalconst.h ../config.h attrib.h global_typedefs.h pcb_bool.h unit.h \
@@ -3688,7 +4040,7 @@ obj_arc_ui.o: obj_arc_ui.c ../config.h obj_arc_ui.h crosshair.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h box.h math_helper.h macro.h move.h misc_util.h
+ obj_rat.h layer_grp.h box.h math_helper.h macro.h move.h misc_util.h
 obj_common.o: obj_common.c ../config.h conf_core.h conf.h \
  global_typedefs.h pcb_bool.h unit.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -3705,7 +4057,7 @@ obj_common.o: obj_common.c ../config.h conf_core.h conf.h \
  obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h obj_pinvia_list.h \
  obj_pinvia.h obj_text.h ht_element.h ../src_3rd/liblihata/genht/ht.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h
+ obj_rat.h layer_grp.h
 obj_elem.o: obj_elem.c ../config.h board.h const.h macro.h \
  global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3718,9 +4070,9 @@ obj_elem.o: obj_elem.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- list_common.h plug_io.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h list_common.h plug_io.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3750,10 +4102,10 @@ obj_line.o: obj_line.c ../config.h undo.h library.h global_typedefs.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h rats_patch.h font.h box.h math_helper.h move.h misc_util.h \
- data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h search.h \
- rats.h netlist.h route_style.h polygon.h rtree.h conf_core.h conf.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h rats_patch.h font.h box.h math_helper.h move.h \
+ misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
+ search.h rats.h netlist.h route_style.h polygon.h rtree.h conf_core.h \
+ conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
@@ -3776,9 +4128,9 @@ obj_line_drcenf.o: obj_line_drcenf.c ../config.h conf_core.h conf.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h \
- drc.h buffer.h find.h rtree.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h move.h misc_util.h data.h crosshair.h \
+ vtonpoint.h hid.h error.h drc.h buffer.h find.h rtree.h
 obj_line_list.o: obj_line_list.c obj_line_list.h obj_line.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
  globalconst.h ../config.h attrib.h global_typedefs.h pcb_bool.h unit.h \
@@ -3796,14 +4148,15 @@ obj_pad.o: obj_pad.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- undo.h polygon.h rtree.h compat_misc.h conf_core.h conf.h pcb-printf.h \
- ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
- ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
- ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
- obj_pad_op.h operation.h draw.h obj_text_draw.h obj_pad_draw.h
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h undo.h polygon.h rtree.h compat_misc.h conf_core.h conf.h \
+ pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
+ ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
+ ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
+ ../src_3rd/genvector/vtp0.h list_conf.h obj_pad_op.h operation.h draw.h \
+ obj_text_draw.h obj_pad_draw.h
 obj_pad_list.o: obj_pad_list.c obj_pad_list.h obj_pad.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
  globalconst.h ../config.h attrib.h global_typedefs.h pcb_bool.h unit.h \
@@ -3821,15 +4174,15 @@ obj_pinvia.o: obj_pinvia.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- undo.h conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
- ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
- ../src_3rd/genvector/vtp0.h list_conf.h polygon.h rtree.h compat_nls.h \
- compat_misc.h stub_vendor.h rotate.h obj_pinvia_op.h operation.h draw.h \
- obj_text_draw.h obj_pinvia_draw.h
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h undo.h conf_core.h conf.h pcb-printf.h \
+ ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
+ ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/genvector/vtp0.h list_conf.h \
+ polygon.h rtree.h compat_nls.h compat_misc.h stub_vendor.h rotate.h \
+ obj_pinvia_op.h operation.h draw.h obj_text_draw.h obj_pinvia_draw.h
 obj_pinvia_list.o: obj_pinvia_list.c obj_pinvia_list.h obj_pinvia.h \
  obj_common.h ../src_3rd/liblihata/genht/hash.h \
  ../src_3rd/genlist/gendlist.h flag.h globalconst.h ../config.h attrib.h \
@@ -3848,8 +4201,8 @@ obj_pinvia_therm.o: obj_pinvia_therm.c ../config.h board.h const.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h polygon.h rtree.h obj_pinvia_therm.h
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h polygon.h rtree.h obj_pinvia_therm.h
 obj_poly.o: obj_poly.c ../config.h board.h const.h macro.h \
  global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -3862,10 +4215,10 @@ obj_poly.o: obj_poly.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- compat_nls.h undo.h polygon.h rtree.h rotate.h search.h rats.h netlist.h \
- route_style.h conf_core.h conf.h pcb-printf.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h compat_nls.h undo.h polygon.h rtree.h rotate.h search.h rats.h \
+ netlist.h route_style.h conf_core.h conf.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/dom.h ../src_3rd/liblihata/lihata.h \
  ../src_3rd/liblihata/parser.h ../src_3rd/liblihata/genht/htsp.h \
@@ -3889,9 +4242,9 @@ obj_rat.o: obj_rat.c ../config.h board.h const.h macro.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
@@ -3915,11 +4268,11 @@ obj_text.o: obj_text.c ../config.h rotate.h global_typedefs.h pcb_bool.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- compat_misc.h compat_nls.h undo.h polygon.h rtree.h obj_text_op.h \
- operation.h draw.h obj_line_draw.h obj_text_draw.h conf_core.h conf.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h compat_misc.h compat_nls.h undo.h polygon.h rtree.h \
+ obj_text_op.h operation.h draw.h obj_line_draw.h obj_text_draw.h \
+ conf_core.h conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
@@ -3945,11 +4298,12 @@ object_act.o: object_act.c ../config.h conf_core.h conf.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h board.h const.h macro.h \
- vtroutestyle.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h action_helper.h change.h undo.h event.h funchash_core.h \
- funchash.h funchash_core_list.h search.h rats.h netlist.h route_style.h \
- draw.h copy.h remove.h compat_misc.h compat_nls.h layer_vis.h
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h board.h const.h \
+ macro.h vtroutestyle.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h action_helper.h change.h undo.h event.h \
+ funchash_core.h funchash.h funchash_core_list.h search.h rats.h \
+ netlist.h route_style.h draw.h copy.h remove.h compat_misc.h \
+ compat_nls.h layer_vis.h
 paths.o: paths.c ../config.h paths.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h error.h conf_core.h conf.h \
@@ -3987,7 +4341,7 @@ plug_footprint_act.o: plug_footprint_act.c ../config.h hid.h error.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h plug_footprint.h vtlibrary.h \
+ obj_rat.h layer_grp.h plug_footprint.h vtlibrary.h \
  ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h
 plug_import.o: plug_import.c ../config.h conf_core.h conf.h \
@@ -4017,11 +4371,11 @@ plug_io.o: plug_io.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_pad_list.h obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h \
  ht_element.h ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
- vtonpoint.h hid.h error.h drc.h buffer.h plug_io.h library.h remove.h \
- paths.h rats_patch.h board.h const.h macro.h vtroutestyle.h font.h box.h \
- math_helper.h move.h misc_util.h hid_actions.h hid_flags.h plugins.h \
- event.h compat_misc.h route_style.h compat_fs.h compat_nls.h layer_vis.h \
- compat_inc.h
+ vtonpoint.h hid.h error.h drc.h layer_grp.h buffer.h plug_io.h library.h \
+ remove.h paths.h rats_patch.h board.h const.h macro.h vtroutestyle.h \
+ font.h box.h math_helper.h move.h misc_util.h hid_actions.h hid_flags.h \
+ plugins.h event.h compat_misc.h route_style.h compat_fs.h compat_nls.h \
+ layer_vis.h compat_inc.h
 plugins.o: plugins.c plugins.h ../config.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
  ../src_3rd/genvector/genvector_undef.h compat_misc.h hid.h error.h drc.h \
@@ -4034,7 +4388,7 @@ plugins.o: plugins.c plugins.h ../config.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h
+ obj_rat.h layer_grp.h
 polygon.o: polygon.c ../config.h conf_core.h conf.h global_typedefs.h \
  pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -4051,11 +4405,11 @@ polygon.o: polygon.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h draw.h polygon.h rtree.h remove.h search.h \
- rats.h netlist.h route_style.h obj_pinvia_therm.h undo.h compat_nls.h \
- obj_all.h obj_poly_draw.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h polygon.h \
+ rtree.h remove.h search.h rats.h netlist.h route_style.h \
+ obj_pinvia_therm.h undo.h compat_nls.h obj_all.h obj_poly_draw.h
 polygon1.o: polygon1.c ../config.h rtree.h global_typedefs.h pcb_bool.h \
  unit.h math_helper.h heap.h compat_cc.h pcb-printf.h \
  ../src_3rd/genvector/gds_char.h ../src_3rd/genvector/genvector_impl.h \
@@ -4078,11 +4432,11 @@ polygon_act.o: polygon_act.c ../config.h conf_core.h conf.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h action_helper.h undo.h funchash_core.h \
- funchash.h funchash_core_list.h polygon.h rtree.h draw.h search.h rats.h \
- netlist.h route_style.h compat_nls.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h \
+ undo.h funchash_core.h funchash.h funchash_core_list.h polygon.h rtree.h \
+ draw.h search.h rats.h netlist.h route_style.h compat_nls.h
 rats.o: rats.c ../config.h conf_core.h conf.h global_typedefs.h \
  pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -4099,11 +4453,11 @@ rats.o: rats.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h draw.h find.h polygon.h rtree.h rats.h \
- netlist.h route_style.h search.h undo.h stub_mincut.h compat_misc.h \
- compat_nls.h vtptr.h obj_rat_draw.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h find.h \
+ polygon.h rtree.h rats.h netlist.h route_style.h search.h undo.h \
+ stub_mincut.h compat_misc.h compat_nls.h vtptr.h obj_rat_draw.h
 rats_act.o: rats_act.c ../config.h conf_core.h conf.h global_typedefs.h \
  pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -4120,11 +4474,11 @@ rats_act.o: rats_act.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h action_helper.h undo.h find.h remove.h \
- funchash_core.h funchash.h funchash_core_list.h compat_nls.h rats.h \
- netlist.h route_style.h draw.h obj_rat_draw.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h \
+ undo.h find.h remove.h funchash_core.h funchash.h funchash_core_list.h \
+ compat_nls.h rats.h netlist.h route_style.h draw.h obj_rat_draw.h
 rats_patch.o: rats_patch.c rats_patch.h board.h ../config.h const.h \
  macro.h global_typedefs.h pcb_bool.h unit.h vtroutestyle.h attrib.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -4137,10 +4491,10 @@ rats_patch.o: rats_patch.c rats_patch.h board.h ../config.h const.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h font.h box.h math_helper.h move.h misc_util.h \
- ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h data.h \
- crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h copy.h \
- compat_misc.h compat_nls.h
+ obj_rat.h layer_grp.h library.h font.h box.h math_helper.h move.h \
+ misc_util.h ../src_3rd/liblihata/genht/htsp.h \
+ ../src_3rd/liblihata/genht/ht.h data.h crosshair.h vtonpoint.h hid.h \
+ error.h drc.h buffer.h copy.h compat_misc.h compat_nls.h
 remove.o: remove.c ../config.h conf_core.h conf.h global_typedefs.h \
  pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -4157,11 +4511,11 @@ remove.o: remove.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h draw.h hid.h error.h drc.h \
- remove.h select.h operation.h undo.h obj_all_op.h obj_arc_op.h \
- obj_elem_op.h obj_line_op.h obj_pad_op.h obj_pinvia_op.h obj_poly_op.h \
- obj_text_op.h obj_rat_op.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h draw.h hid.h \
+ error.h drc.h remove.h select.h operation.h undo.h obj_all_op.h \
+ obj_arc_op.h obj_elem_op.h obj_line_op.h obj_pad_op.h obj_pinvia_op.h \
+ obj_poly_op.h obj_text_op.h obj_rat_op.h
 remove_act.o: remove_act.c const.h ../config.h data.h globalconst.h \
  global_typedefs.h pcb_bool.h unit.h layer.h attrib.h obj_all_list.h \
  obj_arc_list.h obj_common.h ../src_3rd/liblihata/genht/hash.h \
@@ -4173,9 +4527,9 @@ remove_act.o: remove_act.c const.h ../config.h data.h globalconst.h \
  ../src_3rd/liblihata/genht/ht_inlines.h obj_poly_list.h obj_poly.h \
  polyarea.h obj_text_list.h obj_rat_list.h obj_rat.h crosshair.h \
  vtonpoint.h ../src_3rd/genvector/genvector_impl.h \
- ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h buffer.h \
- action_helper.h remove.h board.h macro.h vtroutestyle.h library.h \
- rats_patch.h font.h box.h math_helper.h move.h misc_util.h \
+ ../src_3rd/genvector/genvector_undef.h hid.h error.h drc.h layer_grp.h \
+ buffer.h action_helper.h remove.h board.h macro.h vtroutestyle.h \
+ library.h rats_patch.h font.h box.h math_helper.h move.h misc_util.h \
  funchash_core.h funchash.h funchash_core_list.h
 rotate.o: rotate.c ../config.h board.h const.h macro.h global_typedefs.h \
  pcb_bool.h unit.h vtroutestyle.h attrib.h \
@@ -4189,9 +4543,9 @@ rotate.o: rotate.c ../config.h board.h const.h macro.h global_typedefs.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h \
- draw.h polygon.h rtree.h rotate.h search.h rats.h netlist.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
+ buffer.h draw.h polygon.h rtree.h rotate.h search.h rats.h netlist.h \
  route_style.h select.h operation.h undo.h event.h conf_core.h conf.h \
  pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
@@ -4216,9 +4570,9 @@ route_style.o: route_style.c ../config.h pcb-printf.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h funchash_core.h funchash.h \
- funchash_core_list.h conf_core.h compat_nls.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h funchash_core.h \
+ funchash.h funchash_core_list.h conf_core.h compat_nls.h
 rtree.o: rtree.c ../config.h math_helper.h compat_cc.h rtree.h \
  global_typedefs.h pcb_bool.h unit.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
@@ -4239,10 +4593,10 @@ search.o: search.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h find.h polygon.h rtree.h search.h rats.h \
- netlist.h route_style.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h find.h polygon.h \
+ rtree.h search.h rats.h netlist.h route_style.h
 select.o: select.c ../config.h conf_core.h conf.h global_typedefs.h \
  pcb_bool.h unit.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/genvector/genvector_impl.h \
@@ -4259,11 +4613,11 @@ select.o: select.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h draw.h search.h rats.h netlist.h \
- route_style.h select.h operation.h undo.h find.h compat_misc.h \
- compat_nls.h obj_elem_draw.h obj_pad_draw.h obj_arc_draw.h \
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h draw.h search.h \
+ rats.h netlist.h route_style.h select.h operation.h undo.h find.h \
+ compat_misc.h compat_nls.h obj_elem_draw.h obj_pad_draw.h obj_arc_draw.h \
  obj_pinvia_draw.h obj_line_draw.h obj_poly_draw.h obj_text_draw.h \
  obj_rat_draw.h ../src_3rd/genregex/regex_sei.h \
  ../src_3rd/genregex/regex_templ.h ../src_3rd/genregex/regex.h
@@ -4283,11 +4637,23 @@ select_act.o: select_act.c ../config.h conf_core.h conf.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h action_helper.h undo.h funchash_core.h \
- funchash.h funchash_core_list.h select.h operation.h draw.h remove.h \
- copy.h hid_attrib.h compat_misc.h compat_nls.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h \
+ undo.h funchash_core.h funchash.h funchash_core_list.h select.h \
+ operation.h draw.h remove.h copy.h hid_attrib.h compat_misc.h \
+ compat_nls.h
+stub_draw_csect.o: stub_draw_csect.c ../config.h stub_draw_csect.h hid.h \
+ error.h drc.h unit.h global_typedefs.h pcb_bool.h attrib.h layer.h \
+ globalconst.h obj_all_list.h obj_arc_list.h obj_common.h \
+ ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
+ obj_arc.h ../src_3rd/genlist/gentdlist_impl.h \
+ ../src_3rd/genlist/gendlist.h ../src_3rd/genlist/gentdlist_undef.h \
+ obj_elem_list.h obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h \
+ obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
+ ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
+ obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
+ obj_rat.h layer_grp.h obj_text_draw.h
 stub_draw_fab.o: stub_draw_fab.c ../config.h stub_draw_fab.h hid.h \
  error.h drc.h unit.h global_typedefs.h pcb_bool.h attrib.h layer.h \
  globalconst.h obj_all_list.h obj_arc_list.h obj_common.h \
@@ -4298,7 +4664,7 @@ stub_draw_fab.o: stub_draw_fab.c ../config.h stub_draw_fab.h hid.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h obj_text_draw.h
+ obj_rat.h layer_grp.h obj_text_draw.h
 stub_mincut.o: stub_mincut.c ../config.h stub_mincut.h global_typedefs.h \
  pcb_bool.h unit.h obj_pinvia.h obj_common.h \
  ../src_3rd/liblihata/genht/hash.h ../src_3rd/genlist/gendlist.h flag.h \
@@ -4318,11 +4684,11 @@ undo.o: undo.c ../config.h board.h const.h macro.h global_typedefs.h \
  obj_pad.h obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h ../src_3rd/liblihata/genht/ht_inlines.h \
  obj_poly_list.h obj_poly.h polyarea.h obj_text_list.h obj_rat_list.h \
- obj_rat.h library.h rats_patch.h font.h box.h math_helper.h move.h \
- misc_util.h change.h data.h crosshair.h vtonpoint.h hid.h error.h drc.h \
- buffer.h draw.h insert.h polygon.h rtree.h remove.h rotate.h search.h \
- rats.h netlist.h route_style.h undo.h flag_str.h conf_core.h conf.h \
- pcb-printf.h ../src_3rd/genvector/gds_char.h \
+ obj_rat.h layer_grp.h library.h rats_patch.h font.h box.h math_helper.h \
+ move.h misc_util.h change.h data.h crosshair.h vtonpoint.h hid.h error.h \
+ drc.h buffer.h draw.h insert.h polygon.h rtree.h remove.h rotate.h \
+ search.h rats.h netlist.h route_style.h undo.h flag_str.h conf_core.h \
+ conf.h pcb-printf.h ../src_3rd/genvector/gds_char.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/dom.h \
  ../src_3rd/liblihata/lihata.h ../src_3rd/liblihata/parser.h \
  ../src_3rd/liblihata/genht/htsp.h ../src_3rd/liblihata/genht/ht.h \
@@ -4344,11 +4710,11 @@ undo_act.o: undo_act.c ../config.h conf_core.h conf.h global_typedefs.h \
  obj_elem.h obj_line_list.h obj_line.h obj_pad_list.h obj_pad.h \
  obj_pinvia_list.h obj_pinvia.h obj_text.h ht_element.h \
  ../src_3rd/liblihata/genht/ht.h obj_poly_list.h obj_poly.h polyarea.h \
- obj_text_list.h obj_rat_list.h obj_rat.h library.h rats_patch.h font.h \
- box.h math_helper.h move.h misc_util.h data.h crosshair.h vtonpoint.h \
- hid.h error.h drc.h buffer.h action_helper.h funchash_core.h funchash.h \
- funchash_core_list.h undo.h polygon.h rtree.h search.h rats.h netlist.h \
- route_style.h obj_line_draw.h
+ obj_text_list.h obj_rat_list.h obj_rat.h layer_grp.h library.h \
+ rats_patch.h font.h box.h math_helper.h move.h misc_util.h data.h \
+ crosshair.h vtonpoint.h hid.h error.h drc.h buffer.h action_helper.h \
+ funchash_core.h funchash.h funchash_core_list.h undo.h polygon.h rtree.h \
+ search.h rats.h netlist.h route_style.h obj_line_draw.h
 unit.o: unit.c ../config.h compat_misc.h compat_nls.h unit.h
 vtlibrary.o: vtlibrary.c vtlibrary.h \
  ../src_3rd/genvector/genvector_impl.h \
diff --git a/src/Makefile.in b/src/Makefile.in
index 130002e..16259be 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -69,6 +69,7 @@ put /local/pcb/OBJS [@
 	insert.o
 	intersect.o
 	layer.o
+	layer_grp.o
 	layer_ui.o
 	layer_vis.o
 	library.o
@@ -122,6 +123,7 @@ put /local/pcb/OBJS [@
 	search.o
 	select.o
 	select_act.o
+	stub_draw_csect.o
 	stub_draw_fab.o
 	stub_mincut.o
 	stub_stroke.o
@@ -159,6 +161,12 @@ put /local/pcb/OBJS [@
 	../src_3rd/genregex/regex_sei.o
 	../src_3rd/genregex/regex_se.o
 	../src_3rd/genregex/regex.o
+	../src_3rd/qparse/qparse.o
+@]
+
+# We do not compile these in the executable but we need rules for these for utils
+put /local/pcb/OBJS_UTIL [@
+	../src_3rd/genvector/vts0.o
 @]
 
 # main: action registrations
@@ -203,9 +211,11 @@ append /local/pcb/LIBS    /target/libs/sul/dmalloc/ldflags
 
 # ---- logic ----
 
+
 # Clean up variables
 uniq /local/pcb/OBJS
 uniq /local/pcb/OBJS_C99
+uniq /local/pcb/OBJS_UTIL
 uniq /local/pcb/CFLAGS
 uniq /local/pcb/LDFLAGS
 uniq /local/pcb/LIBS
@@ -225,20 +235,23 @@ print [@
 # This file has been generated from Makefile.in by configure
 # *** DO NOT EDIT THIS FILE ***
 
+ROOT=..
+
 # plugin source
-PLUGDIR=../src_plugins
+PLUGDIR=$(ROOT)/src_plugins
 
 # plugin source install - so that pcb-rnd runs from source properly
 PLUGIDIR=plugins
 
 # src_3rd dir for the lib_ wrapper plugins
-SRC_3RD_DIR=../src_3rd
+SRC_3RD_DIR=$(ROOT)/src_3rd
 
 @/local/pcb/TOPVARS@
 OBJS=@/local/pcb/OBJS@
 OBJS_C99=@/local/pcb/OBJS_C99@
+OBJS_UTIL=@/local/pcb/OBJS_UTIL@
 SRCS=@/local/pcb/SRCS@
-CFLAGS=@/local/pcb/CFLAGS@
+CFLAGS=@?cc/argstd/std_c99@ @/local/pcb/CFLAGS@
 C89FLAGS=@/local/pcb/c89flags@ @/local/pcb/CFLAGS@
 LDFLAGS=@/local/pcb/LDFLAGS@
 LIBS=@/local/pcb/LIBS@ -lm @?/target/libs/ldl@
@@ -246,18 +259,18 @@ EXEDEPS=@/local/pcb/EXEDEPS@
 CLEANFILES=@/local/pcb/CLEANFILES@
 CLEANRULES=@/local/pcb/CLEANRULES@
 CC=@cc/cc@
-CQUOTE=../scconfig/cquote
-SPHASH_PATH=../src_3rd/sphash
+CQUOTE=$(ROOT)/scconfig/cquote
+SPHASH_PATH=$(ROOT)/src_3rd/sphash
 SPHASH=$(SPHASH_PATH)/sphash
 
 all:
 	$(MAKE) revcheck
 	$(MAKE) all_exe
 
-include ../Makefile.conf
+include $(ROOT)/Makefile.conf
 
 revcheck:
-	cd ../scconfig && ./revtest Rev.stamp < Rev.tab
+	cd $(ROOT)/scconfig && ./revtest Rev.stamp < Rev.tab
 
 all_exe: pcb-rnd$(EXE) @/local/pcb/all@
 
@@ -285,7 +298,6 @@ pcblib_DATA= \
 
 
 EXTRA_DIST= \
-	check_icon.data \
 	default_font \
 	default.pcb \
 	pcbtest.sh.in
@@ -293,49 +305,52 @@ EXTRA_DIST= \
 all-local: pcbtest.sh
 
 generated_lists.h: @/local/pcb/ACTION_REG_SRC@ Makefile
-	AWK=@/host/fstools/awk@ ../scconfig/gen_core_lists.sh @/local/pcb/ACTION_REG_SRC@ > generated_lists.h
+	AWK=@/host/fstools/awk@ $(ROOT)/scconfig/gen_core_lists.sh @/local/pcb/ACTION_REG_SRC@ > generated_lists.h
 
 conf_core_fields.h: conf_core.h
-	AWK=@/host/fstools/awk@ ../scconfig/gen_conf.sh ../doc/conf/tree < conf_core.h > conf_core_fields.h
+	AWK=@/host/fstools/awk@ $(ROOT)/scconfig/gen_conf.sh $(ROOT)/doc/conf/tree < conf_core.h > conf_core_fields.h
 
 conf_internal.c: pcb-conf.lht
 	$(CQUOTE) -n conf_internal < pcb-conf.lht > conf_internal.c
 
+defpcb_internal.c: default.pcb
+	$(CQUOTE) -n default_pcb_internal < default.pcb > defpcb_internal.c
+
+# do not make this automatic, most users won't need to regenerate font_internal.c
+gen_font:
+	$(ROOT)/util/devhelpers/font2c.sh < default_font > font_internal.c
+
+util_deps: $(OBJS) $(OBJS_UTIL)
+
 FORCE:
 
 
 DISTCLEANFILES = core_lists.h buildin.c compat_inc.h conf_core_fields.h conf_internal.c generated_lists.h @/local/pcb/DISTCLEANFILES@
 
 clean: $(CLEANRULES)
-	-rm pcb-rnd $(OBJS) $(OBJS_C99) $(CLEANFILES)
+	$(SCCBOX) rm -f -q  pcb-rnd $(OBJS) $(OBJS_C99) $(CLEANFILES)
 
 distclean: FORCE
-	-rm $(DISTCLEANFILES)
-
-install_:
-	$(MKDIR) $(BINDIR) $(DATADIR) $(LIBDIR) $(LIBDIR)/plugins
-	$(CPC) "`pwd`/pcb-rnd" "$(BINDIR)/pcb-rnd"
-	$(CPC) "`pwd`/default.pcb" "$(DATADIR)/default.pcb"
-	$(CPC) "`pwd`/pcb-conf.lht" "$(DATADIR)/pcb-conf.lht"
-	$(CPC) "`pwd`/pcb-menu-lesstif.lht" "$(DATADIR)/pcb-menu-lesstif.lht"
-	$(CPC) "`pwd`/pcb-menu-gtk.lht" "$(DATADIR)/pcb-menu-gtk.lht"
-	$(CPC) "`pwd`/default_font" "$(DATADIR)/default_font"@/local/pcb/rules/install_@
+	$(SCCBOX) rm -f -q  $(DISTCLEANFILES)
 
+install_all:
+	$(SCCBOX) mkdir -p "$(BINDIR)" "$(DATADIR)" "$(LIBDIR)" "$(LIBDIR)/plugins"
+	$(SCCBOX) $(HOW) "pcb-rnd" "$(BINDIR)/pcb-rnd"
+	$(SCCBOX) $(HOW) "default.pcb" "$(DATADIR)/default.pcb"
+	$(SCCBOX) $(HOW) "pcb-conf.lht" "$(DATADIR)/pcb-conf.lht"
+	$(SCCBOX) $(HOW) "pcb-menu-lesstif.lht" "$(DATADIR)/pcb-menu-lesstif.lht"
+	$(SCCBOX) $(HOW) "pcb-menu-gtk.lht" "$(DATADIR)/pcb-menu-gtk.lht"
+	$(SCCBOX) $(HOW) "default_font" "$(DATADIR)/default_font"@/local/pcb/rules/install_@
 
 install:
-	$(MAKE) install_ CPC="$(CP)"@/local/pcb/rules/install@
+	$(MAKE) install_all HOW="install -f"
 
 linstall:
-	$(MAKE) install_ CPC="$(LN)"@/local/pcb/rules/linstall@
-
+	$(MAKE) install_all HOW="linstall -f"
 
 uninstall:
-	$(RM) $(BINDIR)/pcb-rnd
-	$(RM) $(DATADIR)/default.pcb
-	$(RM) $(DATADIR)/pcb-menu-lesstif.lht
-	$(RM) $(DATADIR)/pcb-conf.lht
-	$(RM) $(DATADIR)/pcb-menu-gtk.lht
-	$(RM) $(DATADIR)/default_font@/local/pcb/rules/uninstall@
+	$(MAKE) install_all HOW="uninstall"
+
 @]
 
 # generate explicit rules for .c -> .o
@@ -343,6 +358,12 @@ put /local/comp/OBJS /local/pcb/OBJS
 put /local/comp/OBJS_C99 ?/local/pcb/OBJS_C99
 include {../scconfig/Makefile.comp.inc}
 
+print [@
+# for extern utils:@]
+
+put /local/comp/OBJS /local/pcb/OBJS_UTIL
+include {../scconfig/Makefile.comp.inc}
+
 # generate deps
 put /local/dep/CFLAGS /local/pcb/CFLAGS
 put /local/dep/SRCS /local/pcb/SRCS
diff --git a/src/action_helper.c b/src/action_helper.c
index 804bb60..bd67cde 100644
--- a/src/action_helper.c
+++ b/src/action_helper.c
@@ -776,7 +776,7 @@ void pcb_notify_mode(void)
 			}
 
 			if (conf_core.editor.auto_drc
-					&& !TEST_SILK_LAYER(CURRENT))
+					&& (pcb_layer_flags(pcb_layer_id(PCB->Data, CURRENT)) & PCB_LYT_COPPER))
 				maybe_found_flag = PCB_FLAG_FOUND;
 			else
 				maybe_found_flag = 0;
@@ -901,7 +901,7 @@ void pcb_notify_mode(void)
 					pcb_text_t *text;
 					int flag = PCB_FLAG_CLEARLINE;
 
-					if (pcb_layer_get_group(INDEXOFCURRENT) == pcb_layer_get_group(pcb_solder_silk_layer))
+					if (pcb_layer_flags(INDEXOFCURRENT) & PCB_LYT_BOTTOM)
 						flag |= PCB_FLAG_ONSOLDER;
 					if ((text = pcb_text_new(CURRENT, &PCB->Font, Note.X,
 																		Note.Y, 0, conf_core.design.text_scale, string, pcb_flag_make(flag))) != NULL) {
diff --git a/src/attrib.c b/src/attrib.c
index 8acf151..377508f 100644
--- a/src/attrib.c
+++ b/src/attrib.c
@@ -44,6 +44,9 @@ int pcb_attribute_put(pcb_attribute_list_t * list, const char *name, const char
 {
 	int i;
 
+	if ((name == NULL) || (*name == '\0'))
+		return -1;
+
 	/* If we're allowed to replace an existing attribute, see if we
 	   can.  */
 	if (replace) {
diff --git a/src/board.c b/src/board.c
index af2969e..db83f71 100644
--- a/src/board.c
+++ b/src/board.c
@@ -82,9 +82,9 @@ pcb_board_t *pcb_board_new_(pcb_bool SetDefaultNames)
 						/* this is the most useful starting point for now */
 
 	ptr->Grid = conf_core.editor.grid;
-	pcb_layer_parse_group_string(conf_core.design.groups, &ptr->LayerGroups, PCB_MAX_LAYER, 0);
 	save = PCB;
 	PCB = ptr;
+	pcb_layer_parse_group_string(conf_core.design.groups, &ptr->LayerGroups, PCB_MAX_LAYER, 0);
 	pcb_event(PCB_EVENT_ROUTE_STYLES_CHANGED, NULL);
 	PCB = save;
 
@@ -109,20 +109,40 @@ pcb_board_t *pcb_board_new_(pcb_bool SetDefaultNames)
 	return (ptr);
 }
 
-pcb_board_t *pcb_board_new(void)
+#include "defpcb_internal.c"
+
+pcb_board_t *pcb_board_new(int inhibit_events)
 {
-	pcb_board_t *old, *nw;
+	pcb_board_t *old, *nw = NULL;
 	int dpcb;
+	unsigned int inh = inhibit_events ? PCB_INHIBIT_BOARD_CHANGED : 0;
 
 	old = PCB;
-
 	PCB = NULL;
 
 	dpcb = -1;
 	pcb_io_err_inhibit_inc();
-	conf_list_foreach_path_first(dpcb, &conf_core.rc.default_pcb_file, pcb_load_pcb(__path__, NULL, pcb_false, 1 | 0x10));
+	conf_list_foreach_path_first(dpcb, &conf_core.rc.default_pcb_file, pcb_load_pcb(__path__, NULL, pcb_false, 1 | 0x10 | inh));
 	pcb_io_err_inhibit_dec();
 
+	if (dpcb != 0) { /* no default PCB in file, use embedded version */
+		FILE *f;
+		const char *tmp_fn = ".pcb-rnd.default.pcb";
+
+		/* We can parse from file only, make a temp file */
+		f = fopen(tmp_fn, "wb");
+		if (f != NULL) {
+			fwrite(default_pcb_internal, strlen(default_pcb_internal), 1, f);
+			fclose(f);
+			dpcb = pcb_load_pcb(tmp_fn, NULL, pcb_false, 1 | 0x10);
+			if (dpcb == 0)
+				pcb_message(PCB_MSG_WARNING, "Couldn't find default.pcb - using the embedded fallback\n");
+			else
+				pcb_message(PCB_MSG_ERROR, "Couldn't find default.pcb and failed to load the embedded fallback\n");
+			remove(tmp_fn);
+		}
+	}
+
 	if (dpcb == 0) {
 		nw = PCB;
 		if (nw->Filename != NULL) {
@@ -132,9 +152,6 @@ pcb_board_t *pcb_board_new(void)
 			nw->Data->loader = NULL;
 		}
 	}
-	else {
-		nw = NULL;
-	}
 
 	PCB = old;
 	return nw;
@@ -152,6 +169,7 @@ int pcb_board_new_postproc(pcb_board_t *pcb, int use_defaults)
 void pcb_colors_from_settings(pcb_board_t *ptr)
 {
 	int i;
+	pcb_layer_id_t SLayer = -1, CLayer = -1;
 
 	/* copy default settings */
 	ptr->ConnectedColor = conf_core.appearance.color.connected;
@@ -173,11 +191,16 @@ void pcb_colors_from_settings(pcb_board_t *ptr)
 		ptr->Data->Layer[i].Color = conf_core.appearance.color.layer[i];
 		ptr->Data->Layer[i].SelectedColor = conf_core.appearance.color.layer_selected[i];
 	}
-	ptr->Data->Layer[pcb_component_silk_layer].Color =
-		conf_core.editor.show_solder_side ? conf_core.appearance.color.invisible_objects : conf_core.appearance.color.element;
-	ptr->Data->Layer[pcb_component_silk_layer].SelectedColor = conf_core.appearance.color.element_selected;
-	ptr->Data->Layer[pcb_solder_silk_layer].Color = conf_core.editor.show_solder_side ? conf_core.appearance.color.element : conf_core.appearance.color.invisible_objects;
-	ptr->Data->Layer[pcb_solder_silk_layer].SelectedColor = conf_core.appearance.color.element_selected;
+
+	if (pcb_layer_list(PCB_LYT_TOP | PCB_LYT_SILK, &CLayer, 1) > 0) {
+		ptr->Data->Layer[CLayer].Color = conf_core.editor.show_solder_side ? conf_core.appearance.color.invisible_objects : conf_core.appearance.color.element;
+		ptr->Data->Layer[CLayer].SelectedColor = conf_core.appearance.color.element_selected;
+	}
+
+	if (pcb_layer_list(PCB_LYT_BOTTOM | PCB_LYT_SILK, &SLayer, 1) > 0) {
+		ptr->Data->Layer[SLayer].Color = conf_core.editor.show_solder_side ? conf_core.appearance.color.element : conf_core.appearance.color.invisible_objects;
+		ptr->Data->Layer[SLayer].SelectedColor = conf_core.appearance.color.element_selected;
+	}
 }
 
 typedef struct {
diff --git a/src/board.h b/src/board.h
index 04c40e3..42badbe 100644
--- a/src/board.h
+++ b/src/board.h
@@ -49,6 +49,7 @@ enum {
 #include "global_typedefs.h"
 #include "vtroutestyle.h"
 #include "layer.h"
+#include "layer_grp.h"
 #include "library.h"
 #include "attrib.h"
 #include "rats_patch.h"
@@ -94,7 +95,7 @@ struct pcb_board_s {
 	  IsleArea,										/* minimum poly island to retain */
 	  ThermScale;									/* scale factor used with thermals */
 	pcb_font_t Font;
-	pcb_layer_group_t LayerGroups;
+	pcb_layer_stack_t LayerGroups;
 	vtroutestyle_t RouteStyle;
 	pcb_lib_t NetlistLib[PCB_NUM_NETLISTS];
 	pcb_ratspatch_line_t *NetlistPatches, *NetlistPatchLast;
@@ -119,8 +120,9 @@ void pcb_board_free(pcb_board_t *pcb);
 /* creates a new PCB - low level */
 pcb_board_t *pcb_board_new_(pcb_bool SetDefaultNames);
 
-/* creates a new PCB - high level (uses a template board) */
-pcb_board_t *pcb_board_new(void);
+/* creates a new PCB - high level (uses a template board); does not generate
+   new board event if inhibit_events is set */
+pcb_board_t *pcb_board_new(int inhibit_events);
 
 /* Called after PCB->Data->LayerN is set.  Returns non-zero on error */
 int pcb_board_new_postproc(pcb_board_t *pcb, int use_defaults);
diff --git a/src/buffer.c b/src/buffer.c
index 074c250..5d362a2 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -45,6 +45,7 @@
 #include "compat_misc.h"
 #include "compat_nls.h"
 #include "obj_all_op.h"
+#include "layer_grp.h"
 
 /* ---------------------------------------------------------------------------
  * some local identifiers
@@ -201,7 +202,7 @@ int pcb_act_LoadFootprint(int argc, const char **argv, pcb_coord_t x, pcb_coord_
  */
 pcb_bool pcb_buffer_load_layout(pcb_buffer_t *Buffer, const char *Filename, const char *fmt)
 {
-	pcb_board_t *newPCB = pcb_board_new();
+	pcb_board_t *newPCB = pcb_board_new(1);
 
 	/* new data isn't added to the undo list */
 	if (!pcb_parse_pcb(newPCB, Filename, fmt, CFR_invalid, 0)) {
@@ -394,7 +395,7 @@ void pcb_buffer_mirror(pcb_buffer_t *Buffer)
 		pcb_message(PCB_MSG_ERROR, _("You can't mirror a buffer that has elements!\n"));
 		return;
 	}
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		pcb_layer_t *layer = Buffer->Data->Layer + i;
 		if (textlist_length(&layer->Text)) {
 			pcb_message(PCB_MSG_ERROR, _("You can't mirror a buffer that has text!\n"));
@@ -434,6 +435,7 @@ void pcb_buffer_mirror(pcb_buffer_t *Buffer)
 void pcb_buffer_flip_side(pcb_buffer_t *Buffer)
 {
 	int j, k;
+	pcb_layer_id_t SLayer = -1, CLayer = -1;
 	pcb_layergrp_id_t sgroup, cgroup;
 	pcb_layer_t swap;
 
@@ -471,27 +473,33 @@ void pcb_buffer_flip_side(pcb_buffer_t *Buffer)
 		pcb_text_flip_side(layer, text);
 	}
 	PCB_ENDALL_LOOP;
+
 	/* swap silkscreen layers */
-	swap = Buffer->Data->Layer[pcb_solder_silk_layer];
-	Buffer->Data->Layer[pcb_solder_silk_layer] = Buffer->Data->Layer[pcb_component_silk_layer];
-	Buffer->Data->Layer[pcb_component_silk_layer] = swap;
+	pcb_layer_list(PCB_LYT_BOTTOM | PCB_LYT_SILK, &SLayer, 1);
+	pcb_layer_list(PCB_LYT_TOP | PCB_LYT_SILK, &CLayer, 1);
+	assert(SLayer != -1);
+	assert(CLayer != -1);
+	swap = Buffer->Data->Layer[SLayer];
+	Buffer->Data->Layer[SLayer] = Buffer->Data->Layer[CLayer];
+	Buffer->Data->Layer[CLayer] = swap;
 
 	/* swap layer groups when balanced */
-	sgroup = pcb_layer_get_group(pcb_solder_silk_layer);
-	cgroup = pcb_layer_get_group(pcb_component_silk_layer);
-	if (PCB->LayerGroups.Number[cgroup] == PCB->LayerGroups.Number[sgroup]) {
-		for (j = k = 0; j < PCB->LayerGroups.Number[sgroup]; j++) {
+	sgroup = pcb_layer_get_group(SLayer);
+	cgroup = pcb_layer_get_group(CLayer);
+#warning layer TODO: revise this code for the generic physical layer support; move this code to layer*.c
+	if (PCB->LayerGroups.grp[cgroup].len == PCB->LayerGroups.grp[sgroup].len) {
+		for (j = k = 0; j < PCB->LayerGroups.grp[sgroup].len; j++) {
 			int t1, t2;
-			pcb_cardinal_t cnumber = PCB->LayerGroups.Entries[cgroup][k];
-			pcb_cardinal_t snumber = PCB->LayerGroups.Entries[sgroup][j];
+			pcb_layer_id_t cnumber = PCB->LayerGroups.grp[cgroup].lid[k];
+			pcb_layer_id_t snumber = PCB->LayerGroups.grp[sgroup].lid[j];
 
-			if (snumber >= pcb_max_copper_layer)
+			if ((pcb_layer_flags(snumber)) & PCB_LYT_SILK)
 				continue;
 			swap = Buffer->Data->Layer[snumber];
 
-			while (cnumber >= pcb_max_copper_layer) {
+			while ((pcb_layer_flags(cnumber)) & PCB_LYT_SILK) {
 				k++;
-				cnumber = PCB->LayerGroups.Entries[cgroup][k];
+				cnumber = PCB->LayerGroups.grp[cgroup].lid[k];
 			}
 			Buffer->Data->Layer[snumber] = Buffer->Data->Layer[cnumber];
 			Buffer->Data->Layer[cnumber] = swap;
@@ -575,7 +583,7 @@ pcb_bool pcb_buffer_copy_to_layout(pcb_coord_t X, pcb_coord_t Y)
 	ctx.copy.DeltaY = Y - PCB_PASTEBUFFER->Y;
 
 	/* paste all layers */
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		pcb_layer_t *sourcelayer = &PCB_PASTEBUFFER->Data->Layer[i], *destlayer = LAYER_PTR(i);
 
 		if (destlayer->On) {
diff --git a/src/build_run.c b/src/build_run.c
index fa9fda2..9b75125 100644
--- a/src/build_run.c
+++ b/src/build_run.c
@@ -3,6 +3,7 @@
  *
  *  PCB, interactive printed circuit board design
  *  Copyright (C) 1994,1995,1996,2006 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
  *
  *  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
@@ -34,10 +35,10 @@
 #include "plug_io.h"
 #include "compat_misc.h"
 
-/* ---------------------------------------------------------------------------
- * quits application
- */
 extern void pcb_main_uninit(void);
+/** pcb_quit_app:
+ *  Quits application
+ */
 void pcb_quit_app(void)
 {
 	/*
@@ -58,44 +59,106 @@ void pcb_quit_app(void)
 		pcb_gui->do_exit(pcb_gui);
 }
 
-/* ---------------------------------------------------------------------------
- * Returns a string that has a bunch of information about the program.
- * Can be used for things like "about" dialog boxes.
+/** pcb_get_info_program:
+ *  Returns a string that has a bunch of information about this program.
  */
-
-char *pcb_get_infostr(void)
+char *pcb_get_info_program(void)
 {
-	pcb_hid_t **hids;
-	int i;
 	static gds_t info;
 	static int first_time = 1;
 
-#define TAB "    "
-
 	if (first_time) {
 		first_time = 0;
 		gds_init(&info);
-		gds_append_str(&info, "This is PCB-rnd " VERSION " (" REVISION ")" "\n an interactive\n");
+		gds_append_str(&info, "This is PCB-rnd " VERSION " (" REVISION ")" "\n an interactive ");
 		gds_append_str(&info, "printed circuit board editor\n");
-		gds_append_str(&info, "PCB-rnd forked from gEDA/PCB.");
+		gds_append_str(&info, "pcb-rnd forked from gEDA/PCB.");
 		gds_append_str(&info, "\n\n" "PCB is by harry eaton and others\n\n");
-		gds_append_str(&info, "\nPCB-rnd adds a collection of\n");
-		gds_append_str(&info, "useful-looking random patches.\n");
-		gds_append_str(&info, "\n");
+		gds_append_str(&info, "pcb-rnd is a refactored version ");
+		gds_append_str(&info, "with many new features and improvements.\n\n");
+	}
+	return info.array;
+}
+
+/** pcb_get_info_copyright:
+ *  Returns a string that has a bunch of information about the copyrights.
+ */
+char *pcb_get_info_copyright(void)
+{
+	static gds_t info;
+	static int first_time = 1;
+
+	if (first_time) {
+		first_time = 0;
+		gds_init(&info);
 		gds_append_str(&info, "Copyright (C) Thomas Nau 1994, 1995, 1996, 1997\n");
 		gds_append_str(&info, "Copyright (C) harry eaton 1998-2007\n");
 		gds_append_str(&info, "Copyright (C) C. Scott Ananian 2001\n");
 		gds_append_str(&info, "Copyright (C) DJ Delorie 2003, 2004, 2005, 2006, 2007, 2008\n");
 		gds_append_str(&info, "Copyright (C) Dan McMahill 2003, 2004, 2005, 2006, 2007, 2008\n\n");
-		gds_append_str(&info, "Copyright (C) Tibor Palinkas 2013-2016 (pcb-rnd patches)\n\n");
-		gds_append_str(&info, "It is licensed under the terms of the GNU\n");
-		gds_append_str(&info, "General Public License version 2\n");
-		gds_append_str(&info, "See the LICENSE file for more information\n\n");
-		gds_append_str(&info, "For more information see:\n\n");
+		gds_append_str(&info, "Copyright (C) Tibor Palinkas 2013-2017 (pcb-rnd patches)");
+	}
+	return info.array;
+}
+
+/** pcb_get_info_websites:
+ *  Returns a string that has a bunch of information about the websites.
+ */
+char *pcb_get_info_websites(void)
+{
+	static gds_t info;
+	static int first_time = 1;
+
+	if (first_time) {
+		first_time = 0;
+		gds_init(&info);
+
+		gds_append_str(&info, "For more information see:\n");
 		gds_append_str(&info, "PCB-rnd homepage: http://repo.hu/projects/pcb-rnd\n");
 		gds_append_str(&info, "PCB homepage: http://pcb.geda-project.org\n");
 		gds_append_str(&info, "gEDA homepage: http://www.geda-project.org\n");
 		gds_append_str(&info, "gEDA Wiki: http://wiki.geda-project.org\n\n");
+	}
+	return info.array;
+}
+
+/** pcb_get_info_comments:
+ *  Returns a string as the concatenation of pcb_get_info_program() and pcb_get_info_websites()
+ */
+char *pcb_get_info_comments(void)
+{
+	static gds_t info;
+	static int first_time = 1;
+	char *tmp;
+
+	if (first_time) {
+		first_time = 0;
+		gds_init(&info);
+
+		tmp = pcb_get_info_program();
+		gds_append_str(&info, tmp);
+		tmp = pcb_get_info_websites();
+		gds_append_str(&info, tmp);
+	}
+	return info.array;
+}
+
+
+/** pcb_get_info_compile_options:
+ *  Returns a string that has a bunch of information about the options selected at compile time.
+ */
+char *pcb_get_info_compile_options(void)
+{
+	pcb_hid_t **hids;
+	int i;
+	static gds_t info;
+	static int first_time = 1;
+
+#define TAB "    "
+
+	if (first_time) {
+		first_time = 0;
+		gds_init(&info);
 
 		gds_append_str(&info, "----- Compile Time Options -----\n");
 		hids = pcb_hid_enumerate();
@@ -136,6 +199,37 @@ char *pcb_get_infostr(void)
 	return info.array;
 }
 
+/** pcb_get_infostr:
+ *  Returns a string that has a bunch of information about this copy of pcb.
+ *  Can be used for things like "about" dialog boxes.
+ */
+char *pcb_get_infostr(void)
+{
+	static gds_t info;
+	static int first_time = 1;
+	char *tmp;
+
+	if (first_time) {
+		first_time = 0;
+		gds_init(&info);
+
+		tmp = pcb_get_info_program();
+		gds_append_str(&info, tmp);
+		tmp = pcb_get_info_copyright();
+		gds_append_str(&info, tmp);
+		gds_append_str(&info, "\n\n");
+		gds_append_str(&info, "It is licensed under the terms of the GNU\n");
+		gds_append_str(&info, "General Public License version 2\n");
+		gds_append_str(&info, "See the LICENSE file for more information\n\n");
+		tmp = pcb_get_info_websites();
+		gds_append_str(&info, tmp);
+
+		tmp = pcb_get_info_compile_options();
+		gds_append_str(&info, tmp);
+	}
+	return info.array;
+}
+
 const char *pcb_author(void)
 {
 	if (conf_core.design.fab_author && conf_core.design.fab_author[0])
@@ -144,6 +238,9 @@ const char *pcb_author(void)
 		return pcb_get_user_name();
 }
 
+/** pcb_catch_signal:
+ *  Catches signals which abort the program.
+ */
 void pcb_catch_signal(int Signal)
 {
 	const char *s;
diff --git a/src/build_run.h b/src/build_run.h
index 6c8b8e0..a95aa47 100644
--- a/src/build_run.h
+++ b/src/build_run.h
@@ -24,14 +24,16 @@
  *
  */
 
-/* build info and run control */
-
 void pcb_quit_app(void);
 
-/* Returns a string with info about this copy of pcb. */
+char *pcb_get_info_program(void);
+char *pcb_get_info_copyright(void);
+char *pcb_get_info_websites(void);
+char *pcb_get_info_comments(void);
+char *pcb_get_info_compile_options(void);
+
 char *pcb_get_infostr(void);
 
 const char *pcb_author(void);
 
-/* catches signals which abort the program */
 void pcb_catch_signal(int Signal);
diff --git a/src/change_act.c b/src/change_act.c
index f191e16..a94a875 100644
--- a/src/change_act.c
+++ b/src/change_act.c
@@ -666,6 +666,7 @@ int pcb_act_ChangeName(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y
 					else
 						pinnum = 0;
 					if (pcb_chg_obj_name_query(type, ptr1, ptr2, ptr3, pinnum)) {
+						pcb_redraw();
 						pcb_board_set_changed_flag(pcb_true);
 						pcb_event(PCB_EVENT_RUBBER_RENAME, "ipppi", type, ptr1, ptr2, ptr3, pinnum);
 					}
diff --git a/src/check_icon.data b/src/check_icon.data
deleted file mode 100644
index f6b1f45..0000000
--- a/src/check_icon.data
+++ /dev/null
@@ -1,4 +0,0 @@
-#define check_icon_width 8
-#define check_icon_height 8
-static unsigned char check_icon_bits[] = {
-   0x80, 0xc0, 0x61, 0x31, 0x1b, 0x0f, 0x06, 0x00};
diff --git a/src/compat_dl.c b/src/compat_dl.c
index 1e4aed6..b63cf9f 100644
--- a/src/compat_dl.c
+++ b/src/compat_dl.c
@@ -23,6 +23,7 @@
 #include "config.h"
 
 #include "compat_dl.h"
+#include "compat_cc.h"
 
 #ifdef USE_LOADLIBRARY
 #include <windows.h>
@@ -50,7 +51,7 @@ char *dlerror()
 	dw = GetLastError();
 
 	/* get the corresponding error message */
-	Formatpcb_message(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+	pcb_message(FORMAT_MESSAGE_ALLOCATE_BUFFER |
 								FORMAT_MESSAGE_FROM_SYSTEM |
 								FORMAT_MESSAGE_IGNORE_INSERTS,
 								NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & lpMsgBuf, 0, NULL);
diff --git a/src/crosshair.c b/src/crosshair.c
index ac089c3..e4e6e78 100644
--- a/src/crosshair.c
+++ b/src/crosshair.c
@@ -65,6 +65,8 @@ static void XORDrawElement(pcb_element_t *, pcb_coord_t, pcb_coord_t);
 static void XORDrawBuffer(pcb_buffer_t *);
 static void XORDrawInsertPointObject(void);
 static void XORDrawAttachedArc(pcb_coord_t);
+static void XORDrawPinViaDRCOutline(pcb_pin_t * pv,pcb_coord_t clearance);
+static void XORDrawPadDRCOutline(pcb_pad_t * pv,pcb_coord_t clearance);
 
 static void thindraw_moved_pv(pcb_pin_t * pv, pcb_coord_t x, pcb_coord_t y)
 {
@@ -74,6 +76,14 @@ static void thindraw_moved_pv(pcb_pin_t * pv, pcb_coord_t x, pcb_coord_t y)
 	moved_pv.Y += y;
 
 	pcb_gui->thindraw_pcb_pv(pcb_crosshair.GC, pcb_crosshair.GC, &moved_pv, pcb_true, pcb_false);
+
+	if (conf_core.editor.show_drc) {
+		/* XXX: Naughty cheat - use the mask to draw DRC clearance! */
+		moved_pv.Mask = conf_core.design.via_thickness + PCB->Bloat * 2;
+		pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.cross);
+		XORDrawPinViaDRCOutline(&moved_pv,PCB->Bloat);
+		pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.crosshair);
+	}
 }
 
 static void draw_dashed_line(pcb_hid_gc_t GC, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2)
@@ -135,13 +145,31 @@ static void XORPolygon(pcb_polygon_t *polygon, pcb_coord_t dx, pcb_coord_t dy, i
 /*-----------------------------------------------------------
  * Draws the outline of an arc
  */
+static void XORDrawArc(pcb_arc_t * arc)
+{
+	pcb_coord_t wid = arc->Thickness / 2;
+	pcb_coord_t x1,y1,x2,y2;
+
+	pcb_arc_get_end(arc, 0, &x1, &y1);
+	pcb_arc_get_end(arc, 1, &x2, &y2);
+
+	pcb_gui->draw_arc(pcb_crosshair.GC, arc->X, arc->Y, arc->Width + wid, arc->Height + wid, arc->StartAngle, arc->Delta);
+	if (wid > pcb_pixel_slop) {
+		pcb_gui->draw_arc(pcb_crosshair.GC, arc->X, arc->Y, arc->Width - wid, arc->Height - wid, arc->StartAngle, arc->Delta);
+		pcb_gui->draw_arc(pcb_crosshair.GC, x1, y1, wid, wid, arc->StartAngle, -180 * SGN(arc->Delta));
+		pcb_gui->draw_arc(pcb_crosshair.GC, x2, y2, wid, wid, arc->StartAngle + arc->Delta, 180 * SGN(arc->Delta));
+	}
+}
+
+/*-----------------------------------------------------------
+ * Draws the outline of an attached arc
+ */
 static void XORDrawAttachedArc(pcb_coord_t thick)
 {
 	pcb_arc_t arc;
 	pcb_box_t bx;
 	pcb_coord_t wx, wy;
 	pcb_angle_t sa, dir;
-	pcb_coord_t wid = thick / 2;
 
 	wx = pcb_crosshair.X - pcb_crosshair.AttachedBox.Point1.X;
 	wy = pcb_crosshair.Y - pcb_crosshair.AttachedBox.Point1.Y;
@@ -164,17 +192,9 @@ static void XORDrawAttachedArc(pcb_coord_t thick)
 	arc.StartAngle = sa;
 	arc.Delta = dir;
 	arc.Width = arc.Height = wy;
+	arc.Thickness = thick;
 
-	pcb_arc_get_end(&arc, 0, &bx.X1, &bx.Y1);
-	pcb_arc_get_end(&arc, 1, &bx.X2, &bx.Y2);
-
-	/*  sa = sa - 180; */
-	pcb_gui->draw_arc(pcb_crosshair.GC, arc.X, arc.Y, wy + wid, wy + wid, sa, dir);
-	if (wid > pcb_pixel_slop) {
-		pcb_gui->draw_arc(pcb_crosshair.GC, arc.X, arc.Y, wy - wid, wy - wid, sa, dir);
-		pcb_gui->draw_arc(pcb_crosshair.GC, bx.X1, bx.Y1, wid, wid, sa, -180 * SGN(dir));
-		pcb_gui->draw_arc(pcb_crosshair.GC, bx.X2, bx.Y2, wid, wid, sa + dir, 180 * SGN(dir));
-	}
+	XORDrawArc(&arc);
 }
 
 /*-----------------------------------------------------------
@@ -255,6 +275,13 @@ static void XORDrawElement(pcb_element_t *Element, pcb_coord_t DX, pcb_coord_t D
 			moved_pad.Point2.Y += DY;
 
 			pcb_gui->thindraw_pcb_pad(pcb_crosshair.GC, &moved_pad, pcb_false, pcb_false);
+	
+			/* Draw the DRC outline if it is enabled */
+			if (conf_core.editor.show_drc) {
+				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.cross);
+				XORDrawPadDRCOutline(&moved_pad,PCB->Bloat);
+				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.crosshair);
+			}
 		}
 	}
 	PCB_END_LOOP;
@@ -282,7 +309,7 @@ static void XORDrawBuffer(pcb_buffer_t *Buffer)
 	y = pcb_crosshair.Y - Buffer->Y;
 
 	/* draw all visible layers */
-	for (i = 0; i < pcb_max_copper_layer + 2; i++)
+	for (i = 0; i < pcb_max_layer; i++)
 		if (PCB->Data->Layer[i].On) {
 			pcb_layer_t *layer = &Buffer->Data->Layer[i];
 
@@ -369,14 +396,34 @@ static void XORDrawMoveOrCopy(void)
 			pcb_line_t *line = (pcb_line_t *) pcb_crosshair.AttachedObject.Ptr2;
 
 			XORDrawAttachedLine(line->Point1.X + dx, line->Point1.Y + dy, line->Point2.X + dx, line->Point2.Y + dy, line->Thickness);
+			
+			/* Draw the DRC outline if it is enabled */
+			if (conf_core.editor.show_drc) {
+				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.cross);
+				XORDrawAttachedLine(line->Point1.X + dx, line->Point1.Y + dy,
+					line->Point2.X + dx, line->Point2.Y + dy, 
+					line->Thickness + 2 * (PCB->Bloat + 1) );
+				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.crosshair);
+			}
 			break;
 		}
 
 	case PCB_TYPE_ARC:
 		{
-			pcb_arc_t *Arc = (pcb_arc_t *) pcb_crosshair.AttachedObject.Ptr2;
+			/* Make a temporary arc and move it by dx,dy */
+			pcb_arc_t arc = *((pcb_arc_t *) pcb_crosshair.AttachedObject.Ptr2);
+			arc.X += dx;
+			arc.Y += dy;
 
-			pcb_gui->draw_arc(pcb_crosshair.GC, Arc->X + dx, Arc->Y + dy, Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta);
+			XORDrawArc(&arc);
+
+			/* Draw the DRC outline if it is enabled */
+			if (conf_core.editor.show_drc) {
+				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.cross);
+				arc.Thickness += 2 * (PCB->Bloat + 1);
+				XORDrawArc(&arc);
+				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.crosshair);
+			}
 			break;
 		}
 
@@ -394,14 +441,21 @@ static void XORDrawMoveOrCopy(void)
 	case PCB_TYPE_LINE_POINT:
 		{
 			pcb_line_t *line;
-			pcb_point_t *point;
+			pcb_point_t *point1,*point2;
 
 			line = (pcb_line_t *) pcb_crosshair.AttachedObject.Ptr2;
-			point = (pcb_point_t *) pcb_crosshair.AttachedObject.Ptr3;
-			if (point == &line->Point1)
-				XORDrawAttachedLine(point->X + dx, point->Y + dy, line->Point2.X, line->Point2.Y, line->Thickness);
-			else
-				XORDrawAttachedLine(point->X + dx, point->Y + dy, line->Point1.X, line->Point1.Y, line->Thickness);
+			point1 = (pcb_point_t *) pcb_crosshair.AttachedObject.Ptr3;
+			point2 = (point1 == &line->Point1 ? &line->Point2 : &line->Point1);
+				
+			XORDrawAttachedLine(point1->X + dx, point1->Y + dy, point2->X, point2->Y, line->Thickness);
+
+			/* Draw the DRC outline if it is enabled */
+			if (conf_core.editor.show_drc) {
+				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.cross);
+				XORDrawAttachedLine(point1->X + dx, point1->Y + dy, point2->X, point2->Y,line->Thickness + 2 * (PCB->Bloat + 1) );
+				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.crosshair);
+			}
+
 			break;
 		}
 
@@ -457,6 +511,244 @@ static void XORDrawMoveOrCopy(void)
 }
 
 /* ---------------------------------------------------------------------------
+ * draws the DRC Outline of a pad/via shape with the given style and clearance
+ */
+static void 
+draw_pinvia_shape_drc_outline( pcb_hid_gc_t gc, pcb_coord_t X, pcb_coord_t Y, pcb_coord_t Thickness, pcb_coord_t clearance, int style)
+{
+	struct {double X, Y, angle;} p[8] = {	
+		{0.5, -PCB_TAN_22_5_DEGREE_2,	180.0},
+		{PCB_TAN_22_5_DEGREE_2, -0.5,	270.0},
+		{-PCB_TAN_22_5_DEGREE_2, -0.5, 270.0 },
+		{-0.5, -PCB_TAN_22_5_DEGREE_2,	0.0},
+		{-0.5, PCB_TAN_22_5_DEGREE_2,	0.0},
+		{-PCB_TAN_22_5_DEGREE_2, 0.5,	90.0},
+		{PCB_TAN_22_5_DEGREE_2, 0.5,	90.0},
+		{0.5, PCB_TAN_22_5_DEGREE_2,	180.0}
+	};
+
+	pcb_coord_t		polygon_x[9];
+	pcb_coord_t		polygon_y[9];
+	double				xm[8];
+	double				ym[8];
+	double				xn[8];
+	double				yn[8];
+	double				a[8];
+	int						i;
+	const double	factor	= 2.0;
+
+	/* Constants for Normals and Arc Angles */
+	const double N0 = 0.7071067;
+	const double N1 = 0.44721279658;
+	const double N2 = 0.89442759;
+	const double A0 = 45.0;
+	const double A1 = 26.565;
+	const double A2 = 63.435;
+
+	style = (style-1) & 0x0F;
+
+	/* Calculate multipliers*/
+	for (i = 0; i < 8; i++)	{
+		xm[i] = 1;
+		ym[i] = 1;
+	}
+
+	if (style & 1)
+		xm[0] = xm[1] = xm[6] = xm[7] = factor;
+	if (style & 2)
+		xm[2] = xm[3] = xm[4] = xm[5] = factor;
+	if (style & 4)
+		ym[4] = ym[5] = ym[6] = ym[7] = factor;
+	if (style & 8)
+		ym[0] = ym[1] = ym[2] = ym[3] = factor;
+
+	/* Select Edge Normals and Arc Angles */
+	xn[1] = xn[5] = 0.0;
+	yn[3] = yn[7] = 0.0;
+	yn[1] = -1.0;
+	yn[5] = 1.0;
+	xn[3] = -1.0;
+	xn[7] = +1.0;
+
+	switch(style & 9) {
+		case 1 :	xn[0] = N1; yn[0] = -N2; a[0] = A2; a[1] = -A1; break;
+		case 8 :	xn[0] = N2; yn[0] = -N1; a[0] = A1; a[1] = -A2; break;
+		default :	xn[0] = N0; yn[0] = -N0; a[0] = A0; a[1] = -A0; break;
+	}
+
+	switch(style & 10) {	
+		case 2 :	xn[2] = -N1; yn[2] = -N2; a[2] = A1; a[3] = -A2;  break;
+		case 8 :	xn[2] = -N2; yn[2] = -N1; a[2] = A2; a[3] = -A1;  break;
+		default :	xn[2] = -N0; yn[2] = -N0; a[2] = A0; a[3] = -A0;  break;
+	}
+
+	switch(style & 5)	{
+		case 1 :	xn[6] = N1; yn[6] = N2; a[6] = A1; a[7] = -A2; break;
+		case 4 :	xn[6] = N2; yn[6] = N1; a[6] = A2; a[7] = -A1; break;
+		default :	xn[6] = N0; yn[6] = N0; a[6] = A0; a[7] = -A0; break;
+	}
+
+	switch(style & 6)	{
+		case 2 :	xn[4] = -N1; yn[4] = N2; a[4] = A2; a[5] = -A1; break;
+		case 4 :	xn[4] = -N2; yn[4] = N1; a[4] = A1; a[5] = -A2; break;
+		default :	xn[4] = -N0; yn[4] = N0; a[4] = A0; a[5] = -A0; break;
+	}
+
+	/* add line offset */
+	for (i = 0; i < 8; i++) {
+		polygon_x[i] = X + (p[i].X * Thickness) * xm[i];
+		polygon_y[i] = Y + (p[i].Y * Thickness) * ym[i];
+	}
+	polygon_x[8] = polygon_x[0];
+	polygon_y[8] = polygon_y[0];
+
+	pcb_gui->set_line_cap(gc, Round_Cap);
+	pcb_gui->set_line_width(gc, 0);
+
+	/* Draw the outline */
+	for (i = 0; i < 8; i++)	{
+			pcb_gui->draw_line(	gc,
+													polygon_x[i]		+ (xn[i] * clearance), 
+													polygon_y[i]		+ (yn[i] * clearance),  
+													polygon_x[i+1]	+ (xn[i] * clearance),  
+													polygon_y[i+1]	+ (yn[i] * clearance) );
+
+			pcb_gui->draw_arc( gc,polygon_x[i],polygon_y[i],clearance,clearance,p[i].angle,a[i]);
+	}
+}
+
+/* ---------------------------------------------------------------------------
+ * draws the DRC Outline of a pin/via with the given clearance
+ */
+static void 
+XORDrawPinViaDRCOutline(pcb_pin_t * pv,pcb_coord_t clearance)
+{
+	int style = PCB_FLAG_SQUARE_GET(pv);
+
+	if (PCB_FLAG_TEST(PCB_FLAG_HOLE, pv) || (clearance == 0))
+		return;
+	
+	if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pv))
+	{
+		
+		if((style==0) || (style==1))
+		{
+			pcb_coord_t w = pv->Thickness;
+			pcb_coord_t l = pv->X - (w/2);
+			pcb_coord_t b = pv->Y - (w/2);
+			pcb_coord_t r = l + w;
+			pcb_coord_t t = b + w;
+			pcb_coord_t lc = l - clearance;
+			pcb_coord_t bc = b - clearance;
+			pcb_coord_t rc = r + clearance;
+			pcb_coord_t tc = t + clearance;
+
+			pcb_gui->set_line_cap(pcb_crosshair.GC, Round_Cap);
+			pcb_gui->set_line_width(pcb_crosshair.GC, 0); 
+			pcb_gui->draw_line(pcb_crosshair.GC, rc, t, rc, b);
+			pcb_gui->draw_line(pcb_crosshair.GC, lc, t, lc, b);
+ 			pcb_gui->draw_line(pcb_crosshair.GC, r, tc, l, tc);
+ 			pcb_gui->draw_line(pcb_crosshair.GC, r, bc, l, bc);
+			pcb_gui->draw_arc(pcb_crosshair.GC, r,b,clearance,clearance,180,90);
+			pcb_gui->draw_arc(pcb_crosshair.GC, r,t,clearance,clearance,90,90);
+			pcb_gui->draw_arc(pcb_crosshair.GC, l,b,clearance,clearance,270,90);
+			pcb_gui->draw_arc(pcb_crosshair.GC, l,t,clearance,clearance,0,90);
+		}
+		else
+			draw_pinvia_shape_drc_outline(pcb_crosshair.GC,pv->X,pv->Y,pv->Thickness,clearance,style);
+	}
+	else if (PCB_FLAG_TEST(PCB_FLAG_OCTAGON, pv))
+			draw_pinvia_shape_drc_outline(pcb_crosshair.GC,pv->X,pv->Y,pv->Thickness,clearance,17);
+	else
+	{
+			pcb_coord_t r = (pv->Thickness/2)+clearance;
+
+			pcb_gui->set_line_cap(pcb_crosshair.GC, Round_Cap);
+			pcb_gui->set_line_width(pcb_crosshair.GC, 0); 
+			pcb_gui->draw_arc(pcb_crosshair.GC, pv->X, pv->Y, r, r, 0, 360);
+	}			
+}
+
+/* ---------------------------------------------------------------------------
+ * draws the DRC Outline of a pad with the given clearance
+ */
+static void 
+XORDrawPadDRCOutline(pcb_pad_t * pad,pcb_coord_t clearance)
+{
+	pcb_coord_t x1, y1, x2, y2;
+	pcb_coord_t t = (pad->Thickness / 2);
+	x1 = pad->Point1.X;
+	y1 = pad->Point1.Y;
+	x2 = pad->Point2.X;
+	y2 = pad->Point2.Y;
+
+	pcb_gui->set_line_cap(pcb_crosshair.GC, Round_Cap);
+	pcb_gui->set_line_width(pcb_crosshair.GC, 0);
+
+	if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pad)) {
+		/* slanted square pad */
+		double tx, ty, nx, ny, theta, angle;
+		pcb_coord_t cx0, cx1, cx2, cx3;
+		pcb_coord_t cy0, cy1, cy2, cy3;
+
+		if ((x1 == x2) && (y1 == y2))
+			theta = 0;
+		else
+			theta = atan2(y2 - y1, x2 - x1);
+
+		angle = (270-(theta * PCB_RAD_TO_DEG));
+
+		/* T is a vector half a thickness long, in the direction of
+		   one of the corners.  */
+		tx = t * cos(theta + M_PI / 4) * PCB_SQRT2;
+		ty = t * sin(theta + M_PI / 4) * PCB_SQRT2;
+
+		/* The normal of one of the edges with length = clearance */
+		nx = cos(theta + M_PI / 2) * clearance;
+		ny = sin(theta + M_PI / 2) * clearance;
+
+		/* Coordinates of the pad corners */
+		cx0 = x1 - tx; cx1 = x2 + ty; cx2 = x2 + tx; cx3 = x1 - ty;
+		cy0 = y1 - ty; cy1 = y2 - tx; cy2 = y2 + ty; cy3 = y1 + tx;
+		
+		/* Draw the DRC outline*/
+		pcb_gui->draw_line(pcb_crosshair.GC, cx0 - nx, cy0 - ny, cx1 - nx, cy1 - ny );
+		pcb_gui->draw_line(pcb_crosshair.GC, cx2 + nx, cy2 + ny, cx3 + nx, cy3 + ny );
+		pcb_gui->draw_line(pcb_crosshair.GC, cx0 - ny, cy0 + nx, cx3 - ny, cy3 + nx );
+		pcb_gui->draw_line(pcb_crosshair.GC, cx1 + ny, cy1 - nx, cx2 + ny, cy2 - nx );
+
+		pcb_gui->draw_arc(pcb_crosshair.GC,cx0,cy0,clearance,clearance,angle,90);
+		pcb_gui->draw_arc(pcb_crosshair.GC,cx1,cy1,clearance,clearance,angle-90,90);
+		pcb_gui->draw_arc(pcb_crosshair.GC,cx2,cy2,clearance,clearance,angle-180,90);
+		pcb_gui->draw_arc(pcb_crosshair.GC,cx3,cy3,clearance,clearance,angle-270,90);
+	}
+	else if (x1 == x2 && y1 == y2) {
+		pcb_gui->draw_arc(pcb_crosshair.GC, x1, y1, t + clearance, t + clearance, 0, 360);
+	}
+	else {
+		/* Slanted round-end pads.  */
+		pcb_coord_t dx, dy, ox, oy;
+		double h;
+
+		t += clearance;
+		dx = x2 - x1;
+		dy = y2 - y1;
+		h = t / sqrt(PCB_SQUARE(dx) + PCB_SQUARE(dy));
+		ox = dy * h + 0.5 * SGN(dy);
+		oy = -(dx * h + 0.5 * SGN(dx));
+
+		pcb_gui->draw_line(pcb_crosshair.GC, x1 + ox, y1 + oy, x2 + ox, y2 + oy);
+
+		if (labs(ox) >= pcb_pixel_slop || coord_abs(oy) >= pcb_pixel_slop) {
+			pcb_angle_t angle = atan2(dx, dy) * 57.295779;
+			pcb_gui->draw_line(pcb_crosshair.GC, x1 - ox, y1 - oy, x2 - ox, y2 - oy);
+			pcb_gui->draw_arc(pcb_crosshair.GC, x1, y1, t, t, angle - 180, 180);
+			pcb_gui->draw_arc(pcb_crosshair.GC, x2, y2, t, t, angle, 180);
+		}
+	}
+}
+
+/* ---------------------------------------------------------------------------
  * draws additional stuff that follows the crosshair
  */
 void pcb_draw_attached(void)
@@ -478,9 +770,8 @@ void pcb_draw_attached(void)
 
 			if (conf_core.editor.show_drc) {
 				/* XXX: Naughty cheat - use the mask to draw DRC clearance! */
-				via.Mask = conf_core.design.via_thickness + PCB->Bloat * 2;
 				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.cross);
-				pcb_gui->thindraw_pcb_pv(pcb_crosshair.GC, pcb_crosshair.GC, &via, pcb_false, pcb_true);
+				XORDrawPinViaDRCOutline(&via,PCB->Bloat);
 				pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.crosshair);
 			}
 			break;
@@ -763,7 +1054,7 @@ static void onpoint_work(pcb_crosshair_t * crosshair, pcb_coord_t X, pcb_coord_t
 	info.X = X;
 	info.Y = Y;
 
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		pcb_layer_t *layer = &PCB->Data->Layer[i];
 		/* Only find points of arcs and lines on currently visible layers. */
 		if (!layer->On)
@@ -991,18 +1282,21 @@ void pcb_crosshair_grid_fit(pcb_coord_t X, pcb_coord_t Y)
 		}
 
 		/* find layer groups of the component side and solder side */
-		SLayer = pcb_layer_get_group(pcb_solder_silk_layer);
-		CLayer = pcb_layer_get_group(pcb_component_silk_layer);
+		SLayer = CLayer = -1;
+		pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &SLayer, 1);
+		pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &CLayer, 1);
 		desired_group = PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, pad) ? SLayer : CLayer;
 
-		GROUP_LOOP(PCB->Data, desired_group);
-		{
-			if (layer == desired_layer) {
-				found_our_layer = pcb_true;
-				break;
+		if (desired_group >= 0) {
+			PCB_COPPER_GROUP_LOOP(PCB->Data, desired_group);
+			{
+				if (layer == desired_layer) {
+					found_our_layer = pcb_true;
+					break;
+				}
 			}
+			PCB_END_LOOP;
 		}
-		PCB_END_LOOP;
 
 		if (found_our_layer == pcb_false)
 			ans = PCB_TYPE_NONE;
@@ -1327,3 +1621,4 @@ void pcb_crosshair_set_local_ref(pcb_coord_t X, pcb_coord_t Y, pcb_bool Showing)
 		pcb_notify_mark_change(pcb_true);
 	}
 }
+
diff --git a/src/data.c b/src/data.c
index b9b2c10..8641f8d 100644
--- a/src/data.c
+++ b/src/data.c
@@ -33,6 +33,7 @@
 #include "rtree.h"
 #include "list_common.h"
 #include "obj_all.h"
+#include "layer_it.h"
 
 /* ---------------------------------------------------------------------------
  * some shared identifiers
@@ -49,8 +50,10 @@ int pcb_added_lines;
 void pcb_loop_layers(void *ctx, pcb_layer_cb_t lacb, pcb_line_cb_t lcb, pcb_arc_cb_t acb, pcb_text_cb_t tcb, pcb_poly_cb_t pocb)
 {
 	if ((lacb != NULL) || (lcb != NULL) || (acb != NULL) || (tcb != NULL) || (pocb != NULL)) {
-		LAYER_LOOP(PCB->Data, pcb_max_copper_layer + 2);
-		{
+		pcb_layer_it_t it;
+		pcb_layer_id_t lid;
+		for(lid = pcb_layer_first_all(&PCB->LayerGroups, &it); lid != -1; lid = pcb_layer_next(&it)) {
+			pcb_layer_t *layer = PCB->Data->Layer + lid;
 			if (lacb != NULL)
 				if (lacb(ctx, PCB, layer, 1))
 					continue;
@@ -88,7 +91,6 @@ void pcb_loop_layers(void *ctx, pcb_layer_cb_t lacb, pcb_line_cb_t lcb, pcb_arc_
 			if (lacb != NULL)
 				lacb(ctx, PCB, layer, 0);
 		}
-		PCB_END_LOOP;
 	}
 }
 
@@ -196,7 +198,7 @@ void pcb_data_free(pcb_data_t * data)
 	list_map0(&data->Element, pcb_element_t, pcb_element_free);
 	list_map0(&data->Rat, pcb_rat_t, pcb_rat_free);
 
-	for (layer = data->Layer, i = 0; i < PCB_MAX_LAYER + 2; layer++, i++) {
+	for (layer = data->Layer, i = 0; i < pcb_max_layer; layer++, i++) {
 		pcb_attribute_free(&layer->Attributes);
 		PCB_TEXT_LOOP(layer);
 		{
@@ -258,7 +260,7 @@ pcb_bool pcb_data_is_empty(pcb_data_t *Data)
 
 	hasNoObjects = (pinlist_length(&Data->Via) == 0);
 	hasNoObjects &= (elementlist_length(&Data->Element) == 0);
-	for (i = 0; i < pcb_max_copper_layer + 2; i++)
+	for (i = 0; i < pcb_max_layer; i++)
 		hasNoObjects = hasNoObjects && PCB_LAYER_IS_EMPTY(&(Data->Layer[i]));
 	return (hasNoObjects);
 }
diff --git a/src/data.h b/src/data.h
index 293c8fc..1f60705 100644
--- a/src/data.h
+++ b/src/data.h
@@ -47,16 +47,14 @@ struct pcb_data_s {
 	pcb_rtree_t *via_tree, *element_tree, *pin_tree, *pad_tree, *name_tree[3],	/* for element names */
 	 *rat_tree;
 	pcb_board_t *pcb;
-	pcb_layer_t Layer[PCB_MAX_LAYER + 2];    /* add 2 silkscreen layers */
+	pcb_layer_t Layer[PCB_MAX_LAYER]; /* layer TODO: make this dynamic */
 	pcb_plug_io_t *loader;
 	ratlist_t Rat;
 };
 
 
-#define pcb_max_group (PCB->Data->LayerN)
-#define pcb_max_copper_layer (PCB->Data->LayerN)
-#define pcb_solder_silk_layer (pcb_max_copper_layer + PCB_SOLDER_SIDE)
-#define pcb_component_silk_layer (pcb_max_copper_layer + PCB_COMPONENT_SIDE)
+#define pcb_max_layer (PCB->Data->LayerN)
+#define pcb_max_group (PCB->LayerGroups.len)
 
 extern pcb_buffer_t pcb_buffers[PCB_MAX_BUFFER];
 extern int pcb_added_lines;
diff --git a/src/defpcb_internal.c b/src/defpcb_internal.c
new file mode 100644
index 0000000..6fde09b
--- /dev/null
+++ b/src/defpcb_internal.c
@@ -0,0 +1,51 @@
+/* Autogenerated by cquote.c - DO NOT EDIT */
+#define NL "\n"
+const char *default_pcb_internal = \
+	   "# release: pcb 20110918"
+	NL ""
+	NL "# To read pcb files, the pcb version (or the git source date) must be >= the file version"
+	NL "FileVersion[20070407]"
+	NL ""
+	NL "PCB[\"\" 600000 500000]"
+	NL ""
+	NL "Grid[2500.0 0 0 1]"
+	NL "Cursor[2500 62500 0.000000]"
+	NL "PolyArea[3100.006200]"
+	NL "Thermal[0.500000]"
+	NL "DRC[1200 900 1000 700 1500 1000]"
+	NL "Flags(\"nameonpcb,clearnew,snappin\")"
+	NL "Groups(\"1,3,4,c:2,5,6,s:7:8\")"
+	NL "Styles[\"Signal,1000,7874,3150,2000:Power,2000,8661,3937,2000:Fat,8000,13780,4724,2500:Sig-tight,1000,6400,3150,1200\"]"
+	NL ""
+	NL "Attribute(\"PCB::grid::unit\" \"mil\")"
+	NL "Layer(1 \"component\")"
+	NL "("
+	NL ")"
+	NL "Layer(2 \"solder\")"
+	NL "("
+	NL ")"
+	NL "Layer(3 \"comp-GND\")"
+	NL "("
+	NL ")"
+	NL "Layer(4 \"comp-power\")"
+	NL "("
+	NL ")"
+	NL "Layer(5 \"sold-GND\")"
+	NL "("
+	NL ")"
+	NL "Layer(6 \"sold-power\")"
+	NL "("
+	NL ")"
+	NL "Layer(7 \"signal3\")"
+	NL "("
+	NL ")"
+	NL "Layer(8 \"outline\")"
+	NL "("
+	NL ")"
+	NL "Layer(9 \"silk\")"
+	NL "("
+	NL ")"
+	NL "Layer(10 \"silk\")"
+	NL "("
+	NL ")"
+	NL;
diff --git a/src/draw.c b/src/draw.c
index d540437..1d4ed6c 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -38,6 +38,7 @@
 #include "rotate.h"
 #include "rtree.h"
 #include "stub_draw_fab.h"
+#include "stub_draw_csect.h"
 #include "obj_all.h"
 #include "layer_ui.h"
 
@@ -74,11 +75,11 @@ pcb_bool pcb_draw_doing_assy = pcb_false;
  * some local prototypes
  */
 static void DrawEverything(const pcb_box_t *);
-static void DrawPPV(int group, const pcb_box_t *);
+static void DrawPPV(pcb_layergrp_id_t group, const pcb_box_t * drawn_area);
 static void DrawLayerGroup(int, const pcb_box_t *);
 static void DrawMask(int side, const pcb_box_t *);
 static void DrawRats(const pcb_box_t *);
-static void DrawSilk(int side, const pcb_box_t *);
+static void DrawSilk(unsigned int lyt_side, const pcb_box_t *);
 
 #warning TODO: this should be cached
 void pcb_lighten_color(const char *orig, char buf[8], double factor)
@@ -139,9 +140,12 @@ static void DrawHoles(pcb_bool draw_plated, pcb_bool draw_unplated, const pcb_bo
 /* ---------------------------------------------------------------------------
  * prints assembly drawing.
  */
-static void PrintAssembly(int side, const pcb_box_t * drawn_area)
+static void PrintAssembly(unsigned int lyt_side, const pcb_box_t * drawn_area)
 {
-	pcb_layergrp_id_t side_group = pcb_layer_get_group(pcb_max_copper_layer + side);
+	pcb_layergrp_id_t side_group;
+
+	if (pcb_layer_group_list(PCB_LYT_COPPER | lyt_side, &side_group, 1) != 1)
+		return;
 
 	pcb_draw_doing_assy = pcb_true;
 	pcb_gui->set_draw_faded(Output.fgGC, 1);
@@ -149,7 +153,7 @@ static void PrintAssembly(int side, const pcb_box_t * drawn_area)
 	pcb_gui->set_draw_faded(Output.fgGC, 0);
 
 	/* draw package */
-	DrawSilk(side, drawn_area);
+	DrawSilk(lyt_side, drawn_area);
 	pcb_draw_doing_assy = pcb_false;
 }
 
@@ -174,8 +178,8 @@ static void DrawEverything_holes(const pcb_box_t * drawn_area)
  */
 static void DrawEverything(const pcb_box_t * drawn_area)
 {
-	int i, ngroups, side;
-	pcb_layergrp_id_t component, solder;
+	int i, ngroups, side, slk_len;
+	pcb_layergrp_id_t component, solder, slk[16], gid;
 	/* This is the list of layer groups we will draw.  */
 	pcb_layergrp_id_t do_group[PCB_MAX_LAYERGRP];
 	/* This is the reverse of the order in which we draw them.  */
@@ -188,17 +192,23 @@ static void DrawEverything(const pcb_box_t * drawn_area)
 	PCB->Data->BACKSILKLAYER.Color = PCB->InvisibleObjectsColor;
 
 	memset(do_group, 0, sizeof(do_group));
-	for (ngroups = 0, i = 0; i < pcb_max_copper_layer; i++) {
+	for (ngroups = 0, i = 0; i < pcb_max_layer; i++) {
 		pcb_layer_t *l = LAYER_ON_STACK(i);
 		pcb_layergrp_id_t group = pcb_layer_get_group(pcb_layer_stack[i]);
+		unsigned int gflg = pcb_layergrp_flags(group);
+
+		if (gflg & PCB_LYT_SILK) /* do not draw silk here, it'll be drawn separately */
+			continue;
+
 		if (l->On && !do_group[group]) {
 			do_group[group] = 1;
 			drawn_groups[ngroups++] = group;
 		}
 	}
 
-	component = pcb_layer_get_group(pcb_component_silk_layer);
-	solder = pcb_layer_get_group(pcb_solder_silk_layer);
+	solder = component = -1;
+	pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &solder, 1);
+	pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &component, 1);
 
 	/*
 	 * first draw all 'invisible' stuff
@@ -206,9 +216,11 @@ static void DrawEverything(const pcb_box_t * drawn_area)
 	if (!conf_core.editor.check_planes && pcb_layer_gui_set_vlayer(PCB_VLY_INVISIBLE, 0)) {
 		side = PCB_SWAP_IDENT ? PCB_COMPONENT_SIDE : PCB_SOLDER_SIDE;
 		if (PCB->ElementOn) {
+			pcb_layer_id_t lsilk;
 			pcb_r_search(PCB->Data->element_tree, drawn_area, NULL, draw_element_callback, &side, NULL);
 			pcb_r_search(PCB->Data->name_tree[PCB_ELEMNAME_IDX_VISIBLE()], drawn_area, NULL, draw_element_name_callback, &side, NULL);
-			pcb_draw_layer(&(PCB->Data->Layer[pcb_max_copper_layer + side]), drawn_area);
+			if (pcb_layer_list(PCB_LYT_INVISIBLE_SIDE() | PCB_LYT_SILK, &lsilk, 1) > 0)
+				pcb_draw_layer(&(PCB->Data->Layer[lsilk]), drawn_area);
 		}
 		pcb_r_search(PCB->Data->pad_tree, drawn_area, NULL, draw_pad_callback, &side, NULL);
 		pcb_gui->end_layer();
@@ -234,24 +246,26 @@ static void DrawEverything(const pcb_box_t * drawn_area)
 		DrawEverything_holes(drawn_area);
 
 	/* Draw the solder mask if turned on */
-	if (pcb_layer_gui_set_vlayer(PCB_VLY_TOP_MASK, 0)) {
+	gid = pcb_layergrp_get_top_mask();
+	if ((gid >= 0) && (pcb_layer_gui_set_glayer(gid, 0))) {
 		DrawMask(PCB_COMPONENT_SIDE, drawn_area);
 		pcb_gui->end_layer();
 	}
 
-	if (pcb_layer_gui_set_vlayer(PCB_VLY_BOTTOM_MASK, 0)) {
+	gid = pcb_layergrp_get_bottom_mask();
+	if ((gid >= 0) && (pcb_layer_gui_set_glayer(gid, 0))) {
 		DrawMask(PCB_SOLDER_SIDE, drawn_area);
 		pcb_gui->end_layer();
 	}
 
-	if (pcb_layer_gui_set_vlayer(PCB_VLY_TOP_SILK, 0)) {
-		DrawSilk(PCB_COMPONENT_SIDE, drawn_area);
-		pcb_gui->end_layer();
-	}
-
-	if (pcb_layer_gui_set_vlayer(PCB_VLY_BOTTOM_SILK, 0)) {
-		DrawSilk(PCB_SOLDER_SIDE, drawn_area);
-		pcb_gui->end_layer();
+	/* Draw silks */
+	slk_len = pcb_layer_group_list(PCB_LYT_SILK, slk, sizeof(slk) / sizeof(slk[0]));
+	for(i = 0; i < slk_len; i++) {
+		if (pcb_layer_gui_set_glayer(slk[i], 0)) {
+			unsigned int loc = pcb_layergrp_flags(slk[i]);
+			DrawSilk(loc & PCB_LYT_ANYWHERE, drawn_area);
+			pcb_gui->end_layer();
+		}
 	}
 
 	if (pcb_gui->holes_after)
@@ -269,24 +283,26 @@ static void DrawEverything(const pcb_box_t * drawn_area)
 	}
 
 	paste_empty = pcb_layer_is_paste_empty(PCB_COMPONENT_SIDE);
-	if (pcb_layer_gui_set_vlayer(PCB_VLY_TOP_PASTE, paste_empty)) {
+	gid = pcb_layergrp_get_top_paste();
+	if ((gid >= 0) && (pcb_layer_gui_set_glayer(gid, paste_empty))) {
 		DrawPaste(PCB_COMPONENT_SIDE, drawn_area);
 		pcb_gui->end_layer();
 	}
 
 	paste_empty = pcb_layer_is_paste_empty(PCB_SOLDER_SIDE);
-	if (pcb_layer_gui_set_vlayer(PCB_VLY_BOTTOM_PASTE, paste_empty)) {
+	gid = pcb_layergrp_get_bottom_paste();
+	if ((gid >= 0) && (pcb_layer_gui_set_glayer(gid, paste_empty))) {
 		DrawPaste(PCB_SOLDER_SIDE, drawn_area);
 		pcb_gui->end_layer();
 	}
 
 	if (pcb_layer_gui_set_vlayer(PCB_VLY_TOP_ASSY, 0)) {
-		PrintAssembly(PCB_COMPONENT_SIDE, drawn_area);
+		PrintAssembly(PCB_LYT_TOP, drawn_area);
 		pcb_gui->end_layer();
 	}
 
 	if (pcb_layer_gui_set_vlayer(PCB_VLY_BOTTOM_ASSY, 0)) {
-		PrintAssembly(PCB_SOLDER_SIDE, drawn_area);
+		PrintAssembly(PCB_LYT_BOTTOM, drawn_area);
 		pcb_gui->end_layer();
 	}
 
@@ -295,6 +311,11 @@ static void DrawEverything(const pcb_box_t * drawn_area)
 		pcb_gui->end_layer();
 	}
 
+	if (pcb_layer_gui_set_vlayer(PCB_VLY_CSECT, 0)) {
+		pcb_stub_draw_csect(Output.fgGC);
+		pcb_gui->end_layer();
+	}
+
 	/* find the first ui layer in use */
 	first = NULL;
 	for(i = 0; i < vtlayer_len(&pcb_uilayer); i++) {
@@ -318,23 +339,22 @@ static void DrawEverything(const pcb_box_t * drawn_area)
  * Draws pins pads and vias - Always draws for non-gui HIDs,
  * otherwise drawing depends on PCB->PinOn and PCB->ViaOn
  */
-static void DrawPPV(int group, const pcb_box_t * drawn_area)
+static void DrawPPV(pcb_layergrp_id_t group, const pcb_box_t * drawn_area)
 {
-	pcb_layergrp_id_t component_group = pcb_layer_get_group(pcb_component_silk_layer);
-	pcb_layergrp_id_t solder_group = pcb_layer_get_group(pcb_solder_silk_layer);
 	int side;
+	unsigned int gflg = pcb_layergrp_flags(group);
 
 	if (PCB->PinOn || !pcb_gui->gui) {
 		/* draw element pins */
 		pcb_r_search(PCB->Data->pin_tree, drawn_area, NULL, draw_pin_callback, NULL, NULL);
 
 		/* draw element pads */
-		if (group == component_group) {
+		if (gflg & PCB_LYT_TOP) {
 			side = PCB_COMPONENT_SIDE;
 			pcb_r_search(PCB->Data->pad_tree, drawn_area, NULL, draw_pad_callback, &side, NULL);
 		}
 
-		if (group == solder_group) {
+		if (gflg & PCB_LYT_BOTTOM) {
 			side = PCB_SOLDER_SIDE;
 			pcb_r_search(PCB->Data->pad_tree, drawn_area, NULL, draw_pad_callback, &side, NULL);
 		}
@@ -353,7 +373,7 @@ static void DrawPPV(int group, const pcb_box_t * drawn_area)
  * Draws silk layer.
  */
 
-static void DrawSilk(int side, const pcb_box_t * drawn_area)
+static void DrawSilk(unsigned int lyt_side, const pcb_box_t * drawn_area)
 {
 #if 0
 	/* This code is used when you want to mask silk to avoid exposed
@@ -365,10 +385,17 @@ static void DrawSilk(int side, const pcb_box_t * drawn_area)
 	if (pcb_gui->poly_before) {
 		pcb_gui->use_mask(HID_MASK_BEFORE);
 #endif
-		pcb_draw_layer(LAYER_PTR(pcb_max_copper_layer + side), drawn_area);
+		pcb_layer_id_t lid;
+		int side = lyt_side == PCB_LYT_TOP ? PCB_COMPONENT_SIDE : PCB_SOLDER_SIDE;
+
+		if (pcb_layer_list(PCB_LYT_SILK | lyt_side, &lid, 1) == 0)
+			return;
+
+		pcb_draw_layer(LAYER_PTR(lid), drawn_area);
 		/* draw package */
 		pcb_r_search(PCB->Data->element_tree, drawn_area, NULL, draw_element_callback, &side, NULL);
 		pcb_r_search(PCB->Data->name_tree[PCB_ELEMNAME_IDX_VISIBLE()], drawn_area, NULL, draw_element_name_callback, &side, NULL);
+
 #if 0
 	}
 
@@ -378,8 +405,10 @@ static void DrawSilk(int side, const pcb_box_t * drawn_area)
 	pcb_r_search(PCB->Data->pad_tree, drawn_area, NULL, clear_pad_callback, &side, NULL);
 
 	if (pcb_gui->poly_after) {
+		pcb_layer_id_t lsilk;
 		pcb_gui->use_mask(HID_MASK_AFTER);
-		pcb_draw_layer(LAYER_PTR(pcb_max_copper_layer + layer), drawn_area);
+		if (pcb_layer_list(PCB_LYT_VISIBLE_SIDE() | PCB_LYT_SILK, &lsilk, 1) > 0)
+			pcb_draw_layer(LAYER_PTR(lsilk), drawn_area);
 		/* draw package */
 		pcb_r_search(PCB->Data->element_tree, drawn_area, NULL, draw_element_callback, &side, NULL);
 		pcb_r_search(PCB->Data->name_tree[PCB_ELEMNAME_IDX_VISIBLE()], drawn_area, NULL, draw_element_name_callback, &side, NULL);
@@ -447,6 +476,8 @@ void pcb_draw_layer(pcb_layer_t *Layer, const pcb_box_t * screen)
 {
 	struct pcb_draw_poly_info_s info;
 	pcb_box_t scr2;
+	pcb_layer_id_t lid;
+	unsigned int lflg = 0;
 
 	if ((screen->X2 <= screen->X1) || (screen->Y2 <= screen->Y1)) {
 		scr2 = *screen;
@@ -476,11 +507,15 @@ void pcb_draw_layer(pcb_layer_t *Layer, const pcb_box_t * screen)
 	/* draw the layer text on screen */
 	pcb_r_search(Layer->text_tree, screen, NULL, draw_text_callback, Layer, NULL);
 
-	/* We should check for pcb_gui->gui here, but it's kinda cool seeing the
+	lid = pcb_layer_id(PCB->Data, Layer);
+	if (lid >= 0)
+		lflg = pcb_layer_flags(lid);
+
+	/* The implicit outline rectangle (or automatic outline rectanlge).
+	   We should check for pcb_gui->gui here, but it's kinda cool seeing the
 	   auto-outline magically disappear when you first add something to
-	   the "outline" layer.  */
-	if (pcb_layer_is_empty_(Layer)
-			&& (strcmp(Layer->Name, "outline") == 0 || strcmp(Layer->Name, "route") == 0)) {
+	   the outline layer.  */
+	if ((lflg & PCB_LYT_OUTLINE) && pcb_layer_is_empty_(Layer)) {
 		pcb_gui->set_color(Output.fgGC, Layer->Color);
 		pcb_gui->set_line_width(Output.fgGC, PCB->minWid);
 		pcb_gui->draw_rect(Output.fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
@@ -494,17 +529,19 @@ void pcb_draw_layer(pcb_layer_t *Layer, const pcb_box_t * screen)
 static void DrawLayerGroup(int group, const pcb_box_t * drawn_area)
 {
 	int i, rv = 1;
-	int layernum;
+	pcb_layer_id_t layernum;
 	pcb_layer_t *Layer;
-	int n_entries = PCB->LayerGroups.Number[group];
-	pcb_cardinal_t *layers = PCB->LayerGroups.Entries[group];
+	pcb_cardinal_t n_entries = PCB->LayerGroups.grp[group].len;
+	pcb_layer_id_t *layers = PCB->LayerGroups.grp[group].lid;
+	unsigned int gflg = pcb_layergrp_flags(group);
+
+	if (gflg & PCB_LYT_OUTLINE)
+		rv = 0;
 
 	for (i = n_entries - 1; i >= 0; i--) {
 		layernum = layers[i];
-		Layer = PCB->Data->Layer + layers[i];
-		if (strcmp(Layer->Name, "outline") == 0 || strcmp(Layer->Name, "route") == 0)
-			rv = 0;
-		if (layernum < pcb_max_copper_layer && Layer->On)
+		Layer = PCB->Data->Layer + layernum;
+		if (!(gflg & PCB_LYT_SILK) && Layer->On)
 			pcb_draw_layer(Layer, drawn_area);
 	}
 	if (n_entries > 1)
@@ -599,7 +636,7 @@ void pcb_draw_obj(int type, void *ptr1, void *ptr2)
  * HID drawing callback.
  */
 
-void pcb_hid_expose_callback(pcb_hid_t * hid, pcb_box_t * region, void *item)
+static pcb_hid_t *expose_begin(pcb_hid_t *hid)
 {
 	pcb_hid_t *old_gui = pcb_gui;
 
@@ -610,17 +647,54 @@ void pcb_hid_expose_callback(pcb_hid_t * hid, pcb_box_t * region, void *item)
 
 	hid->set_color(Output.pmGC, "erase");
 	hid->set_color(Output.bgGC, "drill");
+	return old_gui;
+}
 
-	if (item) {
-		pcb_draw_doing_pinout = pcb_true;
-		draw_element((pcb_element_t *) item);
-		pcb_draw_doing_pinout = pcb_false;
-	}
-	else if (!pcb_draw_inhibit)
-		DrawEverything(region);
-
+static void expose_end(pcb_hid_t *old_gui)
+{
 	pcb_gui->destroy_gc(Output.fgGC);
 	pcb_gui->destroy_gc(Output.bgGC);
 	pcb_gui->destroy_gc(Output.pmGC);
 	pcb_gui = old_gui;
 }
+
+void pcb_hid_expose_all(pcb_hid_t * hid, const pcb_hid_expose_ctx_t *ctx)
+{
+	if (!pcb_draw_inhibit) {
+		pcb_hid_t *old_gui = expose_begin(hid);
+		DrawEverything(&ctx->view);
+		expose_end(old_gui);
+	}
+}
+
+void pcb_hid_expose_pinout(pcb_hid_t * hid, const pcb_hid_expose_ctx_t *ctx)
+{
+	pcb_hid_t *old_gui = expose_begin(hid);
+
+	pcb_draw_doing_pinout = pcb_true;
+	draw_element(ctx->content.elem);
+	pcb_draw_doing_pinout = pcb_false;
+
+	expose_end(old_gui);
+}
+
+void pcb_hid_expose_layer(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *e)
+{
+	pcb_hid_t *old_gui = expose_begin(hid);
+	unsigned long lflg = pcb_layer_flags(e->content.layer_id);
+
+	if (lflg & PCB_LYT_CSECT) {
+		if ((pcb_layer_gui_set_vlayer(PCB_VLY_CSECT, 0)) || (e->force)) {
+			pcb_stub_draw_csect(Output.fgGC);
+			pcb_gui->end_layer();
+		}
+	}
+	else if ((e->content.layer_id >= 0) && (e->content.layer_id < pcb_max_layer))
+		pcb_draw_layer(&(PCB->Data->Layer[e->content.layer_id]), &e->view);
+	else
+		pcb_message(PCB_MSG_ERROR, "Internal error: don't know how to draw layer %ld for preview; please report this bug.\n", e->content.layer_id);
+
+	expose_end(old_gui);
+}
+
+
diff --git a/src/draw.h b/src/draw.h
index fef538c..5a899c9 100644
--- a/src/draw.h
+++ b/src/draw.h
@@ -82,4 +82,17 @@ void pcb_draw_obj(int, void *, void *);
 void pcb_draw_layer(pcb_layer_t *, const pcb_box_t *);
 void pcb_erase_obj(int, void *, void *);
 
+/*#define PCB_BBOX_DEBUG*/
+
+#ifdef PCB_BBOX_DEBUG
+#define PCB_DRAW_BBOX(obj) \
+	do { \
+		pcb_gui->set_line_width(Output.fgGC, 0); \
+		pcb_gui->draw_rect(Output.fgGC, obj->BoundingBox.X1, obj->BoundingBox.Y1, obj->BoundingBox.X2, obj->BoundingBox.Y2); \
+	} while(0)
+#else
+#define PCB_DRAW_BBOX(obj)
+#endif
+
+
 #endif
diff --git a/src/file_act.c b/src/file_act.c
index d5857bf..7e69794 100644
--- a/src/file_act.c
+++ b/src/file_act.c
@@ -190,7 +190,7 @@ static int pcb_act_New(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y
 		if (PCB->Changed && conf_core.editor.save_in_tmp)
 			pcb_save_in_tmp();
 		pcb_board_remove(PCB);
-		PCB = pcb_board_new();
+		PCB = pcb_board_new(0);
 		pcb_board_new_postproc(PCB, 1);
 
 		/* setup the new name and reset some values to default */
diff --git a/src/find.c b/src/find.c
index 9fcaf3e..1ce5b94 100644
--- a/src/find.c
+++ b/src/find.c
@@ -146,8 +146,8 @@ static pcb_bool drc = pcb_false;				/* whether to stop if finding something not
 static pcb_bool IsBad = pcb_false;
 static pcb_cardinal_t drcerr_count;		/* count of drc errors */
 static pcb_cardinal_t TotalP, TotalV, NumberOfPads[2];
-static ListType LineList[PCB_MAX_LAYER],	/* list of objects to */
-  PolygonList[PCB_MAX_LAYER], ArcList[PCB_MAX_LAYER], PadList[2], RatList, PVList;
+static ListType LineList[PCB_MAX_LAYER+2],	/* list of objects to */
+  PolygonList[PCB_MAX_LAYER+2], ArcList[PCB_MAX_LAYER+2], PadList[2], RatList, PVList;
 
 /* ---------------------------------------------------------------------------
  * some local prototypes
diff --git a/src/find_lookup.c b/src/find_lookup.c
index b2cad8c..3e00e2f 100644
--- a/src/find_lookup.c
+++ b/src/find_lookup.c
@@ -66,6 +66,9 @@ static pcb_bool ADD_PV_TO_LIST(pcb_pin_t *Pin, int from_type, void *from_ptr, pc
 
 static pcb_bool ADD_PAD_TO_LIST(pcb_cardinal_t L, pcb_pad_t *Pad, int from_type, void *from_ptr, pcb_found_conn_type_t type)
 {
+	if (PadList[L].Data == NULL)
+		return pcb_false;
+
 /*fprintf(stderr, "ADD_PAD_TO_LIST cardinal %d %p %d\n", L, Pad, from_type);*/
 	if (User)
 		pcb_undo_add_obj_to_flag(PCB_TYPE_PAD, Pad->Element, Pad, Pad);
@@ -82,8 +85,10 @@ static pcb_bool ADD_PAD_TO_LIST(pcb_cardinal_t L, pcb_pad_t *Pad, int from_type,
 	return pcb_false;
 }
 
-static pcb_bool ADD_LINE_TO_LIST(pcb_cardinal_t L, pcb_line_t *Ptr, int from_type, void *from_ptr, pcb_found_conn_type_t type)
+static pcb_bool ADD_LINE_TO_LIST(pcb_layer_id_t L, pcb_line_t *Ptr, int from_type, void *from_ptr, pcb_found_conn_type_t type)
 {
+	if (LineList[L].Data == NULL)
+		return pcb_false;
 	if (User)
 		pcb_undo_add_obj_to_flag(PCB_TYPE_LINE, LAYER_PTR(L), (Ptr), (Ptr));
 	PCB_FLAG_SET(TheFlag, (Ptr));
@@ -101,6 +106,9 @@ static pcb_bool ADD_LINE_TO_LIST(pcb_cardinal_t L, pcb_line_t *Ptr, int from_typ
 
 static pcb_bool ADD_ARC_TO_LIST(pcb_cardinal_t L, pcb_arc_t *Ptr, int from_type, void *from_ptr, pcb_found_conn_type_t type)
 {
+	if (ArcList[L].Data == NULL)
+		return pcb_false;
+
 	if (User)
 		pcb_undo_add_obj_to_flag(PCB_TYPE_ARC, LAYER_PTR(L), (Ptr), (Ptr));
 	PCB_FLAG_SET(TheFlag, (Ptr));
@@ -135,6 +143,9 @@ static pcb_bool ADD_RAT_TO_LIST(pcb_rat_t *Ptr, int from_type, void *from_ptr, p
 
 static pcb_bool ADD_POLYGON_TO_LIST(pcb_cardinal_t L, pcb_polygon_t *Ptr, int from_type, void *from_ptr, pcb_found_conn_type_t type)
 {
+	if (PolygonList[L].Data == NULL)
+		return pcb_false;
+
 	if (User)
 		pcb_undo_add_obj_to_flag(PCB_TYPE_POLYGON, LAYER_PTR(L), (Ptr), (Ptr));
 	PCB_FLAG_SET(TheFlag, (Ptr));
@@ -170,7 +181,7 @@ void pcb_layout_lookup_uninit(void)
 {
 	pcb_cardinal_t i;
 
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		free(LineList[i].Data);
 		LineList[i].Data = NULL;
 		free(ArcList[i].Data);
@@ -233,12 +244,14 @@ void pcb_component_lookup_init(void)
  */
 void pcb_layout_lookup_init(void)
 {
-	pcb_cardinal_t i;
+	pcb_layer_id_t i;
 
 	/* initialize line arc and polygon data */
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for(i = 0; i < pcb_max_layer; i++) {
 		pcb_layer_t *layer = LAYER_PTR(i);
 
+		if (pcb_layer_flags(i) & PCB_LYT_COPPER) {
+
 		if (linelist_length(&layer->Line)) {
 			LineList[i].Size = linelist_length(&layer->Line);
 			LineList[i].Data = (void **) calloc(LineList[i].Size, sizeof(pcb_line_t *));
@@ -252,6 +265,8 @@ void pcb_layout_lookup_init(void)
 			PolygonList[i].Data = (void **) calloc(PolygonList[i].Size, sizeof(pcb_polygon_t *));
 		}
 
+		}
+
 		/* clear some struct members */
 		LineList[i].Location = 0;
 		LineList[i].DrawLocation = 0;
@@ -397,7 +412,9 @@ static pcb_bool LookupLOConnectionsToPVList(pcb_bool AndRats)
 			return pcb_true;
 
 		/* now all lines, arcs and polygons of the several layers */
-		for (layer = 0; layer < pcb_max_copper_layer; layer++) {
+		for(layer = 0; layer < pcb_max_layer; layer++) {
+			if (!(pcb_layer_flags(layer) & PCB_LYT_COPPER))
+				continue;
 			if (LAYER_PTR(layer)->no_drc)
 				continue;
 			info.layer = layer;
@@ -435,14 +452,16 @@ static pcb_bool LookupLOConnectionsToPVList(pcb_bool AndRats)
 static pcb_bool LookupLOConnectionsToLOList(pcb_bool AndRats)
 {
 	pcb_bool done;
-	pcb_cardinal_t i, group, layer, ratposition,
+	pcb_layer_id_t layer;
+	pcb_layergrp_id_t group;
+	pcb_cardinal_t i, ratposition,
 		lineposition[PCB_MAX_LAYER], polyposition[PCB_MAX_LAYER], arcposition[PCB_MAX_LAYER], padposition[2];
 
 	/* copy the current LO list positions; the original data is changed
 	 * by 'LookupPVConnectionsToLOList()' which has to check the same
 	 * list entries plus the new ones
 	 */
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		lineposition[i] = LineList[i].Location;
 		polyposition[i] = PolygonList[i].Location;
 		arcposition[i] = ArcList[i].Location;
@@ -456,6 +475,7 @@ static pcb_bool LookupLOConnectionsToLOList(pcb_bool AndRats)
 	 */
 	do {
 		pcb_cardinal_t *position;
+		unsigned int flg;
 
 		if (AndRats) {
 			position = &ratposition;
@@ -472,60 +492,58 @@ static pcb_bool LookupLOConnectionsToLOList(pcb_bool AndRats)
 		for (group = 0; group < pcb_max_group; group++) {
 			pcb_cardinal_t entry;
 
-			for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) {
-				layer = PCB->LayerGroups.Entries[group][entry];
+			for (entry = 0; entry < PCB->LayerGroups.grp[group].len; entry++) {
+				layer = PCB->LayerGroups.grp[group].lid[entry];
 
-				/* be aware that the layer number equal pcb_max_copper_layer
-				 * and pcb_max_copper_layer+1 have a special meaning for pads
+				/* be aware that the layer number equal pcb_max_layer
+				 * and pcb_max_layer+1 have a special meaning for pads
 				 */
-				if (layer < pcb_max_copper_layer) {
-					/* try all new lines */
-					position = &lineposition[layer];
-					for (; *position < LineList[layer].Number; (*position)++)
-						if (LookupLOConnectionsToLine(LINELIST_ENTRY(layer, *position), group, pcb_true))
-							return (pcb_true);
-
-					/* try all new arcs */
-					position = &arcposition[layer];
-					for (; *position < ArcList[layer].Number; (*position)++)
-						if (LookupLOConnectionsToArc(ARCLIST_ENTRY(layer, *position), group))
-							return (pcb_true);
-
-					/* try all new polygons */
-					position = &polyposition[layer];
-					for (; *position < PolygonList[layer].Number; (*position)++)
-						if (LookupLOConnectionsToPolygon(POLYGONLIST_ENTRY(layer, *position), group))
-							return (pcb_true);
-				}
-				else {
-					/* try all new pads */
-					layer -= pcb_max_copper_layer;
-					if (layer > 1) {
-						pcb_message(PCB_MSG_ERROR, _("bad layer number %d pcb_max_copper_layer=%d in find.c\n"), layer, pcb_max_copper_layer);
-						return pcb_false;
-					}
-					position = &padposition[layer];
-					for (; *position < PadList[layer].Number; (*position)++)
-						if (LookupLOConnectionsToPad(PADLIST_ENTRY(layer, *position), group))
-							return (pcb_true);
-				}
+				/* try all new lines */
+				position = &lineposition[layer];
+				for (; *position < LineList[layer].Number; (*position)++)
+					if (LookupLOConnectionsToLine(LINELIST_ENTRY(layer, *position), group, pcb_true))
+						return (pcb_true);
+
+				/* try all new arcs */
+				position = &arcposition[layer];
+				for (; *position < ArcList[layer].Number; (*position)++)
+					if (LookupLOConnectionsToArc(ARCLIST_ENTRY(layer, *position), group))
+						return (pcb_true);
+
+				/* try all new polygons */
+				position = &polyposition[layer];
+				for (; *position < PolygonList[layer].Number; (*position)++)
+					if (LookupLOConnectionsToPolygon(POLYGONLIST_ENTRY(layer, *position), group))
+						return (pcb_true);
 			}
+
+			/* try all new pads */
+			/* handle the special pad layers */
+			flg = pcb_layergrp_flags(group);
+			if ((flg & PCB_LYT_BOTTOM) && (flg & PCB_LYT_COPPER))    layer = PCB_SOLDER_SIDE;
+			else if ((flg & PCB_LYT_TOP) && (flg & PCB_LYT_COPPER))  layer = PCB_COMPONENT_SIDE;
+			else continue; /* skip pads for this group */
+
+			position = &padposition[layer];
+			for (; *position < PadList[layer].Number; (*position)++)
+				if (LookupLOConnectionsToPad(PADLIST_ENTRY(layer, *position), group))
+					return (pcb_true);
 		}
 
 		/* check if all lists are done; Later for-loops
 		 * may have changed the prior lists
 		 */
 		done = !AndRats || ratposition >= RatList.Number;
-		for (layer = 0; layer < pcb_max_copper_layer + 2; layer++) {
-			if (layer < pcb_max_copper_layer)
-				done = done &&
-					lineposition[layer] >= LineList[layer].Number
-					&& arcposition[layer] >= ArcList[layer].Number && polyposition[layer] >= PolygonList[layer].Number;
-			else
-				done = done && padposition[layer - pcb_max_copper_layer] >= PadList[layer - pcb_max_copper_layer].Number;
+		for (layer = 0; layer < pcb_max_layer; layer++) {
+			done = done &&
+				lineposition[layer] >= LineList[layer].Number
+				&& arcposition[layer] >= ArcList[layer].Number && polyposition[layer] >= PolygonList[layer].Number;
 		}
-	}
-	while (!done);
+
+		/* check the two special pad layers */
+		for (layer = 0; layer < 2; layer++)
+			done = done && padposition[layer] >= PadList[layer].Number;
+	} while (!done);
 	return (pcb_false);
 }
 
@@ -708,11 +726,13 @@ static pcb_r_dir_t pv_rat_callback(const pcb_box_t * b, void *cl)
  */
 static pcb_bool LookupPVConnectionsToLOList(pcb_bool AndRats)
 {
-	pcb_cardinal_t layer;
+	pcb_layer_id_t layer;
 	struct lo_info info;
 
 	/* loop over all layers */
-	for (layer = 0; layer < pcb_max_copper_layer; layer++) {
+	for(layer = 0; layer < pcb_max_layer; layer++) {
+		if (!(pcb_layer_flags(layer) & PCB_LYT_COPPER))
+			continue;
 		if (LAYER_PTR(layer)->no_drc)
 			continue;
 		/* do nothing if there are no PV's */
@@ -873,48 +893,50 @@ static pcb_bool LookupLOConnectionsToArc(pcb_arc_t *Arc, pcb_cardinal_t LayerGro
 {
 	pcb_cardinal_t entry;
 	struct lo_info info;
+	unsigned int flg;
 
 	info.arc = *Arc;
 	EXPAND_BOUNDS(&info.arc);
 	/* loop over all layers of the group */
-	for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) {
-		pcb_cardinal_t layer;
+	for (entry = 0; entry < PCB->LayerGroups.grp[LayerGroup].len; entry++) {
+		pcb_layer_id_t layer;
+		pcb_polygon_t *polygon;
+		gdl_iterator_t it;
 
-		layer = PCB->LayerGroups.Entries[LayerGroup][entry];
+		layer = PCB->LayerGroups.grp[LayerGroup].lid[entry];
 
-		/* handle normal layers */
-		if (layer < pcb_max_copper_layer) {
-			pcb_polygon_t *polygon;
-			gdl_iterator_t it;
+		info.layer = layer;
+		/* add arcs */
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->line_tree, &info.arc.BoundingBox, NULL, LOCtoArcLine_callback, &info, NULL);
+		else
+			return pcb_true;
 
-			info.layer = layer;
-			/* add arcs */
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->line_tree, &info.arc.BoundingBox, NULL, LOCtoArcLine_callback, &info, NULL);
-			else
-				return pcb_true;
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->arc_tree, &info.arc.BoundingBox, NULL, LOCtoArcArc_callback, &info, NULL);
+		else
+			return pcb_true;
 
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->arc_tree, &info.arc.BoundingBox, NULL, LOCtoArcArc_callback, &info, NULL);
-			else
-				return pcb_true;
-
-			/* now check all polygons */
-			polylist_foreach(&(PCB->Data->Layer[layer].Polygon), &it, polygon) {
-				if (!PCB_FLAG_TEST(TheFlag, polygon) && pcb_is_arc_in_poly(Arc, polygon)
-						&& ADD_POLYGON_TO_LIST(layer, polygon, PCB_TYPE_ARC, Arc, PCB_FCT_COPPER))
-					return pcb_true;
-			}
-		}
-		else {
-			info.layer = layer - pcb_max_copper_layer;
-			if (setjmp(info.env) == 0)
-				pcb_r_search(PCB->Data->pad_tree, &info.arc.BoundingBox, NULL, LOCtoArcPad_callback, &info, NULL);
-			else
+		/* now check all polygons */
+		polylist_foreach(&(PCB->Data->Layer[layer].Polygon), &it, polygon) {
+			if (!PCB_FLAG_TEST(TheFlag, polygon) && pcb_is_arc_in_poly(Arc, polygon)
+					&& ADD_POLYGON_TO_LIST(layer, polygon, PCB_TYPE_ARC, Arc, PCB_FCT_COPPER))
 				return pcb_true;
 		}
 	}
-	return (pcb_false);
+
+	/* handle the special pad layers */
+	flg = pcb_layergrp_flags(LayerGroup);
+	if ((flg & PCB_LYT_BOTTOM) && (flg & PCB_LYT_COPPER))    info.layer = PCB_SOLDER_SIDE;
+	else if ((flg & PCB_LYT_TOP) && (flg & PCB_LYT_COPPER))  info.layer = PCB_COMPONENT_SIDE;
+	else return pcb_false;
+
+	if (setjmp(info.env) == 0)
+		pcb_r_search(PCB->Data->pad_tree, &info.arc.BoundingBox, NULL, LOCtoArcPad_callback, &info, NULL);
+	else
+		return pcb_true;
+
+	return pcb_false;
 }
 
 static pcb_r_dir_t LOCtoLineLine_callback(const pcb_box_t * b, void *cl)
@@ -985,6 +1007,7 @@ static pcb_bool LookupLOConnectionsToLine(pcb_line_t *Line, pcb_cardinal_t Layer
 {
 	pcb_cardinal_t entry;
 	struct lo_info info;
+	unsigned int flg;
 
 	info.line = *Line;
 	info.layer = LayerGroup;
@@ -996,46 +1019,47 @@ static pcb_bool LookupLOConnectionsToLine(pcb_line_t *Line, pcb_cardinal_t Layer
 		return pcb_true;
 
 	/* loop over all layers of the group */
-	for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) {
-		pcb_cardinal_t layer;
+	for (entry = 0; entry < PCB->LayerGroups.grp[LayerGroup].len; entry++) {
+		pcb_layer_id_t layer;
 
-		layer = PCB->LayerGroups.Entries[LayerGroup][entry];
+		layer = PCB->LayerGroups.grp[LayerGroup].lid[entry];
 
-		/* handle normal layers */
-		if (layer < pcb_max_copper_layer) {
-			info.layer = layer;
-			/* add lines */
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->line_tree, (pcb_box_t *) & info.line, NULL, LOCtoLineLine_callback, &info, NULL);
-			else
-				return pcb_true;
-			/* add arcs */
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->arc_tree, (pcb_box_t *) & info.line, NULL, LOCtoLineArc_callback, &info, NULL);
-			else
-				return pcb_true;
-			/* now check all polygons */
-			if (PolysTo) {
-				gdl_iterator_t it;
-				pcb_polygon_t *polygon;
-
-				polylist_foreach(&(PCB->Data->Layer[layer].Polygon), &it, polygon) {
-					if (!PCB_FLAG_TEST(TheFlag, polygon) && pcb_is_line_in_poly(Line, polygon)
-							&& ADD_POLYGON_TO_LIST(layer, polygon, PCB_TYPE_LINE, Line, PCB_FCT_COPPER))
-						return pcb_true;
-				}
+		info.layer = layer;
+		/* add lines */
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->line_tree, (pcb_box_t *) & info.line, NULL, LOCtoLineLine_callback, &info, NULL);
+		else
+			return pcb_true;
+		/* add arcs */
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->arc_tree, (pcb_box_t *) & info.line, NULL, LOCtoLineArc_callback, &info, NULL);
+		else
+			return pcb_true;
+		/* now check all polygons */
+		if (PolysTo) {
+			gdl_iterator_t it;
+			pcb_polygon_t *polygon;
+
+			polylist_foreach(&(PCB->Data->Layer[layer].Polygon), &it, polygon) {
+				if (!PCB_FLAG_TEST(TheFlag, polygon) && pcb_is_line_in_poly(Line, polygon)
+						&& ADD_POLYGON_TO_LIST(layer, polygon, PCB_TYPE_LINE, Line, PCB_FCT_COPPER))
+					return pcb_true;
 			}
 		}
-		else {
-			/* handle special 'pad' layers */
-			info.layer = layer - pcb_max_copper_layer;
-			if (setjmp(info.env) == 0)
-				pcb_r_search(PCB->Data->pad_tree, &info.line.BoundingBox, NULL, LOCtoLinePad_callback, &info, NULL);
-			else
-				return pcb_true;
-		}
 	}
-	return (pcb_false);
+
+	/* handle the special pad layers */
+	flg = pcb_layergrp_flags(LayerGroup);
+	if ((flg & PCB_LYT_BOTTOM) && (flg & PCB_LYT_COPPER))    info.layer = PCB_SOLDER_SIDE;
+	else if ((flg & PCB_LYT_TOP) && (flg & PCB_LYT_COPPER))  info.layer = PCB_COMPONENT_SIDE;
+	else return pcb_false;
+
+	if (setjmp(info.env) == 0)
+		pcb_r_search(PCB->Data->pad_tree, &info.line.BoundingBox, NULL, LOCtoLinePad_callback, &info, NULL);
+	else
+		return pcb_true;
+
+	return pcb_false;
 }
 
 
@@ -1100,37 +1124,36 @@ static pcb_bool LookupLOConnectionsToRatEnd(pcb_point_t *Point, pcb_cardinal_t L
 {
 	pcb_cardinal_t entry;
 	struct rat_info info;
+	unsigned int flg;
 
 	info.Point = Point;
 	/* loop over all layers of this group */
-	for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) {
-		pcb_cardinal_t layer;
+	for (entry = 0; entry < PCB->LayerGroups.grp[LayerGroup].len; entry++) {
+		pcb_layer_id_t layer;
 
-		layer = PCB->LayerGroups.Entries[LayerGroup][entry];
-		/* handle normal layers
-		   rats don't ever touch
-		   arcs by definition
-		 */
-
-		if (layer < pcb_max_copper_layer) {
-			info.layer = layer;
-			if (setjmp(info.env) == 0)
-				r_search_pt(LAYER_PTR(layer)->line_tree, Point, 1, NULL, LOCtoRat_callback, &info, NULL);
-			else
-				return pcb_true;
-			if (setjmp(info.env) == 0)
-				r_search_pt(LAYER_PTR(layer)->polygon_tree, Point, 1, NULL, PolygonToRat_callback, &info, NULL);
-		}
-		else {
-			/* handle special 'pad' layers */
-			info.layer = layer - pcb_max_copper_layer;
-			if (setjmp(info.env) == 0)
-				r_search_pt(PCB->Data->pad_tree, Point, 1, NULL, LOCtoPad_callback, &info, NULL);
-			else
-				return pcb_true;
-		}
+		layer = PCB->LayerGroups.grp[LayerGroup].lid[entry];
+		/* handle normal layers rats don't ever touch arcs by definition */
+		info.layer = layer;
+		if (setjmp(info.env) == 0)
+			r_search_pt(LAYER_PTR(layer)->line_tree, Point, 1, NULL, LOCtoRat_callback, &info, NULL);
+		else
+			return pcb_true;
+		if (setjmp(info.env) == 0)
+			r_search_pt(LAYER_PTR(layer)->polygon_tree, Point, 1, NULL, PolygonToRat_callback, &info, NULL);
 	}
-	return (pcb_false);
+
+	/* handle the special pad layers */
+	flg = pcb_layergrp_flags(LayerGroup);
+	if ((flg & PCB_LYT_BOTTOM) && (flg & PCB_LYT_COPPER))    info.layer = PCB_SOLDER_SIDE;
+	else if ((flg & PCB_LYT_TOP) && (flg & PCB_LYT_COPPER))  info.layer = PCB_COMPONENT_SIDE;
+	else return pcb_false;
+
+	if (setjmp(info.env) == 0)
+		r_search_pt(PCB->Data->pad_tree, Point, 1, NULL, LOCtoPad_callback, &info, NULL);
+	else
+		return pcb_true;
+
+	return pcb_false;
 }
 
 static pcb_r_dir_t LOCtoPadLine_callback(const pcb_box_t * b, void *cl)
@@ -1219,6 +1242,7 @@ static pcb_bool LookupLOConnectionsToPad(pcb_pad_t *Pad, pcb_cardinal_t LayerGro
 	struct lo_info info;
 	int ic;
 	pcb_bool retv = pcb_false;
+	unsigned int flg;
 
 	/* Internal connection: if pads in the same element have the same
 	   internal connection group number, they are connected */
@@ -1229,9 +1253,9 @@ static pcb_bool LookupLOConnectionsToPad(pcb_pad_t *Pad, pcb_cardinal_t LayerGro
 		int tlayer = -1;
 
 /*fprintf(stderr, "lg===\n");*/
-		for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) {
-			pcb_cardinal_t layer;
-			layer = PCB->LayerGroups.Entries[LayerGroup][entry];
+		for (entry = 0; entry < PCB->LayerGroups.grp[LayerGroup].len; entry++) {
+			pcb_layer_id_t layer;
+			layer = PCB->LayerGroups.grp[LayerGroup].lid[entry];
 /*fprintf(stderr, "lg: %d\n", layer);*/
 			if (layer == PCB_COMPONENT_SIDE)
 				tlayer = PCB_COMPONENT_SIDE;
@@ -1273,39 +1297,41 @@ static pcb_bool LookupLOConnectionsToPad(pcb_pad_t *Pad, pcb_cardinal_t LayerGro
 		return pcb_true;
 
 	/* loop over all layers of the group */
-	for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) {
-		pcb_cardinal_t layer;
+	for (entry = 0; entry < PCB->LayerGroups.grp[LayerGroup].len; entry++) {
+		pcb_layer_id_t layer;
 
-		layer = PCB->LayerGroups.Entries[LayerGroup][entry];
+		layer = PCB->LayerGroups.grp[LayerGroup].lid[entry];
 		/* handle normal layers */
-		if (layer < pcb_max_copper_layer) {
-			info.layer = layer;
-			/* add lines */
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->line_tree, &info.pad.BoundingBox, NULL, LOCtoPadLine_callback, &info, NULL);
-			else
-				return pcb_true;
-			/* add arcs */
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->arc_tree, &info.pad.BoundingBox, NULL, LOCtoPadArc_callback, &info, NULL);
-			else
-				return pcb_true;
-			/* add polygons */
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->polygon_tree, &info.pad.BoundingBox, NULL, LOCtoPadPoly_callback, &info, NULL);
-			else
-				return pcb_true;
-		}
-		else {
-			/* handle special 'pad' layers */
-			info.layer = layer - pcb_max_copper_layer;
-			if (setjmp(info.env) == 0)
-				pcb_r_search(PCB->Data->pad_tree, (pcb_box_t *) & info.pad, NULL, LOCtoPadPad_callback, &info, NULL);
-			else
-				return pcb_true;
-		}
 
+		info.layer = layer;
+		/* add lines */
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->line_tree, &info.pad.BoundingBox, NULL, LOCtoPadLine_callback, &info, NULL);
+		else
+			return pcb_true;
+		/* add arcs */
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->arc_tree, &info.pad.BoundingBox, NULL, LOCtoPadArc_callback, &info, NULL);
+		else
+			return pcb_true;
+		/* add polygons */
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->polygon_tree, &info.pad.BoundingBox, NULL, LOCtoPadPoly_callback, &info, NULL);
+		else
+			return pcb_true;
 	}
+
+	/* handle the special pad layers */
+	flg = pcb_layergrp_flags(LayerGroup);
+	if ((flg & PCB_LYT_BOTTOM) && (flg & PCB_LYT_COPPER))    info.layer = PCB_SOLDER_SIDE;
+	else if ((flg & PCB_LYT_TOP) && (flg & PCB_LYT_COPPER))  info.layer = PCB_COMPONENT_SIDE;
+	else return retv;
+
+	if (setjmp(info.env) == 0)
+		pcb_r_search(PCB->Data->pad_tree, (pcb_box_t *) & info.pad, NULL, LOCtoPadPad_callback, &info, NULL);
+	else
+		return pcb_true;
+
 	return retv;
 }
 
@@ -1374,6 +1400,7 @@ static pcb_bool LookupLOConnectionsToPolygon(pcb_polygon_t *Polygon, pcb_cardina
 {
 	pcb_cardinal_t entry;
 	struct lo_info info;
+	unsigned int flg;
 
 	if (!Polygon->Clipped)
 		return pcb_false;
@@ -1386,43 +1413,45 @@ static pcb_bool LookupLOConnectionsToPolygon(pcb_polygon_t *Polygon, pcb_cardina
 	else
 		return pcb_true;
 /* loop over all layers of the group */
-	for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) {
-		pcb_cardinal_t layer;
+	for (entry = 0; entry < PCB->LayerGroups.grp[LayerGroup].len; entry++) {
+		pcb_layer_id_t layer;
+		gdl_iterator_t it;
+		pcb_polygon_t *polygon;
 
-		layer = PCB->LayerGroups.Entries[LayerGroup][entry];
+		layer = PCB->LayerGroups.grp[LayerGroup].lid[entry];
 
 		/* handle normal layers */
-		if (layer < pcb_max_copper_layer) {
-			gdl_iterator_t it;
-			pcb_polygon_t *polygon;
-
-			/* check all polygons */
-			polylist_foreach(&(PCB->Data->Layer[layer].Polygon), &it, polygon) {
-				if (!PCB_FLAG_TEST(TheFlag, polygon)
-						&& pcb_is_poly_in_poly(polygon, Polygon)
-						&& ADD_POLYGON_TO_LIST(layer, polygon, PCB_TYPE_POLYGON, Polygon, PCB_FCT_COPPER))
-					return pcb_true;
-			}
-
-			info.layer = layer;
-			/* check all lines */
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->line_tree, (pcb_box_t *) & info.polygon, NULL, LOCtoPolyLine_callback, &info, NULL);
-			else
-				return pcb_true;
-			/* check all arcs */
-			if (setjmp(info.env) == 0)
-				pcb_r_search(LAYER_PTR(layer)->arc_tree, (pcb_box_t *) & info.polygon, NULL, LOCtoPolyArc_callback, &info, NULL);
-			else
-				return pcb_true;
-		}
-		else {
-			info.layer = layer - pcb_max_copper_layer;
-			if (setjmp(info.env) == 0)
-				pcb_r_search(PCB->Data->pad_tree, (pcb_box_t *) & info.polygon, NULL, LOCtoPolyPad_callback, &info, NULL);
-			else
+		/* check all polygons */
+		polylist_foreach(&(PCB->Data->Layer[layer].Polygon), &it, polygon) {
+			if (!PCB_FLAG_TEST(TheFlag, polygon)
+					&& pcb_is_poly_in_poly(polygon, Polygon)
+					&& ADD_POLYGON_TO_LIST(layer, polygon, PCB_TYPE_POLYGON, Polygon, PCB_FCT_COPPER))
 				return pcb_true;
 		}
+
+		info.layer = layer;
+		/* check all lines */
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->line_tree, (pcb_box_t *) & info.polygon, NULL, LOCtoPolyLine_callback, &info, NULL);
+		else
+			return pcb_true;
+		/* check all arcs */
+		if (setjmp(info.env) == 0)
+			pcb_r_search(LAYER_PTR(layer)->arc_tree, (pcb_box_t *) & info.polygon, NULL, LOCtoPolyArc_callback, &info, NULL);
+		else
+			return pcb_true;
 	}
-	return (pcb_false);
+
+	/* handle the special pad layers */
+	flg = pcb_layergrp_flags(LayerGroup);
+	if ((flg & PCB_LYT_BOTTOM) && (flg & PCB_LYT_COPPER))    info.layer = PCB_SOLDER_SIDE;
+	else if ((flg & PCB_LYT_TOP) && (flg & PCB_LYT_COPPER))  info.layer = PCB_COMPONENT_SIDE;
+	else return pcb_false;
+
+	if (setjmp(info.env) == 0)
+		pcb_r_search(PCB->Data->pad_tree, (pcb_box_t *) & info.polygon, NULL, LOCtoPolyPad_callback, &info, NULL);
+	else
+		return pcb_true;
+
+	return pcb_false;
 }
diff --git a/src/find_misc.c b/src/find_misc.c
index ec7696b..45f21d3 100644
--- a/src/find_misc.c
+++ b/src/find_misc.c
@@ -38,7 +38,7 @@ static pcb_bool ListsEmpty(pcb_bool AndRats)
 	empty = (PVList.Location >= PVList.Number);
 	if (AndRats)
 		empty = empty && (RatList.Location >= RatList.Number);
-	for (i = 0; i < pcb_max_copper_layer && empty; i++)
+	for (i = 0; i < pcb_max_layer && empty; i++)
 		empty = empty && LineList[i].Location >= LineList[i].Number
 			&& ArcList[i].Location >= ArcList[i].Number && PolygonList[i].Location >= PolygonList[i].Number;
 	return (empty);
@@ -47,8 +47,8 @@ static pcb_bool ListsEmpty(pcb_bool AndRats)
 static void reassign_no_drc_flags(void)
 {
 	int layer;
-
-	for (layer = 0; layer < pcb_max_copper_layer; layer++) {
+#warning layer TODO: decide whether it is from attribute or not
+	for (layer = 0; layer < pcb_max_layer; layer++) {
 		pcb_layer_t *l = LAYER_PTR(layer);
 		l->no_drc = pcb_attrib_get(l, "PCB::skip-drc") != NULL;
 	}
@@ -87,7 +87,7 @@ static void DrawNewConnections(void)
 	pcb_cardinal_t position;
 
 	/* decrement 'i' to keep layerstack order */
-	for (i = pcb_max_copper_layer - 1; i != -1; i--) {
+	for (i = pcb_max_layer; i != -1; i--) {
 		pcb_cardinal_t layer = pcb_layer_stack[i];
 
 		if (PCB->Data->Layer[layer].On) {
@@ -230,7 +230,7 @@ void pcb_lookup_conn(pcb_coord_t X, pcb_coord_t Y, pcb_bool AndDraw, pcb_coord_t
 			pcb_layer_id_t laynum = pcb_layer_id(PCB->Data, (pcb_layer_t *) ptr1);
 
 			/* don't mess with non-conducting objects! */
-			if (laynum >= pcb_max_copper_layer || ((pcb_layer_t *) ptr1)->no_drc)
+			if (!(pcb_layer_flags(laynum) & PCB_LYT_COPPER) || ((pcb_layer_t *) ptr1)->no_drc)
 				return;
 		}
 	}
@@ -426,7 +426,7 @@ static void DumpList(void)
 	PVList.Number = 0;
 	PVList.Location = 0;
 
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		LineList[i].Location = 0;
 		LineList[i].DrawLocation = 0;
 		LineList[i].Number = 0;
diff --git a/src/find_print.c b/src/find_print.c
index 051bbc1..a70fdd5 100644
--- a/src/find_print.c
+++ b/src/find_print.c
@@ -135,7 +135,7 @@ static pcb_bool PrepareNextLoop(FILE * FP)
 	pcb_cardinal_t layer;
 
 	/* reset found LOs for the next pin */
-	for (layer = 0; layer < pcb_max_copper_layer; layer++) {
+	for (layer = 0; layer < pcb_max_layer; layer++) {
 		LineList[layer].Location = LineList[layer].Number = 0;
 		ArcList[layer].Location = ArcList[layer].Number = 0;
 		PolygonList[layer].Location = PolygonList[layer].Number = 0;
diff --git a/src/font.c b/src/font.c
index 33bc51a..9d1a379 100644
--- a/src/font.c
+++ b/src/font.c
@@ -40,6 +40,45 @@
 
 #define STEP_SYMBOLLINE 10
 
+typedef struct embf_line_s {
+	int x1, y1, x2, y2, th;
+} embf_line_t;
+
+typedef struct embf_font_s {
+	int delta;
+	embf_line_t *lines;
+	int num_lines;
+} embf_font_t;
+
+#include "font_internal.c"
+
+static void pcb_font_load_internal(pcb_board_t *pcb)
+{
+	int n, l;
+	memset(&pcb->Font, 0, sizeof(pcb->Font));
+	pcb->Font.MaxWidth  = embf_maxx - embf_minx;
+	pcb->Font.MaxHeight = embf_maxy - embf_miny;
+	for(n = 0; n < sizeof(embf_font) / sizeof(embf_font[0]); n++) {
+		if (embf_font[n].delta != 0) {
+			pcb_symbol_t *s = pcb->Font.Symbol + n;
+			embf_line_t *lines = embf_font[n].lines;
+
+			for(l = 0; l < embf_font[n].num_lines; l++) {
+				pcb_coord_t x1 = PCB_MIL_TO_COORD(lines[l].x1);
+				pcb_coord_t y1 = PCB_MIL_TO_COORD(lines[l].y1);
+				pcb_coord_t x2 = PCB_MIL_TO_COORD(lines[l].x2);
+				pcb_coord_t y2 = PCB_MIL_TO_COORD(lines[l].y2);
+				pcb_coord_t th = PCB_MIL_TO_COORD(lines[l].th);
+				pcb_font_new_line_in_sym(s, x1, y1, x2, y2, th);
+			}
+
+			s->Valid = 1;
+			s->Delta = PCB_MIL_TO_COORD(embf_font[n].delta);
+		}
+	}
+	pcb_font_set_info(&pcb->Font);
+}
+
 /* parses a file with font information and installs it into the provided PCB
  * checks directories given as colon separated list by resource fontPath
  * if the fonts filename doesn't contain a directory component */
@@ -54,7 +93,8 @@ void pcb_font_create_default(pcb_board_t *pcb)
 		const char *s;
 		gds_t buff;
 		s = conf_concat_strlist(&conf_core.rc.default_font_file, &buff, NULL, ':');
-		pcb_message(PCB_MSG_ERROR, _("Can't find font-symbol-file - there won't be font in this design. Searched: '%s'\n"), s);
+		pcb_message(PCB_MSG_WARNING, _("Can't find font-symbol-file. Searched: '%s'; falling back to the embedded default font\n"), s);
+		pcb_font_load_internal(pcb);
 		gds_uninit(&buff);
 	}
 }
diff --git a/src/font_internal.c b/src/font_internal.c
new file mode 100644
index 0000000..729ec47
--- /dev/null
+++ b/src/font_internal.c
@@ -0,0 +1,818 @@
+/* This file is autogenerated by font2c.sh - DO NOT EDIT */
+
+/* Internal copy of the default font; used when no font file is found */
+
+static embf_line_t embf_line_32[] = {
+	{0,0,0,0}
+};
+static embf_line_t embf_line_33[] = { /* ! */
+	{0, 35,		0, 40,		8},
+	{0, 0,		0, 25,		8}
+};
+static embf_line_t embf_line_34[] = { /* " */
+	{0, 0,		0, 10,		8},
+	{10, 0,		10, 10,		8}
+};
+static embf_line_t embf_line_35[] = { /* # */
+	{0, 25,		20, 25,		8},
+	{0, 15,		20, 15,		8},
+	{15, 10,		15, 30,		8},
+	{5, 10,		5, 30,		8}
+};
+static embf_line_t embf_line_36[] = { /* $ */
+	{15, 5,		20, 10,		8},
+	{5, 5,		15, 5,		8},
+	{0, 10,		5, 5,		8},
+	{0, 10,		0, 15,		8},
+	{0, 15,		5, 20,		8},
+	{5, 20,		15, 20,		8},
+	{15, 20,		20, 25,		8},
+	{20, 25,		20, 30,		8},
+	{15, 35,		20, 30,		8},
+	{5, 35,		15, 35,		8},
+	{0, 30,		5, 35,		8},
+	{10, 0,		10, 40,		8}
+};
+static embf_line_t embf_line_37[] = { /* % */
+	{0, 5,		0, 10,		8},
+	{0, 5,		5, 0,		8},
+	{5, 0,		10, 0,		8},
+	{10, 0,		15, 5,		8},
+	{15, 5,		15, 10,		8},
+	{10, 15,		15, 10,		8},
+	{5, 15,		10, 15,		8},
+	{0, 10,		5, 15,		8},
+	{0, 40,		40, 0,		8},
+	{35, 40,		40, 35,		8},
+	{40, 30,		40, 35,		8},
+	{35, 25,		40, 30,		8},
+	{30, 25,		35, 25,		8},
+	{25, 30,		30, 25,		8},
+	{25, 30,		25, 35,		8},
+	{25, 35,		30, 40,		8},
+	{30, 40,		35, 40,		8}
+};
+static embf_line_t embf_line_38[] = { /* & */
+	{0, 35,		5, 40,		8},
+	{0, 5,		0, 15,		8},
+	{0, 5,		5, 0,		8},
+	{0, 25,		15, 10,		8},
+	{5, 40,		10, 40,		8},
+	{10, 40,		20, 30,		8},
+	{0, 15,		25, 40,		8},
+	{5, 0,		10, 0,		8},
+	{10, 0,		15, 5,		8},
+	{15, 5,		15, 10,		8},
+	{0, 25,		0, 35,		8}
+};
+static embf_line_t embf_line_39[] = { /* ' */
+	{0, 10,		10, 0,		8}
+};
+static embf_line_t embf_line_40[] = {
+	{0, 35,		5, 40,		8},
+	{0, 5,		5, 0,		8},
+	{0, 5,		0, 35,		8}
+};
+static embf_line_t embf_line_41[] = {
+	{0, 0,		5, 5,		8},
+	{5, 5,		5, 35,		8},
+	{0, 40,		5, 35,		8}
+};
+static embf_line_t embf_line_42[] = { /* * */
+	{0, 10,		20, 30,		8},
+	{0, 30,		20, 10,		8},
+	{0, 20,		20, 20,		8},
+	{10, 10,		10, 30,		8}
+};
+static embf_line_t embf_line_43[] = { /* + */
+	{0, 20,		20, 20,		8},
+	{10, 10,		10, 30,		8}
+};
+static embf_line_t embf_line_44[] = { /* , */
+	{0, 50,		10, 40,		8}
+};
+static embf_line_t embf_line_45[] = { /* - */
+	{0, 20,		20, 20,		8}
+};
+static embf_line_t embf_line_46[] = { /* . */
+	{0, 40,		5, 40,		8}
+};
+static embf_line_t embf_line_47[] = { /* / */
+	{0, 35,		30, 5,		8}
+};
+static embf_line_t embf_line_48[] = { /* 0 */
+	{0, 35,		5, 40,		8},
+	{0, 5,		0, 35,		8},
+	{0, 5,		5, 0,		8},
+	{5, 0,		15, 0,		8},
+	{15, 0,		20, 5,		8},
+	{20, 5,		20, 35,		8},
+	{15, 40,		20, 35,		8},
+	{5, 40,		15, 40,		8},
+	{0, 30,		20, 10,		8}
+};
+static embf_line_t embf_line_49[] = { /* 1 */
+	{0, 8,		8, 0,		8},
+	{8, 0,		8, 40,		8},
+	{0, 40,		15, 40,		8}
+};
+static embf_line_t embf_line_50[] = { /* 2 */
+	{0, 5,		5, 0,		8},
+	{5, 0,		20, 0,		8},
+	{20, 0,		25, 5,		8},
+	{25, 5,		25, 15,		8},
+	{0, 40,		25, 15,		8},
+	{0, 40,		25, 40,		8}
+};
+static embf_line_t embf_line_51[] = { /* 3 */
+	{0, 5,		5, 0,		8},
+	{5, 0,		15, 0,		8},
+	{15, 0,		20, 5,		8},
+	{15, 40,		20, 35,		8},
+	{5, 40,		15, 40,		8},
+	{0, 35,		5, 40,		8},
+	{5, 18,		15, 18,		8},
+	{20, 5,		20, 13,		8},
+	{20, 23,		20, 35,		8},
+	{20, 23,		15, 18,		8},
+	{20, 13,		15, 18,		8}
+};
+static embf_line_t embf_line_52[] = { /* 4 */
+	{0, 25,		20, 0,		8},
+	{0, 25,		25, 25,		8},
+	{20, 0,		20, 40,		8}
+};
+static embf_line_t embf_line_53[] = { /* 5 */
+	{0, 0,		20, 0,		8},
+	{0, 0,		0, 20,		8},
+	{0, 20,		5, 15,		8},
+	{5, 15,		15, 15,		8},
+	{15, 15,		20, 20,		8},
+	{20, 20,		20, 35,		8},
+	{15, 40,		20, 35,		8},
+	{5, 40,		15, 40,		8},
+	{0, 35,		5, 40,		8}
+};
+static embf_line_t embf_line_54[] = { /* 6 */
+	{15, 0,		20, 5,		8},
+	{5, 0,		15, 0,		8},
+	{0, 5,		5, 0,		8},
+	{0, 5,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{15, 18,		20, 23,		8},
+	{0, 18,		15, 18,		8},
+	{5, 40,		15, 40,		8},
+	{15, 40,		20, 35,		8},
+	{20, 23,		20, 35,		8}
+};
+static embf_line_t embf_line_55[] = { /* 7 */
+	{5, 40,		25, 0,		8},
+	{0, 0,		25, 0,		8}
+};
+static embf_line_t embf_line_56[] = { /* 8 */
+	{0, 35,		5, 40,		8},
+	{0, 27,		0, 35,		8},
+	{0, 27,		7, 20,		8},
+	{7, 20,		13, 20,		8},
+	{13, 20,		20, 27,		8},
+	{20, 27,		20, 35,		8},
+	{15, 40,		20, 35,		8},
+	{5, 40,		15, 40,		8},
+	{0, 13,		7, 20,		8},
+	{0, 5,		0, 13,		8},
+	{0, 5,		5, 0,		8},
+	{5, 0,		15, 0,		8},
+	{15, 0,		20, 5,		8},
+	{20, 5,		20, 13,		8},
+	{13, 20,		20, 13,		8}
+};
+static embf_line_t embf_line_57[] = { /* 9 */
+	{5, 40,		20, 20,		8},
+	{20, 5,		20, 20,		8},
+	{15, 0,		20, 5,		8},
+	{5, 0,		15, 0,		8},
+	{0, 5,		5, 0,		8},
+	{0, 5,		0, 15,		8},
+	{0, 15,		5, 20,		8},
+	{5, 20,		20, 20,		8}
+};
+static embf_line_t embf_line_58[] = { /* : */
+	{0, 15,		5, 15,		8},
+	{0, 25,		5, 25,		8}
+};
+static embf_line_t embf_line_59[] = { /* ; */
+	{0, 40,		10, 30,		8},
+	{10, 15,		10, 20,		8}
+};
+static embf_line_t embf_line_60[] = { /* < */
+	{0, 20,		10, 10,		8},
+	{0, 20,		10, 30,		8}
+};
+static embf_line_t embf_line_61[] = { /* = */
+	{0, 15,		20, 15,		8},
+	{0, 25,		20, 25,		8}
+};
+static embf_line_t embf_line_62[] = { /* > */
+	{0, 10,		10, 20,		8},
+	{0, 30,		10, 20,		8}
+};
+static embf_line_t embf_line_63[] = { /* ? */
+	{10, 20,		10, 25,		8},
+	{10, 35,		10, 40,		8},
+	{0, 5,		0, 10,		8},
+	{0, 5,		5, 0,		8},
+	{5, 0,		15, 0,		8},
+	{15, 0,		20, 5,		8},
+	{20, 5,		20, 10,		8},
+	{10, 20,		20, 10,		8}
+};
+static embf_line_t embf_line_64[] = { /* @ */
+	{0, 0,		0, 30,		8},
+	{0, 30,		10, 40,		8},
+	{10, 40,		40, 40,		8},
+	{50, 25,		50, 0,		8},
+	{50, 0,		40, -10,		8},
+	{40, -10,		10, -10,		8},
+	{10, -10,		0, 0,		8},
+	{15, 10,		15, 20,		8},
+	{15, 20,		20, 25,		8},
+	{20, 25,		30, 25,		8},
+	{30, 25,		35, 20,		8},
+	{35, 20,		40, 25,		8},
+	{35, 20,		35, 5,		8},
+	{35, 10,		30, 5,		8},
+	{20, 5,		30, 5,		8},
+	{20, 5,		15, 10,		8},
+	{40, 25,		50, 25,		8}
+};
+static embf_line_t embf_line_65[] = { /* A */
+	{0, 10,		0, 40,		8},
+	{0, 10,		7, 0,		8},
+	{7, 0,		18, 0,		8},
+	{18, 0,		25, 10,		8},
+	{25, 10,		25, 40,		8},
+	{0, 20,		25, 20,		8}
+};
+static embf_line_t embf_line_66[] = { /* B */
+	{0, 40,		20, 40,		8},
+	{20, 40,		25, 35,		8},
+	{25, 23,		25, 35,		8},
+	{20, 18,		25, 23,		8},
+	{5, 18,		20, 18,		8},
+	{5, 0,		5, 40,		8},
+	{0, 0,		20, 0,		8},
+	{20, 0,		25, 5,		8},
+	{25, 5,		25, 13,		8},
+	{20, 18,		25, 13,		8}
+};
+static embf_line_t embf_line_67[] = { /* C */
+	{7, 40,		20, 40,		8},
+	{0, 33,		7, 40,		8},
+	{0, 7,		0, 33,		8},
+	{0, 7,		7, 0,		8},
+	{7, 0,		20, 0,		8}
+};
+static embf_line_t embf_line_68[] = { /* D */
+	{5, 0,		5, 40,		8},
+	{18, 0,		25, 7,		8},
+	{25, 7,		25, 33,		8},
+	{18, 40,		25, 33,		8},
+	{0, 40,		18, 40,		8},
+	{0, 0,		18, 0,		8}
+};
+static embf_line_t embf_line_69[] = { /* E */
+	{0, 18,		15, 18,		8},
+	{0, 40,		20, 40,		8},
+	{0, 0,		0, 40,		8},
+	{0, 0,		20, 0,		8}
+};
+static embf_line_t embf_line_70[] = { /* F */
+	{0, 0,		0, 40,		8},
+	{0, 0,		20, 0,		8},
+	{0, 18,		15, 18,		8}
+};
+static embf_line_t embf_line_71[] = { /* G */
+	{20, 0,		25, 5,		8},
+	{5, 0,		20, 0,		8},
+	{0, 5,		5, 0,		8},
+	{0, 5,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{5, 40,		20, 40,		8},
+	{20, 40,		25, 35,		8},
+	{25, 25,		25, 35,		8},
+	{20, 20,		25, 25,		8},
+	{10, 20,		20, 20,		8}
+};
+static embf_line_t embf_line_72[] = { /* H */
+	{0, 0,		0, 40,		8},
+	{25, 0,		25, 40,		8},
+	{0, 20,		25, 20,		8}
+};
+static embf_line_t embf_line_73[] = { /* I */
+	{0, 0,		10, 0,		8},
+	{5, 0,		5, 40,		8},
+	{0, 40,		10, 40,		8}
+};
+static embf_line_t embf_line_74[] = { /* J */
+	{7, 0,		15, 0,		8},
+	{15, 0,		15, 35,		8},
+	{10, 40,		15, 35,		8},
+	{5, 40,		10, 40,		8},
+	{0, 35,		5, 40,		8},
+	{0, 35,		0, 30,		8}
+};
+static embf_line_t embf_line_75[] = { /* K */
+	{0, 0,		0, 40,		8},
+	{0, 20,		20, 0,		8},
+	{0, 20,		20, 40,		8}
+};
+static embf_line_t embf_line_76[] = { /* L */
+	{0, 0,		0, 40,		8},
+	{0, 40,		20, 40,		8}
+};
+static embf_line_t embf_line_77[] = { /* M */
+	{0, 0,		0, 40,		8},
+	{0, 0,		15, 20,		8},
+	{15, 20,		30, 0,		8},
+	{30, 0,		30, 40,		8}
+};
+static embf_line_t embf_line_78[] = { /* N */
+	{0, 0,		0, 40,		8},
+	{0, 0,		25, 40,		8},
+	{25, 0,		25, 40,		8}
+};
+static embf_line_t embf_line_79[] = { /* O */
+	{0, 5,		0, 35,		8},
+	{0, 5,		5, 0,		8},
+	{5, 0,		15, 0,		8},
+	{15, 0,		20, 5,		8},
+	{20, 5,		20, 35,		8},
+	{15, 40,		20, 35,		8},
+	{5, 40,		15, 40,		8},
+	{0, 35,		5, 40,		8}
+};
+static embf_line_t embf_line_80[] = { /* P */
+	{5, 0,		5, 40,		8},
+	{0, 0,		20, 0,		8},
+	{20, 0,		25, 5,		8},
+	{25, 5,		25, 15,		8},
+	{20, 20,		25, 15,		8},
+	{5, 20,		20, 20,		8}
+};
+static embf_line_t embf_line_81[] = { /* Q */
+	{0, 5,		0, 35,		8},
+	{0, 5,		5, 0,		8},
+	{5, 0,		15, 0,		8},
+	{15, 0,		20, 5,		8},
+	{20, 5,		20, 30,		8},
+	{10, 40,		20, 30,		8},
+	{5, 40,		10, 40,		8},
+	{0, 35,		5, 40,		8},
+	{10, 25,		20, 40,		8}
+};
+static embf_line_t embf_line_82[] = { /* R */
+	{0, 0,		20, 0,		8},
+	{20, 0,		25, 5,		8},
+	{25, 5,		25, 15,		8},
+	{20, 20,		25, 15,		8},
+	{5, 20,		20, 20,		8},
+	{5, 0,		5, 40,		8},
+	{13, 20,		25, 40,		8}
+};
+static embf_line_t embf_line_83[] = { /* S */
+	{20, 0,		25, 5,		8},
+	{5, 0,		20, 0,		8},
+	{0, 5,		5, 0,		8},
+	{0, 5,		0, 15,		8},
+	{0, 15,		5, 20,		8},
+	{5, 20,		20, 20,		8},
+	{20, 20,		25, 25,		8},
+	{25, 25,		25, 35,		8},
+	{20, 40,		25, 35,		8},
+	{5, 40,		20, 40,		8},
+	{0, 35,		5, 40,		8}
+};
+static embf_line_t embf_line_84[] = { /* T */
+	{0, 0,		20, 0,		8},
+	{10, 0,		10, 40,		8}
+};
+static embf_line_t embf_line_85[] = { /* U */
+	{0, 0,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{5, 40,		15, 40,		8},
+	{15, 40,		20, 35,		8},
+	{20, 0,		20, 35,		8}
+};
+static embf_line_t embf_line_86[] = { /* V */
+	{0, 0,		10, 40,		8},
+	{10, 40,		20, 0,		8}
+};
+static embf_line_t embf_line_87[] = { /* W */
+	{0, 0,		0, 20,		8},
+	{0, 20,		5, 40,		8},
+	{5, 40,		15, 20,		8},
+	{15, 20,		25, 40,		8},
+	{25, 40,		30, 20,		8},
+	{30, 20,		30, 0,		8}
+};
+static embf_line_t embf_line_88[] = { /* X */
+	{0, 40,		25, 0,		8},
+	{0, 0,		25, 40,		8}
+};
+static embf_line_t embf_line_89[] = { /* Y */
+	{0, 0,		10, 20,		8},
+	{10, 20,		20, 0,		8},
+	{10, 20,		10, 40,		8}
+};
+static embf_line_t embf_line_90[] = { /* Z */
+	{0, 0,		25, 0,		8},
+	{0, 40,		25, 0,		8},
+	{0, 40,		25, 40,		8}
+};
+static embf_line_t embf_line_91[] = { /* [ */
+	{0, 0,		5, 0,		8},
+	{0, 0,		0, 40,		8},
+	{0, 40,		5, 40,		8}
+};
+static embf_line_t embf_line_92[] = { /* \ */
+	{0, 5,		30, 35,		8}
+};
+static embf_line_t embf_line_93[] = { /* ] */
+	{0, 0,		5, 0,		8},
+	{5, 0,		5, 40,		8},
+	{0, 40,		5, 40,		8}
+};
+static embf_line_t embf_line_94[] = { /* ^ */
+	{0, 5,		5, 0,		8},
+	{5, 0,		10, 5,		8}
+};
+static embf_line_t embf_line_95[] = { /* _ */
+	{0, 40,		20, 40,		8}
+};
+static embf_line_t embf_line_97[] = { /* a */
+	{15, 20,		20, 25,		8},
+	{5, 20,		15, 20,		8},
+	{0, 25,		5, 20,		8},
+	{0, 25,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{20, 20,		20, 35,		8},
+	{20, 35,		25, 40,		8},
+	{5, 40,		15, 40,		8},
+	{15, 40,		20, 35,		8}
+};
+static embf_line_t embf_line_98[] = { /* b */
+	{0, 0,		0, 40,		8},
+	{0, 35,		5, 40,		8},
+	{5, 40,		15, 40,		8},
+	{15, 40,		20, 35,		8},
+	{20, 25,		20, 35,		8},
+	{15, 20,		20, 25,		8},
+	{5, 20,		15, 20,		8},
+	{0, 25,		5, 20,		8}
+};
+static embf_line_t embf_line_99[] = { /* c */
+	{5, 20,		20, 20,		8},
+	{0, 25,		5, 20,		8},
+	{0, 25,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{5, 40,		20, 40,		8}
+};
+static embf_line_t embf_line_100[] = { /* d */
+	{20, 0,		20, 40,		8},
+	{15, 40,		20, 35,		8},
+	{5, 40,		15, 40,		8},
+	{0, 35,		5, 40,		8},
+	{0, 25,		0, 35,		8},
+	{0, 25,		5, 20,		8},
+	{5, 20,		15, 20,		8},
+	{15, 20,		20, 25,		8}
+};
+static embf_line_t embf_line_101[] = { /* e */
+	{5, 40,		20, 40,		8},
+	{0, 35,		5, 40,		8},
+	{0, 25,		0, 35,		8},
+	{0, 25,		5, 20,		8},
+	{5, 20,		15, 20,		8},
+	{15, 20,		20, 25,		8},
+	{0, 30,		20, 30,		8},
+	{20, 30,		20, 25,		8}
+};
+static embf_line_t embf_line_102[] = { /* f */
+	{5, 5,		5, 40,		8},
+	{5, 5,		10, 0,		8},
+	{10, 0,		15, 0,		8},
+	{0, 20,		10, 20,		8}
+};
+static embf_line_t embf_line_103[] = { /* g */
+	{15, 20,		20, 25,		8},
+	{5, 20,		15, 20,		8},
+	{0, 25,		5, 20,		8},
+	{0, 25,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{5, 40,		15, 40,		8},
+	{15, 40,		20, 35,		8},
+	{0, 50,		5, 55,		8},
+	{5, 55,		15, 55,		8},
+	{15, 55,		20, 50,		8},
+	{20, 20,		20, 50,		8}
+};
+static embf_line_t embf_line_104[] = { /* h */
+	{0, 0,		0, 40,		8},
+	{0, 25,		5, 20,		8},
+	{5, 20,		15, 20,		8},
+	{15, 20,		20, 25,		8},
+	{20, 25,		20, 40,		8}
+};
+static embf_line_t embf_line_105[] = { /* i */
+	{0, 10,		0, 11,		10},
+	{0, 25,		0, 40,		8}
+};
+static embf_line_t embf_line_106[] = { /* j */
+	{5, 10,		5, 11,		10},
+	{5, 25,		5, 50,		8},
+	{0, 55,		5, 50,		8}
+};
+static embf_line_t embf_line_107[] = { /* k */
+	{0, 0,		0, 40,		8},
+	{0, 25,		15, 40,		8},
+	{0, 25,		10, 15,		8}
+};
+static embf_line_t embf_line_108[] = { /* l */
+	{0, 0,		0, 35,		8},
+	{0, 35,		5, 40,		8}
+};
+static embf_line_t embf_line_109[] = { /* m */
+	{5, 25,		5, 40,		8},
+	{5, 25,		10, 20,		8},
+	{10, 20,		15, 20,		8},
+	{15, 20,		20, 25,		8},
+	{20, 25,		20, 40,		8},
+	{20, 25,		25, 20,		8},
+	{25, 20,		30, 20,		8},
+	{30, 20,		35, 25,		8},
+	{35, 25,		35, 40,		8},
+	{0, 20,		5, 25,		8}
+};
+static embf_line_t embf_line_110[] = { /* n */
+	{5, 25,		5, 40,		8},
+	{5, 25,		10, 20,		8},
+	{10, 20,		15, 20,		8},
+	{15, 20,		20, 25,		8},
+	{20, 25,		20, 40,		8},
+	{0, 20,		5, 25,		8}
+};
+static embf_line_t embf_line_111[] = { /* o */
+	{0, 25,		0, 35,		8},
+	{0, 25,		5, 20,		8},
+	{5, 20,		15, 20,		8},
+	{15, 20,		20, 25,		8},
+	{20, 25,		20, 35,		8},
+	{15, 40,		20, 35,		8},
+	{5, 40,		15, 40,		8},
+	{0, 35,		5, 40,		8}
+};
+static embf_line_t embf_line_112[] = { /* p */
+	{5, 25,		5, 55,		8},
+	{0, 20,		5, 25,		8},
+	{5, 25,		10, 20,		8},
+	{10, 20,		20, 20,		8},
+	{20, 20,		25, 25,		8},
+	{25, 25,		25, 35,		8},
+	{20, 40,		25, 35,		8},
+	{10, 40,		20, 40,		8},
+	{5, 35,		10, 40,		8}
+};
+static embf_line_t embf_line_113[] = { /* q */
+	{20, 25,		20, 55,		8},
+	{15, 20,		20, 25,		8},
+	{5, 20,		15, 20,		8},
+	{0, 25,		5, 20,		8},
+	{0, 25,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{5, 40,		15, 40,		8},
+	{15, 40,		20, 35,		8}
+};
+static embf_line_t embf_line_114[] = { /* r */
+	{5, 25,		5, 40,		8},
+	{5, 25,		10, 20,		8},
+	{10, 20,		20, 20,		8},
+	{0, 20,		5, 25,		8}
+};
+static embf_line_t embf_line_115[] = { /* s */
+	{5, 40,		20, 40,		8},
+	{20, 40,		25, 35,		8},
+	{20, 30,		25, 35,		8},
+	{5, 30,		20, 30,		8},
+	{0, 25,		5, 30,		8},
+	{0, 25,		5, 20,		8},
+	{5, 20,		20, 20,		8},
+	{20, 20,		25, 25,		8},
+	{0, 35,		5, 40,		8}
+};
+static embf_line_t embf_line_116[] = { /* t */
+	{5, 0,		5, 35,		8},
+	{5, 35,		10, 40,		8},
+	{0, 15,		10, 15,		8}
+};
+static embf_line_t embf_line_117[] = { /* u */
+	{0, 20,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{5, 40,		15, 40,		8},
+	{15, 40,		20, 35,		8},
+	{20, 20,		20, 35,		8}
+};
+static embf_line_t embf_line_118[] = { /* v */
+	{0, 20,		10, 40,		8},
+	{20, 20,		10, 40,		8}
+};
+static embf_line_t embf_line_119[] = { /* w */
+	{0, 20,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{5, 40,		10, 40,		8},
+	{10, 40,		15, 35,		8},
+	{15, 20,		15, 35,		8},
+	{15, 35,		20, 40,		8},
+	{20, 40,		25, 40,		8},
+	{25, 40,		30, 35,		8},
+	{30, 20,		30, 35,		8}
+};
+static embf_line_t embf_line_120[] = { /* x */
+	{0, 20,		20, 40,		8},
+	{0, 40,		20, 20,		8}
+};
+static embf_line_t embf_line_121[] = { /* y */
+	{0, 20,		0, 35,		8},
+	{0, 35,		5, 40,		8},
+	{20, 20,		20, 50,		8},
+	{15, 55,		20, 50,		8},
+	{5, 55,		15, 55,		8},
+	{0, 50,		5, 55,		8},
+	{5, 40,		15, 40,		8},
+	{15, 40,		20, 35,		8}
+};
+static embf_line_t embf_line_122[] = { /* z */
+	{0, 20,		20, 20,		8},
+	{0, 40,		20, 20,		8},
+	{0, 40,		20, 40,		8}
+};
+static embf_line_t embf_line_123[] = {
+	{5, 5,		10, 0,		8},
+	{5, 5,		5, 15,		8},
+	{0, 20,		5, 15,		8},
+	{0, 20,		5, 25,		8},
+	{5, 25,		5, 35,		8},
+	{5, 35,		10, 40,		8}
+};
+static embf_line_t embf_line_124[] = { /* | */
+	{0, 0,		0, 40,		8}
+};
+static embf_line_t embf_line_125[] = {
+	{0, 0,		5, 5,		8},
+	{5, 5,		5, 15,		8},
+	{5, 15,		10, 20,		8},
+	{5, 25,		10, 20,		8},
+	{5, 25,		5, 35,		8},
+	{0, 40,		5, 35,		8}
+};
+static embf_line_t embf_line_126[] = { /* ~ */
+	{0, 25,		5, 20,		8},
+	{5, 20,		10, 20,		8},
+	{10, 20,		15, 25,		8},
+	{15, 25,		20, 25,		8},
+	{20, 25,		25, 20,		8}
+};
+/***************************************************************/
+static int embf_minx =  0;
+static int embf_miny =  -10;
+static int embf_maxx =  50;
+static int embf_maxy =  55;
+static embf_font_t embf_font[] = {
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{0, NULL, 0},
+	{18, embf_line_32, 0},
+	{12, embf_line_33, 2},
+	{12, embf_line_34, 2},
+	{12, embf_line_35, 4},
+	{12, embf_line_36, 12},
+	{12, embf_line_37, 17},
+	{12, embf_line_38, 11},
+	{12, embf_line_39, 1},
+	{12, embf_line_40, 3},
+	{12, embf_line_41, 3},
+	{12, embf_line_42, 4},
+	{12, embf_line_43, 2},
+	{12, embf_line_44, 1},
+	{12, embf_line_45, 1},
+	{12, embf_line_46, 1},
+	{12, embf_line_47, 1},
+	{12, embf_line_48, 9},
+	{12, embf_line_49, 3},
+	{12, embf_line_50, 6},
+	{12, embf_line_51, 11},
+	{12, embf_line_52, 3},
+	{12, embf_line_53, 9},
+	{12, embf_line_54, 10},
+	{12, embf_line_55, 2},
+	{12, embf_line_56, 15},
+	{12, embf_line_57, 8},
+	{12, embf_line_58, 2},
+	{12, embf_line_59, 2},
+	{12, embf_line_60, 2},
+	{12, embf_line_61, 2},
+	{12, embf_line_62, 2},
+	{12, embf_line_63, 8},
+	{12, embf_line_64, 17},
+	{12, embf_line_65, 6},
+	{12, embf_line_66, 10},
+	{12, embf_line_67, 5},
+	{12, embf_line_68, 6},
+	{12, embf_line_69, 4},
+	{12, embf_line_70, 3},
+	{12, embf_line_71, 10},
+	{12, embf_line_72, 3},
+	{12, embf_line_73, 3},
+	{12, embf_line_74, 6},
+	{12, embf_line_75, 3},
+	{12, embf_line_76, 2},
+	{12, embf_line_77, 4},
+	{12, embf_line_78, 3},
+	{12, embf_line_79, 8},
+	{12, embf_line_80, 6},
+	{12, embf_line_81, 9},
+	{12, embf_line_82, 7},
+	{12, embf_line_83, 11},
+	{12, embf_line_84, 2},
+	{12, embf_line_85, 5},
+	{12, embf_line_86, 2},
+	{12, embf_line_87, 6},
+	{12, embf_line_88, 2},
+	{12, embf_line_89, 3},
+	{12, embf_line_90, 3},
+	{12, embf_line_91, 3},
+	{12, embf_line_92, 1},
+	{12, embf_line_93, 3},
+	{12, embf_line_94, 2},
+	{12, embf_line_95, 1},
+	{0, NULL, 0},
+	{12, embf_line_97, 9},
+	{12, embf_line_98, 8},
+	{12, embf_line_99, 5},
+	{12, embf_line_100, 8},
+	{12, embf_line_101, 8},
+	{10, embf_line_102, 4},
+	{12, embf_line_103, 11},
+	{12, embf_line_104, 5},
+	{10, embf_line_105, 2},
+	{10, embf_line_106, 3},
+	{12, embf_line_107, 3},
+	{10, embf_line_108, 2},
+	{12, embf_line_109, 10},
+	{12, embf_line_110, 6},
+	{12, embf_line_111, 8},
+	{12, embf_line_112, 9},
+	{12, embf_line_113, 8},
+	{12, embf_line_114, 4},
+	{12, embf_line_115, 9},
+	{10, embf_line_116, 3},
+	{12, embf_line_117, 5},
+	{12, embf_line_118, 2},
+	{12, embf_line_119, 9},
+	{12, embf_line_120, 2},
+	{12, embf_line_121, 8},
+	{12, embf_line_122, 3},
+	{12, embf_line_123, 6},
+	{12, embf_line_124, 1},
+	{12, embf_line_125, 6},
+	{12, embf_line_126, 5},
+	{0, NULL, 0}
+};
diff --git a/src/global_typedefs.h b/src/global_typedefs.h
index 92496b4..24ec97c 100644
--- a/src/global_typedefs.h
+++ b/src/global_typedefs.h
@@ -26,7 +26,7 @@
 
 typedef struct pcb_board_s pcb_board_t;
 typedef struct pcb_data_s pcb_data_t;
-typedef struct pcb_layer_group_s pcb_layer_group_t;
+typedef struct pcb_layer_stack_s pcb_layer_stack_t;
 typedef struct pcb_layer_s pcb_layer_t;
 typedef struct pcb_buffer_s pcb_buffer_t;
 typedef struct pcb_net_s pcb_net_t;
diff --git a/src/globalconst.h b/src/globalconst.h
index ef03b80..ea020e1 100644
--- a/src/globalconst.h
+++ b/src/globalconst.h
@@ -47,24 +47,20 @@
 #define PCB_LARGE_VALUE      (COORD_MAX / 2 - 1) /* maximum extent of board and elements */
 
 #define PCB_MAX_LAYER        16    /* max number of layer, check source code for more changes, a *lot* more changes */
-#if 0
 /* new array size that allows substrate layers */
-#	define PCB_MAX_LAYERGRP     ((PCB_MAX_LAYER+4)*2)    /* max number of layer groups, a.k.a. physical layers */
-#else
-#	define PCB_MAX_LAYERGRP     PCB_MAX_LAYER    /* max number of layer groups, a.k.a. physical layers */
-#endif
+#define PCB_MAX_LAYERGRP     ((PCB_MAX_LAYER+8)*2)    /* max number of layer groups, a.k.a. physical layers: a few extra outer layers per side, pluse one substrate per real layer */
 #define PCB_MIN_LINESIZE     PCB_MIL_TO_COORD(0.01)	/* thickness of lines */
-#define PCB_MAX_LINESIZE     PCB_LARGE_VALUE
+#define PCB_MAX_LINESIZE     ((pcb_coord_t)PCB_LARGE_VALUE)
 #define PCB_MIN_ARCSIZE      PCB_MIL_TO_COORD(0.01)
-#define PCB_MAX_ARCSIZE      PCB_LARGE_VALUE
+#define PCB_MAX_ARCSIZE      ((pcb_coord_t)PCB_LARGE_VALUE)
 #define PCB_MIN_TEXTSCALE    10 /* scaling of text objects in percent */
 #define PCB_MAX_TEXTSCALE    10000
 #define PCB_MIN_PINORVIASIZE PCB_MIL_TO_COORD(20)	/* size of a pin or via */
 #define PCB_MIN_PINORVIAHOLE PCB_MIL_TO_COORD(4)	/* size of a pins or vias drilling hole */
-#define PCB_MAX_PINORVIASIZE PCB_LARGE_VALUE
+#define PCB_MAX_PINORVIASIZE ((pcb_coord_t)PCB_LARGE_VALUE)
 #define PCB_MIN_PINORVIACOPPER PCB_MIL_TO_COORD(4)	/* min difference outer-inner diameter */
 #define PCB_MIN_PADSIZE      PCB_MIL_TO_COORD(1)	/* min size of a pad */
-#define PCB_MAX_PADSIZE      PCB_LARGE_VALUE   /* max size of a pad */
+#define PCB_MAX_PADSIZE      ((pcb_coord_t)PCB_LARGE_VALUE)   /* max size of a pad */
 #define PCB_MIN_DRC_VALUE    PCB_MIL_TO_COORD(0.1)
 #define PCB_MAX_DRC_VALUE    PCB_MIL_TO_COORD(500)
 #define PCB_MIN_DRC_SILK     PCB_MIL_TO_COORD(1)
@@ -77,17 +73,13 @@
 #define PCB_MAX_GRID         PCB_MIL_TO_COORD(1000)
 #define PCB_MAX_FONTPOSITION 255 /* upper limit of characters in my font */
 
-#define PCB_MAX_COORD        PCB_LARGE_VALUE /* coordinate limits */
+#define PCB_MAX_COORD        ((pcb_coord_t)PCB_LARGE_VALUE) /* coordinate limits */
 #define PCB_MIN_SIZE         PCB_MIL_TO_COORD(10) /* lowest width and height of the board */
 #define PCB_MAX_BUFFER       5 /* number of pastebuffers additional changes in menu.c are also required to select more buffers */
 
 #define PCB_DEFAULT_DRILLINGHOLE 40 /* default inner/outer ratio for pins/vias in percent */
 
-#if PCB_MAX_LINESIZE > PCB_MAX_PINORVIASIZE	/* maximum size value */
-#define PCB_MAX_SIZE PCB_MAX_LINESIZE
-#else
-#define PCB_MAX_SIZE PCB_MAX_PINORVIASIZE
-#endif
+#define PCB_MAX_SIZE ((pcb_coord_t)PCB_LARGE_VALUE)
 
 #ifndef PCB_PATH_MAX   /* maximum path length */
 #ifdef PATH_MAX
diff --git a/src/gui_act.c b/src/gui_act.c
index f38216c..0e93e2c 100644
--- a/src/gui_act.c
+++ b/src/gui_act.c
@@ -1297,6 +1297,91 @@ static int pcb_act_LibraryChanged(int argc, const char **argv, pcb_coord_t x, pc
 	return 0;
 }
 
+static const char pcb_acts_cursor[] = "Cursor(Type,DeltaUp,DeltaRight,Units)";
+static const char pcb_acth_cursor[] = "Move the cursor.";
+/* %start-doc actions Cursor
+
+This action moves the mouse cursor.  Unlike other actions which take
+coordinates, this action's coordinates are always relative to the
+user's view of the board.  Thus, a positive @var{DeltaUp} may move the
+cursor towards the board origin if the board is inverted.
+
+Type is one of @samp{Pan} or @samp{Warp}.  @samp{Pan} causes the
+viewport to move such that the crosshair is under the mouse cursor.
+ at samp{Warp} causes the mouse cursor to move to be above the crosshair.
+
+ at var{Units} can be one of the following:
+
+ at table @samp
+
+ at item mil
+ at itemx mm
+The cursor is moved by that amount, in board units.
+
+ at item grid
+The cursor is moved by that many grid points.
+
+ at item view
+The values are percentages of the viewport's view.  Thus, a pan of
+ at samp{100} would scroll the viewport by exactly the width of the
+current view.
+
+ at item board
+The values are percentages of the board size.  Thus, a move of
+ at samp{50,50} moves you halfway across the board.
+
+ at end table
+
+%end-doc */
+
+static int pcb_act_Cursor(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	pcb_unit_list_t extra_units_x = {
+		{"grid", 0, 0},
+		{"view", 0, UNIT_PERCENT},
+		{"board", 0, UNIT_PERCENT},
+		{"", 0, 0}
+	};
+	pcb_unit_list_t extra_units_y = {
+		{"grid", 0, 0},
+		{"view", 0, UNIT_PERCENT},
+		{"board", 0, UNIT_PERCENT},
+		{"", 0, 0}
+	};
+	int pan_warp = HID_SC_DO_NOTHING;
+	double dx, dy;
+
+	extra_units_x[0].scale = PCB->Grid;
+	extra_units_x[2].scale = PCB->MaxWidth;
+
+	extra_units_y[0].scale = PCB->Grid;
+	extra_units_y[2].scale = PCB->MaxHeight;
+
+	pcb_gui->get_view_size(&extra_units_x[1].scale, &extra_units_y[1].scale);
+
+	if (argc != 4)
+		PCB_ACT_FAIL(cursor);
+
+	if (pcb_strcasecmp(argv[0], "pan") == 0)
+		pan_warp = HID_SC_PAN_VIEWPORT;
+	else if (pcb_strcasecmp(argv[0], "warp") == 0)
+		pan_warp = HID_SC_WARP_POINTER;
+	else
+		PCB_ACT_FAIL(cursor);
+
+	dx = pcb_get_value_ex(argv[1], argv[3], NULL, extra_units_x, "", NULL);
+	if (conf_core.editor.view.flip_x)
+		dx = -dx;
+	dy = pcb_get_value_ex(argv[2], argv[3], NULL, extra_units_y, "", NULL);
+	if (!conf_core.editor.view.flip_y)
+		dy = -dy;
+
+	pcb_event_move_crosshair(pcb_crosshair.X + dx, pcb_crosshair.Y + dy);
+	pcb_gui->set_crosshair(pcb_crosshair.X, pcb_crosshair.Y, pan_warp);
+
+	return 0;
+}
+
 
 pcb_hid_action_t gui_action_list[] = {
 	{"Display", 0, pcb_act_Display,
@@ -1346,6 +1431,8 @@ pcb_hid_action_t gui_action_list[] = {
 	,
 	{"LibraryChanged", 0, pcb_act_LibraryChanged,
 	 pcb_acth_LibraryChanged, pcb_acts_LibraryChanged}
+	,
+	{"Cursor", 0, pcb_act_Cursor, pcb_acth_cursor, pcb_acts_cursor}
 };
 
 PCB_REGISTER_ACTIONS(gui_action_list, NULL)
diff --git a/src/hid.h b/src/hid.h
index 56fce89..2ab8dcb 100644
--- a/src/hid.h
+++ b/src/hid.h
@@ -9,6 +9,14 @@
 #include "global_typedefs.h"
 #include "attrib.h"
 #include "layer.h"
+#include "layer_grp.h"
+
+typedef enum {
+	PCB_HID_MOUSE_PRESS,
+	PCB_HID_MOUSE_RELEASE,
+	PCB_HID_MOUSE_MOTION
+} pcb_hid_mouse_ev_t;
+
 
 typedef struct pcb_hid_attr_val_s  pcb_hid_attr_val_t;
 typedef struct pcb_hid_attribute_s pcb_hid_attribute_t;
@@ -298,8 +306,14 @@ struct hid_s {
 	int (*shift_is_pressed) (void);
 	int (*control_is_pressed) (void);
 	int (*mod1_is_pressed) (void);
+
 	void (*get_coords) (const char *msg_, pcb_coord_t * x_, pcb_coord_t * y_);
 
+	/* Fill in width and height with the sizes of the current view in
+	   pcb coordinates. used by action "Cursor" to determine max cursor pos.
+	   Width and height are never NULL. */
+	void (*get_view_size)(pcb_coord_t *width, pcb_coord_t *height);
+
 	/* Sets the crosshair, which may differ from the pointer depending
 	   on grid and pad snap.  Note that the HID is responsible for
 	   hiding, showing, redrawing, etc.  The core just tells it what
@@ -526,10 +540,8 @@ struct hid_s {
 	void (*propedit_add_stat)(void *pe, const char *propname, void *propctx, const char *most_common, const char *min, const char *max, const char *avg);
 };
 
-/* This function (in the common code) will be called whenever the GUI
-   needs to redraw the screen, print the board, or export a layer.  If
-   item is not NULL, only draw the given item.  Item is only non-NULL
-   if the HID was created via show_item.
+/* On of these functions (in the common code) will be called whenever the GUI
+   needs to redraw the screen, print the board, or export a layer.
 
    Each time func is called, it should do the following:
 
@@ -541,8 +553,28 @@ struct hid_s {
 
    Do *not* assume that the hid that is passed is the GUI hid.  This
    callback is also used for printing and exporting. */
-struct pcb_box_t;
-void pcb_hid_expose_callback(pcb_hid_t * hid_, pcb_box_t *region_, void *item_);
+
+typedef struct pcb_hid_expose_layer_s {
+	pcb_box_t view;
+	unsigned force:1; /* draw even if layer set fails */
+	union {
+		pcb_layer_id_t layer_id;
+		pcb_element_t *elem;
+	} content;
+} pcb_hid_expose_ctx_t;
+
+typedef void (*pcb_hid_expose_t)(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *ctx);
+
+/* Normal expose: draw all layers with all flags (no .content is used) */
+void pcb_hid_expose_all(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *region);
+
+/* Pinout preview expose: draw an element; content.elem is used */
+void pcb_hid_expose_pinout(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *element);
+
+
+/* Layer preview expose: draw a single layer; content.layer_id is used */
+void pcb_hid_expose_layer(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *ly);
+
 
 /* This is initially set to a "no-gui" gui, and later reset by
    main. hid_expose_callback also temporarily set it for drawing. */
diff --git a/src/hid_actions.c b/src/hid_actions.c
index dd257fc..3af9a71 100644
--- a/src/hid_actions.c
+++ b/src/hid_actions.c
@@ -271,7 +271,7 @@ another:
 	while (*sp && isspace((int) *sp))
 		sp++;
 
-	if (!*sp) {
+	if ((*sp == '\0') || (*sp == '#')) {
 		retcode = 0;
 		goto cleanup;
 	}
diff --git a/src/hid_draw_helpers.c b/src/hid_draw_helpers.c
index 5a8da39..07ac986 100644
--- a/src/hid_draw_helpers.c
+++ b/src/hid_draw_helpers.c
@@ -399,17 +399,21 @@ void pcb_dhlp_thindraw_pcb_pv(pcb_hid_gc_t fg_gc, pcb_hid_gc_t bg_gc, pcb_pin_t
 	}
 
 	if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pv)) {
-		pcb_coord_t l = pv->X - r;
-		pcb_coord_t b = pv->Y - r;
-		pcb_coord_t r = l + w;
-		pcb_coord_t t = b + w;
+		if ((PCB_FLAG_SQUARE_GET(pv) == 0) || (PCB_FLAG_SQUARE_GET(pv) == 1)) {
+			pcb_coord_t l = pv->X - r;
+			pcb_coord_t b = pv->Y - r;
+			pcb_coord_t r = l + w;
+			pcb_coord_t t = b + w;
 
-		pcb_gui->set_line_cap(fg_gc, Round_Cap);
-		pcb_gui->set_line_width(fg_gc, 0);
-		pcb_gui->draw_line(fg_gc, r, t, r, b);
-		pcb_gui->draw_line(fg_gc, l, t, l, b);
-		pcb_gui->draw_line(fg_gc, r, t, l, t);
-		pcb_gui->draw_line(fg_gc, r, b, l, b);
+			pcb_gui->set_line_cap(fg_gc, Round_Cap);
+			pcb_gui->set_line_width(fg_gc, 0);
+			pcb_gui->draw_line(fg_gc, r, t, r, b);
+			pcb_gui->draw_line(fg_gc, l, t, l, b);
+			pcb_gui->draw_line(fg_gc, r, t, l, t);
+			pcb_gui->draw_line(fg_gc, r, b, l, b);
+		}
+		else
+			draw_square_pin_poly(fg_gc, pv->X, pv->Y, w, pcb_true, PCB_FLAG_SQUARE_GET(pv));
 
 	}
 	else if (PCB_FLAG_TEST(PCB_FLAG_OCTAGON, pv)) {
diff --git a/src/hid_extents.c b/src/hid_extents.c
index 148a628..123d780 100644
--- a/src/hid_extents.c
+++ b/src/hid_extents.c
@@ -145,10 +145,8 @@ void hid_extents_init(void)
 	initialised = pcb_true;
 }
 
-pcb_box_t *pcb_hid_get_extents(void *item)
+pcb_box_t *pcb_hid_get_extents_pinout(void *item)
 {
-	pcb_box_t region;
-
 	/* As this isn't a real "HID", we need to ensure we are initialised. */
 	hid_extents_init();
 
@@ -157,11 +155,7 @@ pcb_box_t *pcb_hid_get_extents(void *item)
 	box.X2 = -COORD_MAX;
 	box.Y2 = -COORD_MAX;
 
-	region.X1 = -COORD_MAX;
-	region.Y1 = -COORD_MAX;
-	region.X2 = COORD_MAX;
-	region.Y2 = COORD_MAX;
-	pcb_hid_expose_callback(&extents_hid, &region, item);
+	pcb_hid_expose_pinout(&extents_hid, item);
 
 	return &box;
 }
diff --git a/src/hid_extents.h b/src/hid_extents.h
index 6f5eabd..a88aed0 100644
--- a/src/hid_extents.h
+++ b/src/hid_extents.h
@@ -6,7 +6,7 @@
 
 /* Convenience function that calls the expose callback for the item,
    and returns the extents of what was drawn.  */
-pcb_box_t *pcb_hid_get_extents(void *item);
+pcb_box_t *pcb_hid_get_extents_pinout(void *item);
 
 
 #endif
diff --git a/src/hid_flags.c b/src/hid_flags.c
index 7734166..025cf2c 100644
--- a/src/hid_flags.c
+++ b/src/hid_flags.c
@@ -84,7 +84,7 @@ int pcb_hid_get_flag(const char *name)
 void pcb_hid_save_and_show_layer_ons(int *save_array)
 {
 	int i;
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		save_array[i] = PCB->Data->Layer[i].On;
 		PCB->Data->Layer[i].On = 1;
 	}
@@ -93,6 +93,6 @@ void pcb_hid_save_and_show_layer_ons(int *save_array)
 void pcb_hid_restore_layer_ons(int *save_array)
 {
 	int i;
-	for (i = 0; i < pcb_max_copper_layer + 2; i++)
+	for (i = 0; i < pcb_max_layer; i++)
 		PCB->Data->Layer[i].On = save_array[i];
 }
diff --git a/src/hid_helper.c b/src/hid_helper.c
index 22029d2..1112b3f 100644
--- a/src/hid_helper.c
+++ b/src/hid_helper.c
@@ -32,6 +32,7 @@
 #include "hid_attrib.h"
 #include "hid_helper.h"
 #include "compat_misc.h"
+#include "plug_io.h"
 
 char *pcb_layer_to_file_name(char *dest, pcb_layer_id_t lid, unsigned int flags, pcb_file_name_style_t style)
 {
@@ -56,17 +57,31 @@ char *pcb_layer_to_file_name(char *dest, pcb_layer_id_t lid, unsigned int flags,
 
 	
 	group = pcb_layer_get_group(lid);
-	nlayers = PCB->LayerGroups.Number[group];
+	nlayers = PCB->LayerGroups.grp[group].len;
 	single_name = pcb_layer_name(lid);
 
 	if (flags & PCB_LYT_TOP) {
 		if (style == PCB_FNS_first || (style == PCB_FNS_single && nlayers == 2))
 			res = single_name;
-		res = "top";
+		if (flags & PCB_LYT_SILK)
+			res = "topsilk";
+		else if (flags & PCB_LYT_MASK)
+			res = "topmask";
+		else if (flags & PCB_LYT_PASTE)
+			res = "toppaste";
+		else
+			res = "top";
 	}
 	else if (flags & PCB_LYT_BOTTOM) {
 		if (style == PCB_FNS_first || (style == PCB_FNS_single && nlayers == 2))
 			res = single_name;
+		if (flags & PCB_LYT_SILK)
+			res = "bottomsilk";
+		else if (flags & PCB_LYT_MASK)
+			res = "bottommask";
+		else if (flags & PCB_LYT_PASTE)
+			res = "bottompaste";
+		else
 		res = "bottom";
 	}
 	else {
@@ -101,10 +116,18 @@ void pcb_derive_default_filename(const char *pcbfile, pcb_hid_attribute_t * file
 		*memory = buf;
 	if (buf) {
 		size_t bl;
+		pcb_plug_io_t *i;
 		strcpy(buf, pf);
 		bl = strlen(buf);
-		if (bl > 4 && strcmp(buf + bl - 4, ".pcb") == 0)
-			buf[bl - 4] = 0;
+		for(i = pcb_plug_io_chain; i != NULL; i = i->next) {
+			if (i->default_extension != NULL) {
+				int slen = strlen(i->default_extension);
+				if (bl > slen && strcmp(buf + bl - slen, i->default_extension) == 0) {
+					buf[bl - slen] = 0;
+					break;
+				}
+			}
+		}
 		strcat(buf, suffix);
 		if (filename_attrib->default_val.str_value)
 			free((void *) filename_attrib->default_val.str_value);
diff --git a/src/hid_nogui.c b/src/hid_nogui.c
index b6750be..653a584 100644
--- a/src/hid_nogui.c
+++ b/src/hid_nogui.c
@@ -297,16 +297,12 @@ static int nogui_confirm_dialog(const char *msg, ...)
 
 		answer = read_stdin_line();
 
-		if (answer == NULL)
-			continue;
-
-		if (answer[0] == '0' && answer[1] == '\0') {
-			ret = 0;
+		if ((answer == NULL) || (answer[0] == '1' && answer[1] == '\0')) {
+			ret = 1;
 			valid_answer = pcb_true;
 		}
-
-		if (answer[0] == '1' && answer[1] == '\0') {
-			ret = 1;
+		else if (answer[0] == '0' && answer[1] == '\0') {
+			ret = 0;
 			valid_answer = pcb_true;
 		}
 
diff --git a/src/layer.c b/src/layer.c
index e995833..3144644 100644
--- a/src/layer.c
+++ b/src/layer.c
@@ -30,26 +30,20 @@
 #include "data.h"
 #include "conf_core.h"
 #include "layer.h"
-#include "hid_actions.h"
 #include "compat_misc.h"
 #include "undo.h"
 #include "event.h"
 #include "layer_ui.h"
 
 pcb_virt_layer_t pcb_virt_layers[] = {
-	{"invisible",      PCB_LYT_VIRTUAL + 1,  -1,                  PCB_LYT_VIRTUAL | PCB_LYT_INVIS | PCB_LYT_LOGICAL },
-	{"topmask",        PCB_LYT_VIRTUAL + 2,  -1,                  PCB_LYT_VIRTUAL | PCB_LYT_MASK | PCB_LYT_TOP },
-	{"bottommask",     PCB_LYT_VIRTUAL + 3,  -1,                  PCB_LYT_VIRTUAL | PCB_LYT_MASK | PCB_LYT_BOTTOM },
-	{"topsilk",        PCB_LYT_VIRTUAL + 4,  +PCB_COMPONENT_SIDE, PCB_LYT_SILK | PCB_LYT_TOP },
-	{"bottomsilk",     PCB_LYT_VIRTUAL + 5,  +PCB_SOLDER_SIDE,    PCB_LYT_SILK | PCB_LYT_BOTTOM },
-	{"rats",           PCB_LYT_VIRTUAL + 6,  -1,                  PCB_LYT_VIRTUAL | PCB_LYT_RAT },
-	{"toppaste",       PCB_LYT_VIRTUAL + 7,  -1,                  PCB_LYT_VIRTUAL | PCB_LYT_PASTE | PCB_LYT_TOP },
-	{"bottompaste",    PCB_LYT_VIRTUAL + 8,  -1,                  PCB_LYT_VIRTUAL | PCB_LYT_PASTE | PCB_LYT_BOTTOM },
-	{"topassembly",    PCB_LYT_VIRTUAL + 9,  -1,                  PCB_LYT_VIRTUAL | PCB_LYT_ASSY | PCB_LYT_TOP},
-	{"bottomassembly", PCB_LYT_VIRTUAL + 10, -1,                  PCB_LYT_VIRTUAL | PCB_LYT_ASSY | PCB_LYT_BOTTOM },
-	{"fab",            PCB_LYT_VIRTUAL + 11, -1,                  PCB_LYT_VIRTUAL | PCB_LYT_FAB  | PCB_LYT_LOGICAL },
-	{"plated-drill",   PCB_LYT_VIRTUAL + 12, -1,                  PCB_LYT_VIRTUAL | PCB_LYT_PDRILL },
-	{"unplated-drill", PCB_LYT_VIRTUAL + 13, -1,                  PCB_LYT_VIRTUAL | PCB_LYT_UDRILL },
+	{"invisible",      PCB_LYT_VIRTUAL + 1, PCB_LYT_VIRTUAL | PCB_LYT_INVIS | PCB_LYT_LOGICAL },
+	{"rats",           PCB_LYT_VIRTUAL + 2, PCB_LYT_VIRTUAL | PCB_LYT_RAT },
+	{"topassembly",    PCB_LYT_VIRTUAL + 3, PCB_LYT_VIRTUAL | PCB_LYT_ASSY | PCB_LYT_TOP},
+	{"bottomassembly", PCB_LYT_VIRTUAL + 4, PCB_LYT_VIRTUAL | PCB_LYT_ASSY | PCB_LYT_BOTTOM },
+	{"fab",            PCB_LYT_VIRTUAL + 5, PCB_LYT_VIRTUAL | PCB_LYT_FAB  | PCB_LYT_LOGICAL },
+	{"plated-drill",   PCB_LYT_VIRTUAL + 6, PCB_LYT_VIRTUAL | PCB_LYT_PDRILL },
+	{"unplated-drill", PCB_LYT_VIRTUAL + 7, PCB_LYT_VIRTUAL | PCB_LYT_UDRILL },
+	{"csect",          PCB_LYT_VIRTUAL + 8, PCB_LYT_VIRTUAL | PCB_LYT_CSECT | PCB_LYT_LOGICAL },
 	{ NULL, 0 },
 };
 
@@ -76,6 +70,9 @@ static const pcb_layer_type_name_t pcb_layer_type_names[] = {
 	{ PCB_LYT_FAB,     2, "fab" },
 	{ PCB_LYT_PDRILL,  2, "plateddrill" },
 	{ PCB_LYT_UDRILL,  2, "unplateddrill" },
+	{ PCB_LYT_CSECT,   2, "cross-section" },
+	{ PCB_LYT_SUBSTRATE,2,"substrate" },
+	{ PCB_LYT_MISC,    2, "misc" },
 	{ PCB_LYT_UI,      2, "userinterface" },
 	{ PCB_LYT_VIRTUAL, 3, "virtual" },
 	{ 0, 0, NULL }
@@ -86,8 +83,15 @@ static const char *pcb_layer_type_class_names[] = {
 };
 
 #define PCB_LAYER_VIRT_MIN (PCB_LYT_VIRTUAL + PCB_VLY_first + 1)
-#define PCB_LAYER_VIRT_MAX (PCB_LYT_VIRTUAL + PCB_VLY_end - 1)
+#define PCB_LAYER_VIRT_MAX (PCB_LYT_VIRTUAL + PCB_VLY_end)
 
+#define layer_if_too_many(fail_cmd) \
+do { \
+	if (PCB->Data->LayerN >= PCB_MAX_LAYER) { \
+		pcb_message(PCB_MSG_ERROR, "Too many layers - can't have more than %d\n", PCB_MAX_LAYER); \
+		fail_cmd; \
+	} \
+} while(0)
 
 pcb_bool pcb_layer_is_empty_(pcb_layer_t *layer)
 {
@@ -130,121 +134,14 @@ pcb_bool pcb_layer_is_empty_(pcb_layer_t *layer)
 
 pcb_bool pcb_layer_is_empty(pcb_layer_id_t num)
 {
-	if ((num >= 0) && (num < pcb_max_copper_layer+2))
+	if ((num >= 0) && (num < pcb_max_layer))
 		return pcb_layer_is_empty_(PCB->Data->Layer + num);
 	return pcb_false;
 }
 
-pcb_bool pcb_is_layergrp_empty(pcb_layergrp_id_t num)
-{
-	int i;
-	for (i = 0; i < PCB->LayerGroups.Number[num]; i++)
-		if (!pcb_layer_is_empty(PCB->LayerGroups.Entries[num][i]))
-			return pcb_false;
-	return pcb_true;
-}
-
-int pcb_layer_parse_group_string(const char *s, pcb_layer_group_t *LayerGroup, int LayerN, int oldfmt)
-{
-	int group, member, layer;
-	pcb_bool c_set = pcb_false,						/* flags for the two special layers to */
-		s_set = pcb_false;							/* provide a default setting for old formats */
-	int groupnum[PCB_MAX_LAYERGRP + 2];
-
-	/* clear struct */
-	memset(LayerGroup, 0, sizeof(pcb_layer_group_t));
-
-	/* Clear assignments */
-	for (layer = 0; layer < PCB_MAX_LAYER + 2; layer++)
-		groupnum[layer] = -1;
-
-	/* loop over all groups */
-	for (group = 0; s && *s && group < LayerN; group++) {
-		while (*s && isspace((int) *s))
-			s++;
-
-		/* loop over all group members */
-		for (member = 0; *s; s++) {
-			/* ignore white spaces and get layernumber */
-			while (*s && isspace((int) *s))
-				s++;
-			switch (*s) {
-			case 'c':
-			case 'C':
-			case 't':
-			case 'T':
-				layer = LayerN + PCB_COMPONENT_SIDE;
-				c_set = pcb_true;
-				break;
-
-			case 's':
-			case 'S':
-			case 'b':
-			case 'B':
-				layer = LayerN + PCB_SOLDER_SIDE;
-				s_set = pcb_true;
-				break;
-
-			default:
-				if (!isdigit((int) *s))
-					goto error;
-				layer = atoi(s) - 1;
-				break;
-			}
-			if (member >= LayerN + 1)
-				goto error;
-			if (oldfmt) {
-				/* the old format didn't always have the silks */
-				if (layer > LayerN + MAX(PCB_SOLDER_SIDE, PCB_COMPONENT_SIDE)) {
-					/* UGLY HACK: we assume oldfmt is 1 only when called from io_pcb .y */
-					PCB->Data->LayerN++;
-					LayerN++;
-				}
-				if (layer > LayerN + MAX(PCB_SOLDER_SIDE, PCB_COMPONENT_SIDE) + 2)
-					goto error;
-			}
-			else {
-				if (layer > LayerN + MAX(PCB_SOLDER_SIDE, PCB_COMPONENT_SIDE))
-					goto error;
-			}
-			groupnum[layer] = group;
-			LayerGroup->Entries[group][member++] = layer;
-			while (*++s && isdigit((int) *s));
-
-			/* ignore white spaces and check for separator */
-			while (*s && isspace((int) *s))
-				s++;
-			if (!*s || *s == ':')
-				break;
-			if (*s != ',')
-				goto error;
-		}
-		LayerGroup->Number[group] = member;
-		if (*s == ':')
-			s++;
-	}
-	if (!s_set)
-		LayerGroup->Entries[PCB_SOLDER_SIDE][LayerGroup->Number[PCB_SOLDER_SIDE]++] = LayerN + PCB_SOLDER_SIDE;
-	if (!c_set)
-		LayerGroup->Entries[PCB_COMPONENT_SIDE][LayerGroup->Number[PCB_COMPONENT_SIDE]++] = LayerN + PCB_COMPONENT_SIDE;
-
-	for (layer = 0; layer < LayerN && group < LayerN; layer++)
-		if (groupnum[layer] == -1) {
-			LayerGroup->Entries[group][0] = layer;
-			LayerGroup->Number[group] = 1;
-			group++;
-		}
-	return (0);
-
-	/* reset structure on error */
-error:
-	memset(LayerGroup, 0, sizeof(pcb_layer_group_t));
-	return (1);
-}
-
 pcb_layer_id_t pcb_layer_id(pcb_data_t *Data, pcb_layer_t *Layer)
 {
-	if ((Layer >= Data->Layer) && (Layer < (Data->Layer + PCB_MAX_LAYER + 2)))
+	if ((Layer >= Data->Layer) && (Layer < (Data->Layer + PCB_MAX_LAYER)))
 		return Layer - Data->Layer;
 
 	if ((Layer >= pcb_uilayer.array) && (Layer < pcb_uilayer.array + vtlayer_len(&pcb_uilayer)))
@@ -253,27 +150,6 @@ pcb_layer_id_t pcb_layer_id(pcb_data_t *Data, pcb_layer_t *Layer)
 	return -1;
 }
 
-pcb_layergrp_id_t pcb_layer_get_group(pcb_layer_id_t Layer)
-{
-	pcb_layergrp_id_t group, i;
-
-#warning TODO: layer group cleanup: remove this +2 for the silks
-	if ((Layer < 0) || (Layer > pcb_max_copper_layer+2))
-		return -1;
-
-	for (group = 0; group < pcb_max_group; group++)
-		for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
-			if (PCB->LayerGroups.Entries[group][i] == Layer)
-				return (group);
-
-	return -1;
-}
-
-pcb_layergrp_id_t pcb_layer_get_group_(pcb_layer_t *Layer)
-{
-	return pcb_layer_get_group(pcb_layer_id(PCB->Data, Layer));
-}
-
 pcb_bool pcb_layer_is_paste_empty(pcb_side_t side)
 {
 	pcb_bool paste_empty = pcb_true;
@@ -288,95 +164,21 @@ pcb_bool pcb_layer_is_paste_empty(pcb_side_t side)
 	return paste_empty;
 }
 
-pcb_layergrp_id_t pcb_layer_move_to_group(pcb_layer_id_t layer, pcb_layergrp_id_t group)
-{
-	pcb_layergrp_id_t prev, i, j;
-
-	if (layer < 0 || layer > pcb_max_copper_layer + 1)
-		return -1;
-	prev = pcb_layer_get_group(layer);
-	if ((layer == pcb_solder_silk_layer && group == pcb_layer_get_group(pcb_component_silk_layer))
-			|| (layer == pcb_component_silk_layer && group == pcb_layer_get_group(pcb_solder_silk_layer))
-			|| (group < 0 || group >= pcb_max_group) || (prev == group))
-		return prev;
-
-	/* Remove layer from prev group */
-	for (j = i = 0; i < PCB->LayerGroups.Number[prev]; i++)
-		if (PCB->LayerGroups.Entries[prev][i] != layer)
-			PCB->LayerGroups.Entries[prev][j++] = PCB->LayerGroups.Entries[prev][i];
-	PCB->LayerGroups.Number[prev]--;
-
-	/* Add layer to new group.  */
-	i = PCB->LayerGroups.Number[group]++;
-	PCB->LayerGroups.Entries[group][i] = layer;
-
-	return group;
-}
-
-#warning TODO: remove this once we have explicit outline layer
-#define LAYER_IS_OUTLINE(idx) (((idx) > 0) && ((idx) <= pcb_max_copper_layer) && (strcmp(PCB->Data->Layer[idx].Name, "route") == 0 || strcmp(PCB->Data->Layer[(idx)].Name, "outline") == 0))
-
 unsigned int pcb_layer_flags(pcb_layer_id_t layer_idx)
 {
-	unsigned int res = 0;
+	pcb_layer_t *l;
 
 	if (layer_idx & PCB_LYT_UI)
 		return PCB_LYT_UI | PCB_LYT_VIRTUAL;
 
-	if (layer_idx == pcb_solder_silk_layer)
-		return PCB_LYT_SILK | PCB_LYT_BOTTOM;
-
-	if (layer_idx == pcb_component_silk_layer)
-		return PCB_LYT_SILK | PCB_LYT_TOP;
-
 	if ((layer_idx >= PCB_LAYER_VIRT_MIN) && (layer_idx <= PCB_LAYER_VIRT_MAX))
 		return pcb_virt_layers[layer_idx - PCB_LAYER_VIRT_MIN].type;
 
-	if (layer_idx > pcb_max_copper_layer+2)
+	if ((layer_idx < 0) || (layer_idx >= pcb_max_layer))
 		return 0;
 
-	if (layer_idx < pcb_max_copper_layer) {
-		if (!LAYER_IS_OUTLINE(layer_idx)) {
-			/* check whether it's top, bottom or internal */
-			int group, entry;
-			for (group = 0; group < pcb_max_group; group++) {
-				if (PCB->LayerGroups.Number[group]) {
-					unsigned int my_group = 0, gf = 0;
-					for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) {
-						int layer = PCB->LayerGroups.Entries[group][entry];
-						if (layer == layer_idx)
-							my_group = 1;
-						if (layer == pcb_component_silk_layer)
-							gf |= PCB_LYT_TOP;
-						else if (layer == pcb_solder_silk_layer)
-							gf |= PCB_LYT_BOTTOM;
-					}
-					if (my_group) {
-						res |= gf;
-						if (gf == 0)
-							res |= PCB_LYT_INTERN;
-						break; /* stop searching groups */
-					}
-				}
-			}
-			res |= PCB_LYT_COPPER;
-		}
-		else
-			res |= PCB_LYT_OUTLINE;
-	}
-
-	return res;
-}
-
-unsigned int pcb_layergrp_flags(pcb_layergrp_id_t group)
-{
-	unsigned int res = 0;
-	int layeri;
-
-	for (layeri = 0; layeri < PCB->LayerGroups.Number[group]; layeri++)
-		res |= pcb_layer_flags(PCB->LayerGroups.Entries[group][layeri]);
-
-	return res;
+	l = &PCB->Data->Layer[layer_idx];
+	return pcb_layergrp_flags(l->grp);
 }
 
 #define APPEND(n) \
@@ -391,19 +193,11 @@ unsigned int pcb_layergrp_flags(pcb_layergrp_id_t group)
 			used++; \
 	} while(0)
 
-/* For now, return only non-silks */
 #define APPEND_VIRT(v) \
 do { \
-	if (v->data_layer_offs < 0) \
-		APPEND(v->new_id); \
+	APPEND(v->new_id); \
 } while(0)
 
-/* this would be how we returned silks from here
-		APPEND(pcb_max_copper_layer + v->data_layer_offs); \
-	else \
-*/
-
-
 const pcb_virt_layer_t *pcb_vlayer_get_first(pcb_layer_type_t mask)
 {
 	const pcb_virt_layer_t *v;
@@ -424,7 +218,7 @@ int pcb_layer_list(pcb_layer_type_t mask, pcb_layer_id_t *res, int res_len)
 		if ((v->type & mask) == mask)
 			APPEND_VIRT(v);
 
-	for (n = 0; n < PCB_MAX_LAYER + 2; n++)
+	for (n = 0; n < PCB_MAX_LAYER; n++)
 		if ((pcb_layer_flags(n) & mask) == mask)
 			APPEND(n);
 
@@ -444,7 +238,7 @@ int pcb_layer_list_any(pcb_layer_type_t mask, pcb_layer_id_t *res, int res_len)
 		if ((v->type & mask))
 			APPEND_VIRT(v);
 
-	for (n = 0; n < PCB_MAX_LAYER + 2; n++)
+	for (n = 0; n < PCB_MAX_LAYER; n++)
 		if ((pcb_layer_flags(n) & mask))
 			APPEND(n);
 
@@ -455,101 +249,40 @@ int pcb_layer_list_any(pcb_layer_type_t mask, pcb_layer_id_t *res, int res_len)
 	return used;
 }
 
-int pcb_layer_group_list(pcb_layer_type_t mask, pcb_layergrp_id_t *res, int res_len)
-{
-	int group, layeri, used = 0;
-	for (group = 0; group < pcb_max_group; group++) {
-		for (layeri = 0; layeri < PCB->LayerGroups.Number[group]; layeri++) {
-			int layer = PCB->LayerGroups.Entries[group][layeri];
-			if ((pcb_layer_flags(layer) & mask) == mask) {
-				APPEND(group);
-				goto added; /* do not add a group twice */
-			}
-		}
-		added:;
-	}
-	return used;
-}
-
-int pcb_layer_group_list_any(pcb_layer_type_t mask, pcb_layergrp_id_t *res, int res_len)
-{
-	int group, layeri, used = 0;
-	for (group = 0; group < pcb_max_group; group++) {
-		for (layeri = 0; layeri < PCB->LayerGroups.Number[group]; layeri++) {
-			int layer = PCB->LayerGroups.Entries[group][layeri];
-			if ((pcb_layer_flags(layer) & mask)) {
-				APPEND(group);
-				goto added; /* do not add a group twice */
-			}
-		}
-		added:;
-	}
-	return used;
-}
-
 pcb_layer_id_t pcb_layer_by_name(const char *name)
 {
 	int n;
-	for (n = 0; n < pcb_max_copper_layer + 2; n++)
+	for (n = 0; n < pcb_max_layer; n++)
 		if (strcmp(PCB->Data->Layer[n].Name, name) == 0)
 			return n;
 	return -1;
 }
 
-pcb_layergrp_id_t pcb_layer_lookup_group(pcb_layer_id_t layer_id)
-{
-	int group, layeri;
-	for (group = 0; group < pcb_max_group; group++) {
-		for (layeri = 0; layeri < PCB->LayerGroups.Number[group]; layeri++) {
-			int layer = PCB->LayerGroups.Entries[group][layeri];
-			if (layer == layer_id)
-				return group;
-		}
-	}
-	return -1;
-}
-
-void pcb_layer_add_in_group(pcb_layer_id_t layer_id, pcb_layergrp_id_t group_id)
-{
-	int glen = PCB->LayerGroups.Number[group_id];
-	PCB->LayerGroups.Entries[group_id][glen] = layer_id;
-	PCB->LayerGroups.Number[group_id]++;
-}
-
-
 void pcb_layers_reset()
 {
 	int n;
 
-	/* reset layer names */
-	for(n = 2; n < PCB_MAX_LAYER; n++) {
+	/* reset everything to empty, even if that's invalid (no top/bottom copper)
+	   for the rest of the code: the (embedded) default design will overwrite this. */
+	/* reset layers */
+	for(n = 0; n < PCB_MAX_LAYER; n++) {
 		if (PCB->Data->Layer[n].Name != NULL)
 			free((char *)PCB->Data->Layer[n].Name);
 		PCB->Data->Layer[n].Name = pcb_strdup("<pcb_layers_reset>");
+		PCB->Data->Layer[n].grp = -1;
 	}
 
 	/* reset layer groups */
-	for(n = 0; n < PCB_MAX_LAYERGRP; n++)
-		PCB->LayerGroups.Number[n] = 0;
-
-	/* set up one copper layer on top and one on bottom */
-	PCB->Data->LayerN = 2;
-	PCB->LayerGroups.Number[PCB_SOLDER_SIDE] = 1;
-	PCB->LayerGroups.Number[PCB_COMPONENT_SIDE] = 1;
-	PCB->LayerGroups.Entries[PCB_SOLDER_SIDE][0] = PCB_SOLDER_SIDE;
-	PCB->LayerGroups.Entries[PCB_COMPONENT_SIDE][0] = PCB_COMPONENT_SIDE;
-
-	/* Name top and bottom layers */
-	if (PCB->Data->Layer[PCB_COMPONENT_SIDE].Name != NULL)
-		free((char *)PCB->Data->Layer[PCB_COMPONENT_SIDE].Name);
-	PCB->Data->Layer[PCB_COMPONENT_SIDE].Name = pcb_strdup("<top>");
-
-	if (PCB->Data->Layer[PCB_SOLDER_SIDE].Name != NULL)
-		free((char *)PCB->Data->Layer[PCB_SOLDER_SIDE].Name);
-	PCB->Data->Layer[PCB_SOLDER_SIDE].Name = pcb_strdup("<bottom>");
+	for(n = 0; n < PCB_MAX_LAYERGRP; n++) {
+		PCB->LayerGroups.grp[n].len = 0;
+		PCB->LayerGroups.grp[n].type = 0;
+		PCB->LayerGroups.grp[n].valid = 0;
+	}
+	PCB->LayerGroups.len = 0;
+	PCB->Data->LayerN = 0;
 }
 
-pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb_bool_t reuse_group, const char *lname)
+pcb_layer_id_t pcb_layer_create_old(pcb_layer_type_t type, pcb_bool reuse_layer, pcb_bool_t reuse_group, const char *lname)
 {
 	pcb_layer_id_t id;
 	pcb_layergrp_id_t grp = -1;
@@ -577,6 +310,9 @@ pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb
 			case PCB_LYT_UDRILL:
 			case PCB_LYT_PDRILL:
 			case PCB_LYT_UI:
+			case PCB_LYT_CSECT:
+			case PCB_LYT_SUBSTRATE:
+			case PCB_LYT_MISC:
 				return -1; /* do not create virtual layers */
 
 			case PCB_LYT_INTERN:
@@ -591,8 +327,8 @@ pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb
 					case PCB_LYT_BOTTOM: return PCB_SOLDER_SIDE;
 					case PCB_LYT_INTERN:
 						for(grp = 2; grp < PCB_MAX_LAYERGRP; grp++) {
-							if (PCB->LayerGroups.Number[grp] > 0) {
-								id = PCB->LayerGroups.Entries[grp][0];
+							if (PCB->LayerGroups.grp[grp].len > 0) {
+								id = PCB->LayerGroups.grp[grp].lid[0];
 								if (strcmp(PCB->Data->Layer[id].Name, "outline") != 0)
 									return id;
 							}
@@ -603,8 +339,8 @@ pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb
 
 			case PCB_LYT_OUTLINE:
 				for(grp = 2; grp < PCB_MAX_LAYERGRP; grp++) {
-					if (PCB->LayerGroups.Number[grp] > 0) {
-						id = PCB->LayerGroups.Entries[grp][0];
+					if (PCB->LayerGroups.grp[grp].len > 0) {
+						id = PCB->LayerGroups.grp[grp].lid[0];
 						if (strcmp(PCB->Data->Layer[id].Name, "outline") == 0)
 							return id;
 					}
@@ -651,6 +387,9 @@ pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb
 			case PCB_LYT_UDRILL:
 			case PCB_LYT_PDRILL:
 			case PCB_LYT_UI:
+			case PCB_LYT_CSECT:
+			case PCB_LYT_SUBSTRATE:
+			case PCB_LYT_MISC:
 				return -1; /* do not create virtual layers */
 
 			case PCB_LYT_INTERN:
@@ -667,8 +406,8 @@ pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb
 					case PCB_LYT_INTERN:
 						/* find the first internal layer */
 						for(found = 0, grp = 2; grp < PCB_MAX_LAYERGRP; grp++) {
-							if (PCB->LayerGroups.Number[grp] > 0) {
-								id = PCB->LayerGroups.Entries[grp][0];
+							if (PCB->LayerGroups.grp[grp].len > 0) {
+								id = PCB->LayerGroups.grp[grp].lid[0];
 								if (strcmp(PCB->Data->Layer[id].Name, "outline") != 0) {
 									found = 1;
 									break;
@@ -688,12 +427,14 @@ pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb
 	if (grp < 0) {
 		/* Also need to create a group */
 		for(grp = 0; grp < PCB_MAX_LAYERGRP; grp++)
-			if (PCB->LayerGroups.Number[grp] == 0)
+			if (PCB->LayerGroups.grp[grp].len == 0)
 				break;
 		if (grp >= PCB_MAX_LAYERGRP)
 			return -2;
 	}
 
+	layer_if_too_many(return -1);
+
 	id = PCB->Data->LayerN++;
 
 	if (lname != NULL) {
@@ -703,43 +444,34 @@ pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb
 	}
 
 	/* add layer to group */
-	PCB->LayerGroups.Entries[grp][PCB->LayerGroups.Number[grp]] = id;
-	PCB->LayerGroups.Number[grp]++;
+	PCB->LayerGroups.grp[grp].lid[PCB->LayerGroups.grp[grp].len] = id;
+	PCB->LayerGroups.grp[grp].len++;
 
 	return id;
 }
 
-/* Temporary hack: silk layers have to be added as the last entry in the top and bottom layer groups, if they are not already in */
-static void hack_in_silks()
+pcb_layer_id_t pcb_layer_create(pcb_layergrp_id_t grp, const char *lname)
 {
-	int sl, cl, found, n;
-
-	sl = PCB_SOLDER_SIDE + PCB->Data->LayerN;
-	for(found = 0, n = 0; n < PCB->LayerGroups.Number[PCB_SOLDER_SIDE]; n++)
-		if (PCB->LayerGroups.Entries[PCB_SOLDER_SIDE][n] == sl)
-			found = 1;
-
-	if (!found) {
-		PCB->LayerGroups.Entries[PCB_SOLDER_SIDE][PCB->LayerGroups.Number[PCB_SOLDER_SIDE]] = sl;
-		PCB->LayerGroups.Number[PCB_SOLDER_SIDE]++;
-		if (PCB->Data->Layer[sl].Name != NULL)
-			free((char *)PCB->Data->Layer[sl].Name);
-		PCB->Data->Layer[sl].Name = pcb_strdup("silk");
-	}
+	pcb_layer_id_t id;
 
+	layer_if_too_many(return -1);
 
-	cl = PCB_COMPONENT_SIDE + PCB->Data->LayerN;
-	for(found = 0, n = 0; n < PCB->LayerGroups.Number[PCB_COMPONENT_SIDE]; n++)
-		if (PCB->LayerGroups.Entries[PCB_COMPONENT_SIDE][n] == cl)
-			found = 1;
+	id = PCB->Data->LayerN++;
+
+	if (lname != NULL) {
+		if (PCB->Data->Layer[id].Name != NULL)
+			free((char *)PCB->Data->Layer[id].Name);
+		PCB->Data->Layer[id].Name = pcb_strdup(lname);
+	}
 
-	if (!found) {
-		PCB->LayerGroups.Entries[PCB_COMPONENT_SIDE][PCB->LayerGroups.Number[PCB_COMPONENT_SIDE]] = cl;
-		PCB->LayerGroups.Number[PCB_COMPONENT_SIDE]++;
-		if (PCB->Data->Layer[cl].Name != NULL)
-			free((char *)PCB->Data->Layer[cl].Name);
-		PCB->Data->Layer[cl].Name = pcb_strdup("silk");
+	/* add layer to group */
+	if (grp >= 0) {
+		PCB->LayerGroups.grp[grp].lid[PCB->LayerGroups.grp[grp].len] = id;
+		PCB->LayerGroups.grp[grp].len++;
 	}
+	PCB->Data->Layer[id].grp = grp;
+
+	return id;
 }
 
 int pcb_layer_rename(pcb_layer_id_t layer, const char *lname)
@@ -750,11 +482,6 @@ int pcb_layer_rename(pcb_layer_id_t layer, const char *lname)
 	return 0;
 }
 
-void pcb_layers_finalize()
-{
-	hack_in_silks();
-}
-
 #undef APPEND
 
 /* ---------------------------------------------------------------------------
@@ -805,20 +532,20 @@ static void move_all_thermals(int old_index, int new_index)
 	PCB_ENDALL_LOOP;
 }
 
-static int LastLayerInComponentGroup(int layer)
+static int is_last_top_copper_layer(int layer)
 {
 	pcb_layergrp_id_t cgroup = pcb_layer_get_group(pcb_max_group + PCB_COMPONENT_SIDE);
 	pcb_layergrp_id_t lgroup = pcb_layer_get_group(layer);
-	if (cgroup == lgroup && PCB->LayerGroups.Number[lgroup] == 2)
+	if (cgroup == lgroup && PCB->LayerGroups.grp[lgroup].len == 1)
 		return 1;
 	return 0;
 }
 
-static int LastLayerInSolderGroup(int layer)
+static int is_last_bottom_copper_layer(int layer)
 {
 	int sgroup = pcb_layer_get_group(pcb_max_group + PCB_SOLDER_SIDE);
 	int lgroup = pcb_layer_get_group(layer);
-	if (sgroup == lgroup && PCB->LayerGroups.Number[lgroup] == 2)
+	if (sgroup == lgroup && PCB->LayerGroups.grp[lgroup].len == 1)
 		return 1;
 	return 0;
 }
@@ -833,114 +560,102 @@ int pcb_layer_rename_(pcb_layer_t *Layer, char *Name)
 
 int pcb_layer_move(pcb_layer_id_t old_index, pcb_layer_id_t new_index)
 {
-	int groups[PCB_MAX_LAYERGRP + 2], l, g;
+	pcb_layer_id_t l;
+	pcb_layergrp_id_t g;
 	pcb_layer_t saved_layer;
-	int saved_group;
 
-	pcb_undo_add_layer_move(old_index, new_index);
-	pcb_undo_inc_serial();
 
-	if (old_index < -1 || old_index >= pcb_max_copper_layer) {
-		pcb_message(PCB_MSG_ERROR, "Invalid old layer %d for move: must be -1..%d\n", old_index, pcb_max_copper_layer - 1);
+	if (old_index < -1 || old_index >= pcb_max_layer) {
+		pcb_message(PCB_MSG_ERROR, "Invalid old layer %d for move: must be -1..%d\n", old_index, pcb_max_layer - 1);
 		return 1;
 	}
-	if (new_index < -1 || new_index > pcb_max_copper_layer || new_index >= PCB_MAX_LAYER) {
-		pcb_message(PCB_MSG_ERROR, "Invalid new layer %d for move: must be -1..%d\n", new_index, pcb_max_copper_layer);
+	if (new_index < -1 || new_index > pcb_max_layer || new_index >= PCB_MAX_LAYER) {
+		pcb_message(PCB_MSG_ERROR, "Invalid new layer %d for move: must be -1..%d\n", new_index, pcb_max_layer);
 		return 1;
 	}
 	if (old_index == new_index)
 		return 0;
 
-	if (new_index == -1 && LastLayerInComponentGroup(old_index)) {
+	if (new_index == -1 && is_last_top_copper_layer(old_index)) {
 		pcb_gui->confirm_dialog("You can't delete the last top-side layer\n", "Ok", NULL);
 		return 1;
 	}
 
-	if (new_index == -1 && LastLayerInSolderGroup(old_index)) {
+	if (new_index == -1 && is_last_bottom_copper_layer(old_index)) {
 		pcb_gui->confirm_dialog("You can't delete the last bottom-side layer\n", "Ok", NULL);
 		return 1;
 	}
 
-	for (g = 0; g < PCB_MAX_LAYERGRP + 2; g++)
-		groups[g] = -1;
-
-	for (g = 0; g < PCB_MAX_LAYERGRP; g++)
-		for (l = 0; l < PCB->LayerGroups.Number[g]; l++)
-			groups[PCB->LayerGroups.Entries[g][l]] = g;
+	pcb_undo_add_layer_move(old_index, new_index);
+	pcb_undo_inc_serial();
 
-	if (old_index == -1) {
+	if (old_index == -1) { /* insert new layer */
+		pcb_layergrp_id_t gid;
 		pcb_layer_t *lp;
-		if (pcb_max_copper_layer == PCB_MAX_LAYER) {
+		if (pcb_max_layer == PCB_MAX_LAYER) {
 			pcb_message(PCB_MSG_ERROR, "No room for new layers\n");
 			return 1;
 		}
 		/* Create a new layer at new_index. */
 		lp = &PCB->Data->Layer[new_index];
 		memmove(&PCB->Data->Layer[new_index + 1],
-						&PCB->Data->Layer[new_index], (pcb_max_copper_layer - new_index + 2) * sizeof(pcb_layer_t));
-		memmove(&groups[new_index + 1], &groups[new_index], (pcb_max_copper_layer - new_index + 2) * sizeof(int));
-		pcb_max_copper_layer++;
+						&PCB->Data->Layer[new_index], (pcb_max_layer - new_index) * sizeof(pcb_layer_t));
+		pcb_max_layer++;
 		memset(lp, 0, sizeof(pcb_layer_t));
 		lp->On = 1;
 		lp->Name = pcb_strdup("New Layer");
 		lp->Color = conf_core.appearance.color.layer[new_index];
 		lp->SelectedColor = conf_core.appearance.color.layer_selected[new_index];
-		for (l = 0; l < pcb_max_copper_layer; l++)
+
+		/* insert the new layer into the top copper group (or if that fails, in
+		   any copper group) */
+		gid = -1;
+		if (pcb_layer_group_list(PCB_LYT_COPPER | PCB_LYT_TOP, &gid, 1) < 1)
+			pcb_layer_group_list(PCB_LYT_COPPER, &gid, 1);
+		lp->grp = gid;
+
+		for (l = 0; l < pcb_max_layer; l++)
 			if (pcb_layer_stack[l] >= new_index)
 				pcb_layer_stack[l]++;
-		pcb_layer_stack[pcb_max_copper_layer - 1] = new_index;
+		pcb_layer_stack[pcb_max_layer - 1] = new_index;
 	}
-	else if (new_index == -1) {
-		/* Delete the layer at old_index */
+	else if (new_index == -1) { /* Delete the layer at old_index */
+#warning layer TODO remove objects, free fields
 		memmove(&PCB->Data->Layer[old_index],
-						&PCB->Data->Layer[old_index + 1], (pcb_max_copper_layer - old_index + 2 - 1) * sizeof(pcb_layer_t));
-		memset(&PCB->Data->Layer[pcb_max_copper_layer + 1], 0, sizeof(pcb_layer_t));
-		memmove(&groups[old_index], &groups[old_index + 1], (pcb_max_copper_layer - old_index + 2 - 1) * sizeof(int));
-		for (l = 0; l < pcb_max_copper_layer; l++)
+						&PCB->Data->Layer[old_index + 1], (pcb_max_layer - old_index - 1) * sizeof(pcb_layer_t));
+		memset(&PCB->Data->Layer[pcb_max_layer + 1], 0, sizeof(pcb_layer_t));
+		for (l = 0; l < pcb_max_layer; l++)
 			if (pcb_layer_stack[l] == old_index)
-				memmove(pcb_layer_stack + l, pcb_layer_stack + l + 1, (pcb_max_copper_layer - l - 1) * sizeof(pcb_layer_stack[0]));
-		pcb_max_copper_layer--;
-		for (l = 0; l < pcb_max_copper_layer; l++)
+				memmove(pcb_layer_stack + l, pcb_layer_stack + l + 1, (pcb_max_layer - l - 1) * sizeof(pcb_layer_stack[0]));
+		pcb_max_layer--;
+		for (l = 0; l < pcb_max_layer; l++)
 			if (pcb_layer_stack[l] > old_index)
 				pcb_layer_stack[l]--;
 	}
 	else {
 		/* Move an existing layer */
 		memcpy(&saved_layer, &PCB->Data->Layer[old_index], sizeof(pcb_layer_t));
-		saved_group = groups[old_index];
-		if (old_index < new_index) {
+		if (old_index < new_index)
 			memmove(&PCB->Data->Layer[old_index], &PCB->Data->Layer[old_index + 1], (new_index - old_index) * sizeof(pcb_layer_t));
-			memmove(&groups[old_index], &groups[old_index + 1], (new_index - old_index) * sizeof(int));
-		}
-		else {
+		else
 			memmove(&PCB->Data->Layer[new_index + 1], &PCB->Data->Layer[new_index], (old_index - new_index) * sizeof(pcb_layer_t));
-			memmove(&groups[new_index + 1], &groups[new_index], (old_index - new_index) * sizeof(int));
-		}
 		memcpy(&PCB->Data->Layer[new_index], &saved_layer, sizeof(pcb_layer_t));
-		groups[new_index] = saved_group;
 	}
 
 	move_all_thermals(old_index, new_index);
 
-	for (g = 0; g < PCB_MAX_LAYERGRP; g++)
-		PCB->LayerGroups.Number[g] = 0;
-	for (l = 0; l < pcb_max_copper_layer + 2; l++) {
+	for (g = 0; g < pcb_max_group; g++)
+		PCB->LayerGroups.grp[g].len = 0;
+
+	for (l = 0; l < pcb_max_layer; l++) {
 		int i;
-		g = groups[l];
+		g = PCB->Data->Layer[l].grp;
 		if (g >= 0) {
-			i = PCB->LayerGroups.Number[g]++;
-			PCB->LayerGroups.Entries[g][i] = l;
+			i = PCB->LayerGroups.grp[g].len++;
+			PCB->LayerGroups.grp[g].lid[i] = l;
 		}
 	}
 
-	for (g = 0; g < PCB_MAX_LAYERGRP; g++)
-		if (PCB->LayerGroups.Number[g] == 0) {
-			memmove(&PCB->LayerGroups.Number[g],
-							&PCB->LayerGroups.Number[g + 1], (PCB_MAX_LAYERGRP - g - 1) * sizeof(PCB->LayerGroups.Number[g]));
-			memmove(&PCB->LayerGroups.Entries[g],
-							&PCB->LayerGroups.Entries[g + 1], (PCB_MAX_LAYERGRP - g - 1) * sizeof(PCB->LayerGroups.Entries[g]));
-		}
-
 	pcb_event(PCB_EVENT_LAYERS_CHANGED, NULL);
 	pcb_gui->invalidate_all();
 	return 0;
@@ -950,7 +665,7 @@ const char *pcb_layer_name(pcb_layer_id_t id)
 {
 	if (id < 0)
 		return NULL;
-	if (id < pcb_max_copper_layer+2)
+	if (id < pcb_max_layer)
 		return PCB->Data->Layer[id].Name;
 	if ((id >= PCB_LAYER_VIRT_MIN) && (id <= PCB_LAYER_VIRT_MAX))
 		return pcb_virt_layers[id-PCB_LAYER_VIRT_MIN].name;
@@ -959,7 +674,7 @@ const char *pcb_layer_name(pcb_layer_id_t id)
 
 pcb_layer_t *pcb_get_layer(pcb_layer_id_t id)
 {
-	if ((id >= 0) && (id < pcb_max_copper_layer+2))
+	if ((id >= 0) && (id < pcb_max_layer))
 		return &PCB->Data->Layer[id];
 	if (id & PCB_LYT_UI) {
 		id &= ~(PCB_LYT_VIRTUAL | PCB_LYT_UI);
@@ -993,10 +708,8 @@ int pcb_layer_gui_set_vlayer(pcb_virtual_layer_t vid, int is_empty)
 
 #warning TODO: need to pass the flags of the group, not the flags of the layer once we have a group for each layer
 	if (pcb_gui->set_layer_group != NULL) {
-		pcb_layer_id_t lid = v->data_layer_offs;
 		pcb_layergrp_id_t grp;
-		if (lid >= 0)
-			lid += pcb_max_copper_layer;
+		pcb_layer_id_t lid = v->new_id;
 		grp = pcb_layer_lookup_group(lid);
 		return pcb_gui->set_layer_group(grp, lid, v->type, is_empty);
 	}
@@ -1005,30 +718,54 @@ int pcb_layer_gui_set_vlayer(pcb_virtual_layer_t vid, int is_empty)
 	return 1;
 }
 
-int pcb_layer_gui_set_glayer(pcb_layergrp_id_t grp, int is_empty)
+int pcb_layer_gui_set_g_ui(pcb_layer_t *first, int is_empty)
 {
 	/* if there's no GUI, that means no draw should be done */
 	if (pcb_gui == NULL)
 		return 0;
 
 	if (pcb_gui->set_layer_group != NULL)
-		return pcb_gui->set_layer_group(grp, PCB->LayerGroups.Entries[grp][0], pcb_layergrp_flags(grp), is_empty);
+		return pcb_gui->set_layer_group(-1, pcb_layer_id(PCB->Data, first), PCB_LYT_VIRTUAL | PCB_LYT_UI, is_empty);
 
 	/* if the GUI doesn't have a set_layer, assume it wants to draw all layers */
 	return 1;
 }
 
-
-int pcb_layer_gui_set_g_ui(pcb_layer_t *first, int is_empty)
+static pcb_layer_id_t pcb_layer_get_cached(pcb_layer_id_t *cache, unsigned int loc, unsigned int typ)
 {
-	/* if there's no GUI, that means no draw should be done */
-	if (pcb_gui == NULL)
-		return 0;
+	pcb_layer_group_t *g;
 
-	if (pcb_gui->set_layer_group != NULL)
-		return pcb_gui->set_layer_group(-1, first, PCB_LYT_VIRTUAL | PCB_LYT_UI, is_empty);
+	if (*cache < pcb_max_layer) { /* check if the cache is still pointing to the right layer */
+		pcb_layergrp_id_t gid = PCB->Data->Layer[*cache].grp;
+		if ((gid >= 0) && (gid < PCB->LayerGroups.len)) {
+			g = &(PCB->LayerGroups.grp[gid]);
+			if ((g->type & loc) && (g->type & typ) && (g->lid[0] == *cache))
+				return *cache;
+		}
+	}
 
-	/* if the GUI doesn't have a set_layer, assume it wants to draw all layers */
-	return 1;
+	/* nope: need to resolve it again */
+	g = pcb_get_grp(&PCB->LayerGroups, loc, typ);
+	if ((g == NULL) || (g->len == 0)) {
+		*cache = -1;
+		return -1;
+	}
+	*cache = g->lid[0];
+	return *cache;
 }
 
+pcb_layer_id_t pcb_layer_get_bottom_silk()
+{
+	static pcb_layer_id_t cache = -1;
+	pcb_layer_id_t id = pcb_layer_get_cached(&cache, PCB_LYT_BOTTOM, PCB_LYT_SILK);
+	assert(id >= 0);
+	return id;
+}
+
+pcb_layer_id_t pcb_layer_get_top_silk()
+{
+	static pcb_layer_id_t cache = -1;
+	pcb_layer_id_t id =  pcb_layer_get_cached(&cache, PCB_LYT_TOP, PCB_LYT_SILK);
+	assert(id >= 0);
+	return id;
+}
diff --git a/src/layer.h b/src/layer.h
index 2d84aa1..347a9cf 100644
--- a/src/layer.h
+++ b/src/layer.h
@@ -28,23 +28,62 @@
 #ifndef PCB_LAYER_H
 #define PCB_LAYER_H
 
+typedef long int pcb_layer_id_t;
+typedef long int pcb_layergrp_id_t;
+
+/* Layer type bitfield */
+typedef enum {
+	/* Stack-up (vertical position): */
+	PCB_LYT_TOP      = 0x00000001, /* layer is on the top side of the board */
+	PCB_LYT_BOTTOM   = 0x00000002, /* layer is on the bottom side of the board */
+	PCB_LYT_INTERN   = 0x00000004, /* layer is internal */
+	PCB_LYT_LOGICAL  = 0x00000008, /* not in the layer stackup (typically aux drawing layer ) */
+	PCB_LYT_ANYWHERE = 0x000000FF, /* MASK: layer is anywhere on the stack */
+
+	/* What the layer consists of */
+	PCB_LYT_COPPER   = 0x00000100, /* copper objects */
+	PCB_LYT_SILK     = 0x00000200, /* silk objects */
+	PCB_LYT_MASK     = 0x00000400, /* solder mask */
+	PCB_LYT_PASTE    = 0x00000800, /* paste */
+	PCB_LYT_OUTLINE  = 0x00001000, /* outline (contour of the board) */
+	PCB_LYT_RAT      = 0x00002000, /* (virtual) rats nest (one, not in the stackup) */
+	PCB_LYT_INVIS    = 0x00004000, /* (virtual) layer is invisible (one, not in the stackup) */
+	PCB_LYT_ASSY     = 0x00008000, /* (virtual) assembly drawing (top and bottom) */
+	PCB_LYT_FAB      = 0x00010000, /* (virtual) fab drawing (one, not in the stackup) */
+	PCB_LYT_PDRILL   = 0x00020000, /* (virtual) plated drills (affects all physical layers) */
+	PCB_LYT_UDRILL   = 0x00040000, /* (virtual) unplated drills (affects all physical layers) */
+	PCB_LYT_UI       = 0x00080000, /* (virtual) user interface drawings (feature plugins use this for displaying states or debug info) */
+	PCB_LYT_CSECT    = 0x00100000, /* (virtual) cross-section drawing (displaying layer groups) */
+	PCB_LYT_SUBSTRATE= 0x00200000, /* substrate / insulator */
+	PCB_LYT_MISC     = 0x00400000, /* misc physical layers (e.g. adhesive) */
+	PCB_LYT_ANYTHING = 0x00FFFF00, /* MASK: layers consist anything */
+
+	/* misc properties */
+	PCB_LYT_VIRTUAL  = 0x01000000, /* the layer is not in the layer array (generated layer) */
+	PCB_LYT_ANYPROP  = 0x7F000000  /* MASK: misc layer properties */
+} pcb_layer_type_t;
+
+
+typedef enum {
+	PCB_VLY_INVISIBLE,
+	PCB_VLY_RATS,
+	PCB_VLY_TOP_ASSY,
+	PCB_VLY_BOTTOM_ASSY,
+	PCB_VLY_FAB,
+	PCB_VLY_PLATED_DRILL,
+	PCB_VLY_UNPLATED_DRILL,
+	PCB_VLY_CSECT,
+
+	/* for determining the range, do not use */
+	PCB_VLY_end,
+	PCB_VLY_first = PCB_VLY_INVISIBLE
+} pcb_virtual_layer_t;
+
 #include "globalconst.h"
 #include "global_typedefs.h"
 #include "attrib.h"
 #include "obj_all_list.h"
 
-typedef long int pcb_layer_id_t;
-typedef long int pcb_layergrp_id_t;
-
-/* ----------------------------------------------------------------------
- * layer group. A layer group identifies layers which are always switched
- * on/off together.
- */
-struct pcb_layer_group_s {
-	pcb_cardinal_t Number[PCB_MAX_LAYERGRP],      /* number of entries per groups */
-	  Entries[PCB_MAX_LAYERGRP][PCB_MAX_LAYER + 2];
-};
-
 struct pcb_layer_s {              /* holds information about one layer */
 	const char *Name;               /* layer name */
 	linelist_t Line;
@@ -57,6 +96,7 @@ struct pcb_layer_s {              /* holds information about one layer */
 	const char *SelectedColor;
 	pcb_attribute_list_t Attributes;
 	int no_drc;                    /* whether to ignore the layer when checking the design rules */
+	pcb_layergrp_id_t grp;         /* the group this layer is in (cross-reference) */
 
 	const char *cookie;            /* for UI layers: registration cookie; NULL for unused UI layers */
 };
@@ -65,9 +105,6 @@ struct pcb_layer_s {              /* holds information about one layer */
 /* returns the layer number for the passed copper or silk layer pointer */
 pcb_layer_id_t pcb_layer_id(pcb_data_t *Data, pcb_layer_t *Layer);
 
-/* lookup the group to which a layer belongs to returns -1 if no group is found */
-pcb_layergrp_id_t pcb_layer_get_group(pcb_layer_id_t Layer);
-pcb_layergrp_id_t pcb_layer_get_group_(pcb_layer_t *Layer);
 
 /* the offsets of the two additional special layers (e.g. silk) for 'component'
    and 'solder'. The offset of PCB_MAX_LAYER is not added here. Also can be
@@ -80,36 +117,25 @@ typedef enum {
 pcb_bool pcb_layer_is_paste_empty(pcb_side_t side);
 
 
-/* Returns group actually moved to (i.e. either group or previous) */
-pcb_layergrp_id_t pcb_layer_move_to_group(pcb_layer_id_t layer, pcb_layergrp_id_t group);
+/* Cached lookup of the first silk layer in the bottom or top group */
+pcb_layer_id_t pcb_layer_get_bottom_silk();
+pcb_layer_id_t pcb_layer_get_top_silk();
+
 
 /************ OLD API - new code should not use these **************/
 
 #define	LAYER_ON_STACK(n)	(&PCB->Data->Layer[pcb_layer_stack[(n)]])
 #define LAYER_PTR(n)            (&PCB->Data->Layer[(n)])
 #define	CURRENT			(PCB->SilkActive ? &PCB->Data->Layer[ \
-				(conf_core.editor.show_solder_side ? pcb_solder_silk_layer : pcb_component_silk_layer)] \
+				(conf_core.editor.show_solder_side ? pcb_layer_get_bottom_silk() : pcb_layer_get_top_silk())] \
 				: LAYER_ON_STACK(0))
 #define	INDEXOFCURRENT		(PCB->SilkActive ? \
-				(conf_core.editor.show_solder_side ? pcb_solder_silk_layer : pcb_component_silk_layer) \
+				(conf_core.editor.show_solder_side ? pcb_layer_get_bottom_silk() : pcb_layer_get_top_silk()) \
 				: pcb_layer_stack[0])
 #define SILKLAYER		Layer[ \
-				(conf_core.editor.show_solder_side ? pcb_solder_silk_layer : pcb_component_silk_layer)]
+				(conf_core.editor.show_solder_side ? pcb_layer_get_bottom_silk() : pcb_layer_get_top_silk())]
 #define BACKSILKLAYER		Layer[ \
-				(conf_core.editor.show_solder_side ? pcb_component_silk_layer : pcb_solder_silk_layer)]
-
-#define TEST_SILK_LAYER(layer)	(pcb_layer_id(PCB->Data, layer) >= pcb_max_copper_layer)
-
-#define GROUP_LOOP(data, group) do { 	\
-	pcb_cardinal_t entry; \
-        for (entry = 0; entry < ((pcb_board_t *)(data->pcb))->LayerGroups.Number[(group)]; entry++) \
-        { \
-		pcb_layer_t *layer;		\
-		pcb_cardinal_t number; 		\
-		number = ((pcb_board_t *)(data->pcb))->LayerGroups.Entries[(group)][entry]; \
-		if (number >= pcb_max_copper_layer)	\
-		  continue;			\
-		layer = &data->Layer[number];
+				(conf_core.editor.show_solder_side ? pcb_layer_get_top_silk() : pcb_layer_get_bottom_silk())]
 
 #define LAYER_LOOP(data, ml) do { \
         pcb_cardinal_t n; \
@@ -130,68 +156,14 @@ pcb_bool pcb_layer_is_empty_(pcb_layer_t *ly);
 pcb_bool pcb_layer_is_empty(pcb_layer_id_t ly);
 #define PCB_LAYER_IS_EMPTY(layer) pcb_layer_is_empty_((layer))
 
-/* Returns pcb_true if all layers in a group are empty */
-pcb_bool pcb_is_layergrp_empty(pcb_layergrp_id_t lgrp);
-
-/* Layer type bitfield */
-typedef enum {
-	/* Stack-up (vertical position): */
-	PCB_LYT_TOP      = 0x00000001, /* layer is on the top side of the board */
-	PCB_LYT_BOTTOM   = 0x00000002, /* layer is on the bottom side of the board */
-	PCB_LYT_INTERN   = 0x00000004, /* layer is internal */
-	PCB_LYT_LOGICAL  = 0x00000008, /* not in the layer stackup (typically aux drawing layer ) */
-	PCB_LYT_ANYWHERE = 0x000000FF, /* MASK: layer is anywhere on the stack */
-
-	/* What the layer consists of */
-	PCB_LYT_COPPER   = 0x00000100, /* copper objects */
-	PCB_LYT_SILK     = 0x00000200, /* silk objects */
-	PCB_LYT_MASK     = 0x00000400, /* solder mask */
-	PCB_LYT_PASTE    = 0x00000800, /* paste */
-	PCB_LYT_OUTLINE  = 0x00001000, /* outline (contour of the board) */
-	PCB_LYT_RAT      = 0x00002000, /* (virtual) rats nest (one, not in the stackup) */
-	PCB_LYT_INVIS    = 0x00004000, /* (virtual) layer is invisible (one, not in the stackup) */
-	PCB_LYT_ASSY     = 0x00008000, /* (virtual) assembly drawing (top and bottom) */
-	PCB_LYT_FAB      = 0x00010000, /* (virtual) fab drawing (one, not in the stackup) */
-	PCB_LYT_PDRILL   = 0x00020000, /* (virtual) plated drills (affects all physical layers) */
-	PCB_LYT_UDRILL   = 0x00040000, /* (virtual) unplated drills (affects all physical layers) */
-	PCB_LYT_UI       = 0x00080000, /* (virtual) user interface drawings (feature plugins use this for displaying states or debug info) */
-	PCB_LYT_ANYTHING = 0x00FFFF00, /* MASK: layers consist anything */
-
-	/* misc properties */
-	PCB_LYT_VIRTUAL  = 0x01000000, /* the layer is not in the layer array (generated layer) */
-	PCB_LYT_ANYPROP  = 0x7F000000  /* MASK: misc layer properties */
-} pcb_layer_type_t;
-
-
-typedef enum {
-	PCB_VLY_INVISIBLE,
-	PCB_VLY_TOP_MASK,
-	PCB_VLY_BOTTOM_MASK,
-	PCB_VLY_TOP_SILK,
-	PCB_VLY_BOTTOM_SILK,
-	PCB_VLY_RATS,
-	PCB_VLY_TOP_PASTE,
-	PCB_VLY_BOTTOM_PASTE,
-	PCB_VLY_TOP_ASSY,
-	PCB_VLY_BOTTOM_ASSY,
-	PCB_VLY_FAB,
-	PCB_VLY_PLATED_DRILL,
-	PCB_VLY_UNPLATED_DRILL,
 
-	/* for determining the range, do not use */
-	PCB_VLY_end,
-	PCB_VLY_first = PCB_VLY_INVISIBLE
-} pcb_virtual_layer_t;
-
-/* call the gui to set a virtual layer or a layer group or the UI layer group */
+/* call the gui to set a virtual layer or the UI layer group */
 int pcb_layer_gui_set_vlayer(pcb_virtual_layer_t vid, int is_empty);
-int pcb_layer_gui_set_glayer(pcb_layergrp_id_t grp, int is_empty);
 int pcb_layer_gui_set_g_ui(pcb_layer_t *first, int is_empty);
 
 
 /* returns a bitfield of pcb_layer_type_t; returns 0 if layer_idx is invalid. */
 unsigned int pcb_layer_flags(pcb_layer_id_t layer_idx);
-unsigned int pcb_layergrp_flags(pcb_layergrp_id_t group_idx);
 
 /* map bits of a layer type (call cb for each bit set); return number of bits
    found. */
@@ -207,17 +179,6 @@ int pcb_layer_type_map(pcb_layer_type_t type, void *ctx, void (*cb)(void *ctx, p
 int pcb_layer_list(pcb_layer_type_t mask, pcb_layer_id_t *res, int res_len);
 int pcb_layer_list_any(pcb_layer_type_t mask, pcb_layer_id_t *res, int res_len);
 
-/* Same as pcb_layer_list but lists layer groups. A group is matching
-   if any layer in that group matches mask. */
-int pcb_layer_group_list(pcb_layer_type_t mask, pcb_layergrp_id_t *res, int res_len);
-int pcb_layer_group_list_any(pcb_layer_type_t mask, pcb_layergrp_id_t *res, int res_len);
-
-/* Looks up which group a layer is in. Returns group ID. */
-pcb_layergrp_id_t pcb_layer_lookup_group(pcb_layer_id_t layer_id);
-
-/* Put a layer in a group (the layer should not be in any other group) */
-void pcb_layer_add_in_group(pcb_layer_id_t layer_id, pcb_layergrp_id_t group_id);
-
 /* Slow linear search for a layer by name */
 pcb_layer_id_t pcb_layer_by_name(const char *name);
 
@@ -226,6 +187,9 @@ pcb_layer_id_t pcb_layer_by_name(const char *name);
 /* Reset layers to the bare minimum (double sided board) */
 void pcb_layers_reset();
 
+/* Create a new layer and put it in an existing group (if grp is not -1). */
+pcb_layer_id_t pcb_layer_create(pcb_layergrp_id_t grp, const char *lname);
+
 /* If reuse_layer is false, create a new layer of the given type; if
    reuse_group is true, try to put the new layer on an existing group.
    If reuse_layer is 1, first try to return an already exiting layer that
@@ -233,8 +197,10 @@ void pcb_layers_reset();
    Upon creating a new layer, name it according to lname if it is not NULL
    Returns a layer index (or -1 on error)
    Do not create: mask, silk, paste; they are special layers.
+
+   OLD API: tries to handle groups together with layers - DO NOT USE
    */
-pcb_layer_id_t pcb_layer_create(pcb_layer_type_t type, pcb_bool reuse_layer, pcb_bool_t reuse_group, const char *lname);
+pcb_layer_id_t pcb_layer_create_old(pcb_layer_type_t type, pcb_bool reuse_layer, pcb_bool_t reuse_group, const char *lname);
 
 /* Rename an existing layer by idx */
 int pcb_layer_rename(pcb_layer_id_t layer, const char *lname);
@@ -243,22 +209,17 @@ int pcb_layer_rename(pcb_layer_id_t layer, const char *lname);
 int pcb_layer_rename_(pcb_layer_t *Layer, char *Name);
 
 
-/* Needs to be called once at the end, when all layers has been added */
-void pcb_layers_finalize();
-
-
 /* index is 0..PCB_MAX_LAYER-1.  If old_index is -1, a new layer is
    inserted at that index.  If new_index is -1, the specified layer is
    deleted.  Returns non-zero on error, zero if OK.  */
 int pcb_layer_move(pcb_layer_id_t old_index, pcb_layer_id_t new_index);
 
 
-
 /* list of virtual layers: these are generated by the draw code but do not
    have a real layer in the array */
 typedef struct pcb_virt_layer_s {
 	char *name;
-	pcb_layer_id_t new_id, data_layer_offs;
+	pcb_layer_id_t new_id;
 	pcb_layer_type_t type;
 } pcb_virt_layer_t;
 
@@ -272,13 +233,10 @@ const pcb_virt_layer_t *pcb_vlayer_get_first(pcb_layer_type_t mask);
 #define PCB_LAYERFLG_ON_VISIBLE_SIDE(uint_flags) \
 	(!!(conf_core.editor.show_solder_side ? ((uint_flags) & PCB_LYT_BOTTOM) : ((uint_flags) & PCB_LYT_TOP)))
 
-/********* OBSOLETE functions, do not use in new code *********/
-/* parses the group definition string which is a colon separated list of
-   comma separated layer numbers (1,2,b:4,6,8,t); oldfmt is 0 or 1
-   depending on PCB() or PCB[] in the file header.
+#define PCB_LYT_VISIBLE_SIDE() \
+	((conf_core.editor.show_solder_side ? PCB_LYT_BOTTOM : PCB_LYT_TOP))
 
-   OBSOLETE, do not use in new code: only the conf system and io_pcb
-   may need this. */
-int pcb_layer_parse_group_string(const char *s, pcb_layer_group_t *LayerGroup, int LayerN, int oldfmt);
+#define PCB_LYT_INVISIBLE_SIDE() \
+	((conf_core.editor.show_solder_side ? PCB_LYT_TOP : PCB_LYT_BOTTOM))
 
 #endif
diff --git a/src/layer_grp.c b/src/layer_grp.c
new file mode 100644
index 0000000..e91b8ab
--- /dev/null
+++ b/src/layer_grp.c
@@ -0,0 +1,622 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996,2004,2006 Thomas Nau
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas (pcb-rnd extensions)
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+#include "config.h"
+#include "board.h"
+#include "data.h"
+#include "layer_grp.h"
+#include "compat_misc.h"
+#include "event.h"
+
+/* notify the rest of the code after layer group changes so that the GUI
+   and other parts sync up */
+static int inhibit_notify = 0;
+#define NOTIFY() \
+do { \
+	if (!inhibit_notify) { \
+		pcb_event(PCB_EVENT_LAYERS_CHANGED, NULL); \
+		if (pcb_gui != NULL) \
+			pcb_gui->invalidate_all(); \
+	} \
+} while(0)
+
+void pcb_layergrp_inhibit_inc(void)
+{
+	inhibit_notify++;
+}
+
+void pcb_layergrp_inhibit_dec(void)
+{
+	inhibit_notify--;
+}
+
+pcb_layergrp_id_t pcb_layer_get_group_(pcb_layer_t *Layer)
+{
+	return Layer->grp;
+}
+
+pcb_layergrp_id_t pcb_layer_get_group(pcb_layer_id_t lid)
+{
+	if ((lid < 0) || (lid >= pcb_max_layer))
+		return -1;
+
+	return pcb_layer_get_group_(&PCB->Data->Layer[lid]);
+}
+
+int pcb_layergrp_del_layer(pcb_layergrp_id_t gid, pcb_layer_id_t lid)
+{
+	int n;
+	pcb_layer_group_t *grp;
+	pcb_layer_t *layer;
+
+	if ((lid < 0) || (lid >= pcb_max_layer))
+		return -1;
+
+	layer = PCB->Data->Layer + lid;
+	if (gid < 0)
+		gid = layer->grp;
+	if (gid >= PCB->LayerGroups.len)
+		return -1;
+
+	grp = &PCB->LayerGroups.grp[gid];
+
+	if (layer->grp != gid)
+		return -1;
+
+	for(n = 0; n < grp->len; n++) {
+		if (grp->lid[n] == lid) {
+			int remain = grp->len - n - 1;
+			if (remain > 0)
+				memmove(&grp->lid[n], &grp->lid[n+1], remain * sizeof(pcb_layer_id_t));
+			grp->len--;
+			layer->grp = -1;
+			NOTIFY();
+			return 0;
+		}
+	}
+
+
+	/* also: broken layer group list */
+	return -1;
+}
+
+pcb_layergrp_id_t pcb_layer_move_to_group(pcb_layer_id_t lid, pcb_layergrp_id_t gid)
+{
+	if (pcb_layergrp_del_layer(-1, lid) != 0)
+		return -1;
+	pcb_layer_add_in_group(lid, gid);
+	NOTIFY();
+	return gid;
+}
+
+unsigned int pcb_layergrp_flags(pcb_layergrp_id_t gid)
+{
+
+	if ((gid < 0) || (gid >= PCB->LayerGroups.len))
+		return 0;
+
+	return PCB->LayerGroups.grp[gid].type;
+}
+
+const char *pcb_layergrp_name(pcb_layergrp_id_t gid)
+{
+
+	if ((gid < 0) || (gid >= PCB->LayerGroups.len))
+		return 0;
+
+	return PCB->LayerGroups.grp[gid].name;
+}
+
+pcb_bool pcb_is_layergrp_empty(pcb_layergrp_id_t num)
+{
+	int i;
+	pcb_layer_group_t *g = &PCB->LayerGroups.grp[num];
+
+	/* some layers are never empty */
+	if (g->type & PCB_LYT_MASK)
+		return pcb_false;
+
+	if (g->type & PCB_LYT_PASTE) {
+		if (g->type & PCB_LYT_TOP)
+			return pcb_layer_is_paste_empty(PCB_COMPONENT_SIDE);
+		if (g->type & PCB_LYT_BOTTOM)
+			return pcb_layer_is_paste_empty(PCB_SOLDER_SIDE);
+	}
+
+	for (i = 0; i < g->len; i++)
+		if (!pcb_layer_is_empty(g->lid[i]))
+			return pcb_false;
+	return pcb_true;
+}
+
+int pcb_layergrp_free(pcb_layer_stack_t *stack, pcb_layergrp_id_t id)
+{
+	if ((id >= 0) && (id < stack->len)) {
+		int n;
+		pcb_layer_group_t *g = stack->grp + id;
+		if (g->name != NULL)
+			free(g->name);
+		for(n = 0; n < g->len; n++) {
+			pcb_layer_t *layer = PCB->Data->Layer + g->lid[n];
+			layer->grp = -1;
+		}
+		memset(g, 0, sizeof(pcb_layer_group_t));
+		return 0;
+	}
+	return -1;
+}
+
+int pcb_layergrp_move_onto(pcb_layer_stack_t *stack, pcb_layergrp_id_t dst, pcb_layergrp_id_t src)
+{
+	pcb_layer_group_t *d, *s;
+	int n;
+
+	if ((src < 0) || (src >= stack->len))
+		return -1;
+	if ((dst < stack->len) && (pcb_layergrp_free(stack, dst) != 0))
+		return -1;
+	d = stack->grp + dst;
+	s = stack->grp + src;
+	memcpy(d, s, sizeof(pcb_layer_group_t));
+
+	/* update layer's group refs to the new grp */
+	for(n = 0; n < d->len; n++) {
+		pcb_layer_t *layer = PCB->Data->Layer + d->lid[n];
+		layer->grp = dst;
+	}
+
+	memset(s, 0, sizeof(pcb_layer_group_t));
+	NOTIFY();
+	return 0;
+}
+
+static int flush_item(const char *s, const char *start, pcb_layer_id_t *lids, int *lids_len, pcb_layer_type_t *loc)
+{
+	char *end;
+	pcb_layer_id_t lid;
+	switch (*start) {
+		case 'c': case 'C': case 't': case 'T': *loc = PCB_LYT_TOP; break;
+		case 's': case 'S': case 'b': case 'B': *loc = PCB_LYT_BOTTOM; break;
+		default:
+			lid = strtol(start, &end, 10)-1;
+			if (end != s)
+				return -1;
+			if ((*lids_len) >= PCB_MAX_LAYER)
+				return -1;
+			lids[*lids_len] = lid;
+			(*lids_len)++;
+	}
+	return 0;
+}
+
+pcb_layer_group_t *pcb_get_grp(pcb_layer_stack_t *stack, pcb_layer_type_t loc, pcb_layer_type_t typ)
+{
+	int n;
+	for(n = 0; n < stack->len; n++)
+		if ((stack->grp[n].type & loc) && (stack->grp[n].type & typ))
+			return &(stack->grp[n]);
+	return NULL;
+}
+
+pcb_layer_group_t *pcb_layergrp_insert_after(pcb_layer_stack_t *stack, pcb_layergrp_id_t where)
+{
+	int n;
+	if ((where <= 0) || (where >= stack->len))
+		return NULL;
+
+	for(n = stack->len-1; n > where; n--)
+		pcb_layergrp_move_onto(stack, n+1, n);
+
+	stack->len++;
+	NOTIFY();
+	return stack->grp+where+1;
+}
+
+static pcb_layer_group_t *pcb_get_grp_new_intern_(pcb_layer_stack_t *stack, int omit_substrate)
+{
+	int bl, n;
+
+	if (stack->len+2 >= PCB_MAX_LAYERGRP)
+		return NULL;
+
+	/* seek the bottom copper layer */
+	for(bl = stack->len; bl >= 0; bl--) {
+		if ((stack->grp[bl].type & PCB_LYT_BOTTOM) && (stack->grp[bl].type & PCB_LYT_COPPER)) {
+
+			/* insert a new internal layer: move existing layers to make room */
+			for(n = stack->len-1; n >= bl; n--)
+				pcb_layergrp_move_onto(stack, n+2, n);
+
+			stack->len += 2;
+
+			stack->grp[bl].name = pcb_strdup("Intern");
+			stack->grp[bl].type = PCB_LYT_INTERN | PCB_LYT_COPPER;
+			stack->grp[bl].valid = 1;
+			bl++;
+			if (!omit_substrate) {
+				stack->grp[bl].type = PCB_LYT_INTERN | PCB_LYT_SUBSTRATE;
+				stack->grp[bl].valid = 1;
+			}
+			return &stack->grp[bl-1];
+		}
+	}
+	return NULL;
+}
+
+pcb_layer_group_t *pcb_get_grp_new_intern(pcb_layer_stack_t *stack, int intern_id)
+{
+	pcb_layer_group_t *g;
+
+	if (intern_id > 0) { /* look for existing intern layer first */
+		int n;
+		for(n = 0; n < stack->len; n++)
+			if (stack->grp[n].intern_id == intern_id)
+				return &stack->grp[n];
+	}
+
+	inhibit_notify++;
+	g = pcb_get_grp_new_intern_(stack, 0);
+	inhibit_notify--;
+	g->intern_id = intern_id;
+	NOTIFY();
+	return g;
+}
+
+pcb_layer_group_t *pcb_get_grp_new_misc(pcb_layer_stack_t *stack)
+{
+	pcb_layer_group_t *g;
+	inhibit_notify++;
+	g = pcb_get_grp_new_intern_(stack, 1);
+	inhibit_notify--;
+	NOTIFY();
+	return g;
+}
+
+/* Move an inclusive block of groups [from..to] by delta on the stack, assuming
+   target is already cleared and the new hole will be cleared by the caller */
+static void move_grps(pcb_layer_stack_t *stk, pcb_layergrp_id_t from, pcb_layergrp_id_t to, int delta)
+{
+	int g, remaining, n;
+
+	for(g = from; g <= to; g++) {
+		for(n = 0; n < stk->grp[g].len; n++) {
+			pcb_layer_t *l = pcb_get_layer(stk->grp[g].lid[n]);
+			if ((l != NULL) && (l->grp > 0))
+				l->grp += delta;
+		}
+	}
+
+	remaining = to - from+1;
+	if (remaining > 0)
+		memmove(&stk->grp[from + delta], &stk->grp[from], sizeof(pcb_layer_group_t) * remaining);
+}
+
+int pcb_layergrp_del(pcb_layer_stack_t *stk, pcb_layergrp_id_t gid, int del_layers)
+{
+	int n;
+
+	if ((gid < 0) || (gid >= stk->len))
+		return -1;
+
+	for(n = 0; n < stk->grp[gid].len; n++) {
+		pcb_layer_t *l = pcb_get_layer(stk->grp[gid].lid[n]);
+		if (l != NULL) {
+			if (del_layers) {
+				pcb_layer_move(stk->grp[gid].lid[n], -1);
+				n = 0; /* restart counting because the layer remove code may have changed the order */
+			}
+			else {
+				/* detach only */
+				l->grp = -1;
+			}
+		}
+	}
+
+	pcb_layergrp_free(stk, gid);
+	move_grps(stk, gid+1, stk->len-1, -1);
+	stk->len--;
+	NOTIFY();
+	return 0;
+}
+
+int pcb_layergrp_move(pcb_layer_stack_t *stk, pcb_layergrp_id_t from, pcb_layergrp_id_t to_before)
+{
+	pcb_layer_group_t tmp;
+	int n;
+
+	if ((from < 0) || (from >= stk->len))
+		return -1;
+
+	if ((to_before < 0) || (to_before >= stk->len))
+		return -1;
+
+	if ((to_before == from + 1) || (to_before == from))
+		return 0;
+
+	memcpy(&tmp, &stk->grp[from], sizeof(pcb_layer_group_t));
+	memset(&stk->grp[from], 0, sizeof(pcb_layer_group_t));
+	if (to_before < from + 1) {
+		move_grps(stk, to_before, from-1, +1);
+		memcpy(&stk->grp[to_before], &tmp, sizeof(pcb_layer_group_t));
+	}
+	else {
+		move_grps(stk, from+1, to_before-1, -1);
+		memcpy(&stk->grp[to_before-1], &tmp, sizeof(pcb_layer_group_t));
+	}
+
+	/* fix up the group id for the layers of the group moved */
+	for(n = 0; n < stk->grp[to_before].len; n++) {
+		pcb_layer_t *l = pcb_get_layer(stk->grp[to_before].lid[n]);
+		if ((l != NULL) && (l->grp > 0))
+			l->grp = to_before;
+	}
+
+	NOTIFY();
+	return 0;
+}
+
+
+	/* ugly hack: remove the extra substrate we added after the outline layer */
+void pcb_layergrp_fix_old_outline(pcb_layer_stack_t *LayerGroup)
+{
+	pcb_layer_group_t *g = pcb_get_grp(LayerGroup, PCB_LYT_ANYWHERE, PCB_LYT_OUTLINE);
+	if ((g != NULL) && (g[1].type & PCB_LYT_SUBSTRATE)) {
+		pcb_layergrp_id_t gid = g - LayerGroup->grp + 1;
+		pcb_layergrp_del(LayerGroup, gid, 0);
+	}
+}
+
+void pcb_layergrp_fix_turn_to_outline(pcb_layer_group_t *g)
+{
+	g->type |= PCB_LYT_OUTLINE;
+	g->type &= ~PCB_LYT_COPPER;
+	free(g->name);
+	g->name = pcb_strdup("global outline");
+}
+
+
+#define LAYER_IS_OUTLINE(idx) ((PCB->Data->Layer[idx].Name != NULL) && ((strcmp(PCB->Data->Layer[idx].Name, "route") == 0 || strcmp(PCB->Data->Layer[(idx)].Name, "outline") == 0)))
+int pcb_layer_parse_group_string(const char *grp_str, pcb_layer_stack_t *LayerGroup, int LayerN, int oldfmt)
+{
+	const char *s, *start;
+	pcb_layer_id_t lids[PCB_MAX_LAYER];
+	int lids_len = 0;
+	pcb_layer_type_t loc = PCB_LYT_INTERN;
+	pcb_layer_group_t *g;
+	int n;
+
+	inhibit_notify++;
+
+	/* clear struct */
+	pcb_layer_group_setup_default(LayerGroup);
+
+	for(start = s = grp_str; ; s++) {
+		switch(*s) {
+			case ',':
+				if (flush_item(s, start, lids, &lids_len, &loc) != 0)
+					goto error;
+				start = s+1;
+				break;
+			case '\0':
+			case ':':
+				if (flush_item(s, start, lids, &lids_len, &loc) != 0)
+					goto error;
+				/* finalize group */
+				if (loc & PCB_LYT_INTERN)
+					g = pcb_get_grp_new_intern(LayerGroup, -1);
+				else
+					g = pcb_get_grp(LayerGroup, loc, PCB_LYT_COPPER);
+
+				for(n = 0; n < lids_len; n++) {
+					if (lids[n] < 0)
+						continue;
+					if (LAYER_IS_OUTLINE(lids[n])) {
+						if (g->type & PCB_LYT_INTERN)
+							pcb_layergrp_fix_turn_to_outline(g);
+						else
+							pcb_message(PCB_MSG_ERROR, "outline layer can not be on the solder or component side - converting it into a copper layer\n");
+					}
+					pcb_layer_add_in_group_(g, g - LayerGroup->grp, lids[n]);
+				}
+
+				lids_len = 0;
+
+				/* prepare for next iteration */
+				loc = PCB_LYT_INTERN;
+				start = s+1;
+				break;
+		}
+		if (*s == '\0')
+			break;
+	}
+
+	pcb_layergrp_fix_old_outline(LayerGroup);
+
+	/* set the two silks */
+	g = pcb_get_grp(LayerGroup, PCB_LYT_BOTTOM, PCB_LYT_SILK);
+	pcb_layer_add_in_group_(g, g - LayerGroup->grp, LayerN-2);
+
+	g = pcb_get_grp(LayerGroup, PCB_LYT_TOP, PCB_LYT_SILK);
+	pcb_layer_add_in_group_(g, g - LayerGroup->grp, LayerN-1);
+
+	inhibit_notify--;
+	return 0;
+
+	/* reset structure on error */
+error:
+	inhibit_notify--;
+	memset(LayerGroup, 0, sizeof(pcb_layer_stack_t));
+	return 1;
+}
+
+int pcb_layer_gui_set_glayer(pcb_layergrp_id_t grp, int is_empty)
+{
+	/* if there's no GUI, that means no draw should be done */
+	if (pcb_gui == NULL)
+		return 0;
+
+	if (pcb_gui->set_layer_group != NULL)
+		return pcb_gui->set_layer_group(grp, PCB->LayerGroups.grp[grp].lid[0], pcb_layergrp_flags(grp), is_empty);
+
+	/* if the GUI doesn't have a set_layer, assume it wants to draw all layers */
+	return 1;
+}
+
+#define APPEND(n) \
+	do { \
+		if (res != NULL) { \
+			if (used < res_len) { \
+				res[used] = n; \
+				used++; \
+			} \
+		} \
+		else \
+			used++; \
+	} while(0)
+
+int pcb_layer_group_list(pcb_layer_type_t mask, pcb_layergrp_id_t *res, int res_len)
+{
+	int group, used = 0;
+	for (group = 0; group < pcb_max_group; group++) {
+		if ((pcb_layergrp_flags(group) & mask) == mask)
+				APPEND(group);
+	}
+	return used;
+}
+
+int pcb_layer_group_list_any(pcb_layer_type_t mask, pcb_layergrp_id_t *res, int res_len)
+{
+	int group, used = 0;
+	for (group = 0; group < pcb_max_group; group++) {
+		if ((pcb_layergrp_flags(group) & mask))
+				APPEND(group);
+	}
+	return used;
+}
+
+pcb_layergrp_id_t pcb_layer_lookup_group(pcb_layer_id_t layer_id)
+{
+	if ((layer_id < 0) || (layer_id > pcb_max_layer))
+		return -1;
+	return PCB->Data->Layer[layer_id].grp;
+}
+
+int pcb_layer_add_in_group_(pcb_layer_group_t *grp, pcb_layergrp_id_t group_id, pcb_layer_id_t layer_id)
+{
+	if ((layer_id < 0) || (layer_id >= pcb_max_layer))
+		return -1;
+
+	grp->lid[grp->len] = layer_id;
+	grp->len++;
+	PCB->Data->Layer[layer_id].grp = group_id;
+
+	return 0;
+}
+
+int pcb_layer_add_in_group(pcb_layer_id_t layer_id, pcb_layergrp_id_t group_id)
+{
+	if ((group_id < 0) || (group_id >= PCB->LayerGroups.len))
+		return -1;
+
+	return pcb_layer_add_in_group_(&PCB->LayerGroups.grp[group_id], group_id, layer_id);
+}
+
+#define NEWG(g, flags, gname) \
+do { \
+	g = &(newg->grp[newg->len]); \
+	g->valid = 1; \
+	if (gname != NULL) \
+		g->name = pcb_strdup(gname); \
+	else \
+		g->name = NULL; \
+	g->type = flags; \
+	newg->len++; \
+} while(0)
+
+void pcb_layer_group_setup_default(pcb_layer_stack_t *newg)
+{
+	pcb_layer_group_t *g;
+
+	memset(newg, 0, sizeof(pcb_layer_stack_t));
+
+	NEWG(g, PCB_LYT_TOP | PCB_LYT_PASTE, "top paste");
+	NEWG(g, PCB_LYT_TOP | PCB_LYT_SILK, "top silk");
+	NEWG(g, PCB_LYT_TOP | PCB_LYT_MASK, "top mask");
+	NEWG(g, PCB_LYT_TOP | PCB_LYT_COPPER, "top copper");
+	NEWG(g, PCB_LYT_INTERN | PCB_LYT_SUBSTRATE, NULL);
+
+	NEWG(g, PCB_LYT_BOTTOM | PCB_LYT_COPPER, "bottom copper");
+	NEWG(g, PCB_LYT_BOTTOM | PCB_LYT_MASK, "bottom mask");
+	NEWG(g, PCB_LYT_BOTTOM | PCB_LYT_SILK, "bottom silk");
+	NEWG(g, PCB_LYT_BOTTOM | PCB_LYT_PASTE, "bottom paste");
+
+/*	NEWG(g, PCB_LYT_INTERN | PCB_LYT_OUTLINE, "outline");*/
+}
+
+static pcb_layergrp_id_t pcb_layergrp_get_cached(pcb_layer_id_t *cache, unsigned int loc, unsigned int typ)
+{
+	pcb_layer_group_t *g;
+
+	/* check if the last known value is still accurate */
+	if ((*cache >= 0) && (*cache < PCB->LayerGroups.len)) {
+		g = &(PCB->LayerGroups.grp[*cache]);
+		if ((g->type & loc) && (g->type & typ))
+			return *cache;
+	}
+
+	/* nope: need to resolve it again */
+	g = pcb_get_grp(&PCB->LayerGroups, loc, typ);
+	if (g == NULL)
+		*cache = -1;
+	else
+		*cache = (g - PCB->LayerGroups.grp);
+	return *cache;
+}
+
+pcb_layergrp_id_t pcb_layergrp_get_bottom_mask()
+{
+	static pcb_layer_id_t cache = -1;
+	return pcb_layergrp_get_cached(&cache, PCB_LYT_BOTTOM, PCB_LYT_MASK);
+}
+
+pcb_layergrp_id_t pcb_layergrp_get_top_mask()
+{
+	static pcb_layer_id_t cache = -1;
+	return pcb_layergrp_get_cached(&cache, PCB_LYT_TOP, PCB_LYT_MASK);
+}
+
+pcb_layergrp_id_t pcb_layergrp_get_bottom_paste()
+{
+	static pcb_layer_id_t cache = -1;
+	return pcb_layergrp_get_cached(&cache, PCB_LYT_BOTTOM, PCB_LYT_PASTE);
+}
+
+pcb_layergrp_id_t pcb_layergrp_get_top_paste()
+{
+	static pcb_layer_id_t cache = -1;
+	return pcb_layergrp_get_cached(&cache, PCB_LYT_TOP, PCB_LYT_PASTE);
+}
diff --git a/src/layer_grp.h b/src/layer_grp.h
new file mode 100644
index 0000000..1b64f3c
--- /dev/null
+++ b/src/layer_grp.h
@@ -0,0 +1,155 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996,2006 Thomas Nau
+ *  Copyright (C) 2016, 2017 Tibor 'Igor2' Palinkas (pcb-rnd extensions)
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+#ifndef PCB_LAYER_GRP_H
+#define PCB_LAYER_GRP_H
+
+typedef struct pcb_layer_group_s pcb_layer_group_t;
+
+#include "layer.h"
+
+/* ----------------------------------------------------------------------
+ * layer group. A layer group identifies layers which are always switched
+ * on/off together.
+ */
+
+struct pcb_layer_group_s {
+	pcb_cardinal_t len;                    /* number of layer IDs in use */
+	pcb_layer_id_t lid[PCB_MAX_LAYER];     /* lid=layer ID */
+	char *name;                            /* name of the physical layer (independent of the name of the layer groups) */
+	pcb_layer_type_t type;
+
+	unsigned valid:1;                      /* 1 if it's a new-style, valid layer group; 0 after loading old files with no layer stackup info */
+	unsigned vis:1;                        /* 1 if layer group is visible on the GUI */
+
+	/* internal: temporary states */
+	int intern_id;                         /* for the old layer import mechanism */
+};
+
+
+/* layer stack: an ordered list of layer groups (physical layers). */
+struct pcb_layer_stack_s {
+	pcb_cardinal_t len;
+	pcb_layer_group_t grp[PCB_MAX_LAYERGRP];
+};
+
+/* lookup the group to which a layer belongs to returns -1 if no group is found */
+pcb_layergrp_id_t pcb_layer_get_group(pcb_layer_id_t Layer);
+pcb_layergrp_id_t pcb_layer_get_group_(pcb_layer_t *Layer);
+
+/* Returns group actually moved to (i.e. either group or previous) */
+pcb_layergrp_id_t pcb_layer_move_to_group(pcb_layer_id_t layer, pcb_layergrp_id_t group);
+
+/* Returns pcb_true if all layers in a group are empty */
+pcb_bool pcb_is_layergrp_empty(pcb_layergrp_id_t lgrp);
+
+/* call the gui to set a layer group */
+int pcb_layer_gui_set_glayer(pcb_layergrp_id_t grp, int is_empty);
+
+/* returns a bitfield of pcb_layer_type_t; returns 0 if layer_idx is invalid. */
+unsigned int pcb_layergrp_flags(pcb_layergrp_id_t group_idx);
+const char *pcb_layergrp_name(pcb_layergrp_id_t gid);
+
+/* Same as pcb_layer_list but lists layer groups. A group is matching
+   if any layer in that group matches mask. */
+int pcb_layer_group_list(pcb_layer_type_t mask, pcb_layergrp_id_t *res, int res_len);
+int pcb_layer_group_list_any(pcb_layer_type_t mask, pcb_layergrp_id_t *res, int res_len);
+
+/* Looks up which group a layer is in. Returns group ID. */
+pcb_layergrp_id_t pcb_layer_lookup_group(pcb_layer_id_t layer_id);
+
+/* Put a layer in a group (the layer should not be in any other group);
+   returns 0 on success */
+int pcb_layer_add_in_group(pcb_layer_id_t layer_id, pcb_layergrp_id_t group_id);
+int pcb_layer_add_in_group_(pcb_layer_group_t *grp, pcb_layergrp_id_t group_id, pcb_layer_id_t layer_id);
+
+/* Remove a layer group; if del_layers is zero, layers are kept but detached
+   (.grp = -1), else layers are deleted too */
+int pcb_layergrp_del(pcb_layer_stack_t *stk, pcb_layergrp_id_t gid, int del_layers);
+
+/** Move gfrom to to_before and shift the stack as necessary. Return -1 on range error */
+int pcb_layergrp_move(pcb_layer_stack_t *stk, pcb_layergrp_id_t gfrom, pcb_layergrp_id_t to_before);
+
+/** Move src onto dst, not shifting the stack, free()'ing and overwriting dst,
+    leaving a gap (0'd slot) at src */
+int pcb_layergrp_move_onto(pcb_layer_stack_t *stack, pcb_layergrp_id_t dst, pcb_layergrp_id_t src);
+
+
+/* Insert a new layer group in the layer stack after the specified group */
+pcb_layer_group_t *pcb_layergrp_insert_after(pcb_layer_stack_t *stack, pcb_layergrp_id_t where);
+
+
+/* Enable/disable inhibition of layer changed events during layer group updates */
+void pcb_layergrp_inhibit_inc(void);
+void pcb_layergrp_inhibit_dec(void);
+
+/********* OBSOLETE functions, do not use in new code *********/
+/* parses the group definition string which is a colon separated list of
+   comma separated layer numbers (1,2,b:4,6,8,t); oldfmt is 0 or 1
+   depending on PCB() or PCB[] in the file header.
+
+   OBSOLETE, do not use in new code: only the conf system and io_pcb
+   may need this. */
+int pcb_layer_parse_group_string(const char *s, pcb_layer_stack_t *LayerGroup, int LayerN, int oldfmt);
+
+#define PCB_COPPER_GROUP_LOOP(data, group) do { 	\
+	pcb_cardinal_t entry; \
+        for (entry = 0; entry < ((pcb_board_t *)(data->pcb))->LayerGroups.grp[(group)].len; entry++) \
+        { \
+		pcb_layer_t *layer;		\
+		pcb_layer_id_t number; 		\
+		number = ((pcb_board_t *)(data->pcb))->LayerGroups.grp[(group)].lid[entry]; \
+		if (!(pcb_layer_flags(number) & PCB_LYT_COPPER)) \
+		  continue;			\
+		layer = &data->Layer[number];
+
+/* transitional code: old loaders load the old layer stack, convert to the new
+   (and back before save) */
+void pcb_layer_group_from_old(pcb_board_t *pcb);
+void pcb_layer_group_to_old(pcb_board_t *pcb);
+
+/* for parsing old files with old layer descriptions, with no layer groups */
+void pcb_layer_group_setup_default(pcb_layer_stack_t *newg);
+pcb_layer_group_t *pcb_get_grp(pcb_layer_stack_t *stack, pcb_layer_type_t loc, pcb_layer_type_t typ);
+pcb_layer_group_t *pcb_get_grp_new_intern(pcb_layer_stack_t *stack, int intern_id);
+pcb_layer_group_t *pcb_get_grp_new_misc(pcb_layer_stack_t *stack);
+
+/* ugly hack: remove the extra substrate we added after the outline layer */
+void pcb_layergrp_fix_old_outline(pcb_layer_stack_t *LayerGroup);
+
+/* ugly hack: turn an old intern layer group into an outline group after realizing it is really an outline (reading the old layers) */
+void pcb_layergrp_fix_turn_to_outline(pcb_layer_group_t *g);
+
+
+
+/* Cached layer group lookups foir a few common cases */
+pcb_layergrp_id_t pcb_layergrp_get_bottom_mask();
+pcb_layergrp_id_t pcb_layergrp_get_top_mask();
+pcb_layergrp_id_t pcb_layergrp_get_bottom_paste();
+pcb_layergrp_id_t pcb_layergrp_get_top_paste();
+
+#endif
diff --git a/src/layer_it.h b/src/layer_it.h
new file mode 100644
index 0000000..8b4c7f9
--- /dev/null
+++ b/src/layer_it.h
@@ -0,0 +1,120 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* Layer and layer group iterators (static inline functions) */
+
+#ifndef PCB_LAYER_IT_H
+#define PCB_LAYER_IT_H
+
+#include "layer_grp.h"
+
+typedef struct pcb_layer_it_s pcb_layer_it_t;
+
+/* Start an iteration matching exact flags or any of the flags; returns -1 if over */
+static inline PCB_FUNC_UNUSED pcb_layer_id_t pcb_layer_first(pcb_layer_stack_t *stack, pcb_layer_it_t *it, unsigned int exact_mask);
+static inline PCB_FUNC_UNUSED pcb_layer_id_t pcb_layer_first_any(pcb_layer_stack_t *stack, pcb_layer_it_t *it, unsigned int any_mask);
+
+/* next iteration; returns -1 if over */
+static inline PCB_FUNC_UNUSED pcb_layer_id_t pcb_layer_next(pcb_layer_it_t *it);
+
+
+/*************** inline implementation *************************/
+struct pcb_layer_it_s {
+	pcb_layer_stack_t *stack;
+	pcb_layergrp_id_t gid;
+	pcb_cardinal_t lidx;
+	unsigned int mask;
+	unsigned int exact:1;
+	unsigned int global:1;
+};
+
+static inline PCB_FUNC_UNUSED pcb_layer_id_t pcb_layer_next(pcb_layer_it_t *it)
+{
+	if (it->global) {
+		/* over all layers, random order, without any checks - go the cheap way, bypassing groups */
+		if (it->lidx < pcb_max_layer)
+			return it->lidx++;
+		return -1;
+	}
+	else for(;;) {
+		pcb_layer_group_t *g = &(it->stack->grp[it->gid]);
+		pcb_layer_id_t lid;
+		unsigned int hit;
+		if (it->lidx >= g->len) { /* layer list over in this group */
+			it->gid++;
+			if (it->gid >= PCB_MAX_LAYERGRP) /* last group */
+				return -1;
+			it->lidx = 0;
+			continue; /* skip to next group */
+		}
+		/* TODO: check group flags against mask here for more efficiency */
+		lid = g->lid[it->lidx];
+		it->lidx++;
+		hit = pcb_layer_flags(lid) & it->mask;
+		if (it->exact) {
+			if (hit == it->mask)
+				return lid;
+		}
+		else {
+			if (hit)
+				return lid;
+		}
+		/* skip to next group */
+	}
+}
+
+static inline PCB_FUNC_UNUSED pcb_layer_id_t pcb_layer_first(pcb_layer_stack_t *stack, pcb_layer_it_t *it, unsigned int exact_mask)
+{
+	it->stack = stack;
+	it->mask = exact_mask;
+	it->gid = 0;
+	it->lidx = 0;
+	it->exact = 1;
+	it->global = 0;
+	return pcb_layer_next(it);
+}
+
+static inline PCB_FUNC_UNUSED pcb_layer_id_t pcb_layer_first_any(pcb_layer_stack_t *stack, pcb_layer_it_t *it, unsigned int any_mask)
+{
+	it->stack = stack;
+	it->mask = any_mask;
+	it->gid = 0;
+	it->lidx = 0;
+	it->exact = 0;
+	it->global = 0;
+	return pcb_layer_next(it);
+}
+
+static inline PCB_FUNC_UNUSED pcb_layer_id_t pcb_layer_first_all(pcb_layer_stack_t *stack, pcb_layer_it_t *it)
+{
+	it->stack = stack;
+	it->lidx = 0;
+	it->global = 1;
+	return pcb_layer_next(it);
+}
+
+
+#endif
diff --git a/src/layer_vis.c b/src/layer_vis.c
index a8c7d78..846a35b 100644
--- a/src/layer_vis.c
+++ b/src/layer_vis.c
@@ -85,8 +85,8 @@ void pcb_layervis_parse_string(const char *layer_string)
 		}
 	}
 
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-		if (i < pcb_max_copper_layer)
+	for (i = 0; i < pcb_max_layer; i++) {
+		if (!(pcb_layer_flags(i) & PCB_LYT_SILK))
 			pcb_layer_stack[i] = i;
 		PCB->Data->Layer[i].On = pcb_false;
 	}
@@ -120,7 +120,7 @@ void pcb_layervis_parse_string(const char *layer_string)
 		}
 		else {
 			int found = 0;
-			for (lno = 0; lno < pcb_max_copper_layer; lno++)
+			for (lno = 0; lno < pcb_max_layer; lno++)
 				if (pcb_strcasecmp(args[i], PCB->Data->Layer[lno].Name) == 0) {
 					pcb_layervis_change_group_vis(lno, pcb_true, pcb_true);
 					found = 1;
@@ -131,7 +131,7 @@ void pcb_layervis_parse_string(const char *layer_string)
 				if (!listed_layers) {
 					fprintf(stderr, "Named layers in this board are:\n");
 					listed_layers = 1;
-					for (lno = 0; lno < pcb_max_copper_layer; lno++)
+					for (lno = 0; lno < pcb_max_layer; lno++)
 						fprintf(stderr, "\t%s\n", PCB->Data->Layer[lno].Name);
 					fprintf(stderr, "Also: component, solder, rats, invisible, pins, vias, elements or silk, mask, solderside.\n");
 				}
@@ -148,9 +148,9 @@ static void PushOnTopOfLayerStack(int NewTop)
 	int i;
 
 	/* ignore silk layers */
-	if (NewTop < pcb_max_copper_layer) {
+	if (NewTop < pcb_max_layer) {
 		/* first find position of passed one */
-		for (i = 0; i < pcb_max_copper_layer; i++)
+		for (i = 0; i < pcb_max_layer; i++)
 			if (pcb_layer_stack[i] == NewTop)
 				break;
 
@@ -189,11 +189,11 @@ int pcb_layervis_change_group_vis(int Layer, pcb_bool On, pcb_bool ChangeStackOr
 
 	/* decrement 'i' to keep stack in order of layergroup */
 	if ((group = pcb_layer_get_group(Layer)) >= 0) {
-		for (i = PCB->LayerGroups.Number[group]; i;) {
-			int layer = PCB->LayerGroups.Entries[group][--i];
+		for (i = PCB->LayerGroups.grp[group].len; i;) {
+			pcb_layer_id_t layer = PCB->LayerGroups.grp[group].lid[--i];
 
 			/* don't count the passed member of the group */
-			if (layer != Layer && layer < pcb_max_copper_layer) {
+			if (layer != Layer && layer < pcb_max_layer) {
 				PCB->Data->Layer[layer].On = On;
 
 				/* push layer on top of stack if switched on */
@@ -220,12 +220,12 @@ int pcb_layervis_change_group_vis(int Layer, pcb_bool On, pcb_bool ChangeStackOr
  */
 void pcb_layervis_reset_stack(void)
 {
-	pcb_layergrp_id_t comp_group;
+	pcb_layer_id_t comp;
 	pcb_cardinal_t i;
 
 	assert(PCB->Data->LayerN <= PCB_MAX_LAYER);
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-		if (i < pcb_max_copper_layer)
+	for (i = 0; i < pcb_max_layer; i++) {
+		if (!(pcb_layer_flags(i) & PCB_LYT_SILK))
 			pcb_layer_stack[i] = i;
 		PCB->Data->Layer[i].On = pcb_true;
 	}
@@ -235,9 +235,9 @@ void pcb_layervis_reset_stack(void)
 	PCB->ViaOn = pcb_true;
 	PCB->RatOn = pcb_true;
 
-	/* Bring the component group to the front and make it active.  */
-	comp_group = pcb_layer_get_group(pcb_component_silk_layer);
-	pcb_layervis_change_group_vis(PCB->LayerGroups.Entries[comp_group][0], 1, 1);
+	/* Bring the top copper group to the front and make it active.  */
+	if (pcb_layer_list(PCB_LYT_TOP | PCB_LYT_COPPER, &comp, 1) > 0)
+		pcb_layervis_change_group_vis(comp, 1, 1);
 }
 
 /* ---------------------------------------------------------------------------
@@ -258,8 +258,8 @@ void pcb_layervis_save_stack(void)
 						"pcb_layervis_save_stack()  layerstack was already saved and not" "yet restored.  cnt = %d\n", SavedStack.cnt);
 	}
 
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-		if (i < pcb_max_copper_layer)
+	for (i = 0; i < pcb_max_layer; i++) {
+		if (!(pcb_layer_flags(i) & PCB_LYT_SILK))
 			SavedStack.pcb_layer_stack[i] = pcb_layer_stack[i];
 		SavedStack.LayerOn[i] = PCB->Data->Layer[i].On;
 	}
@@ -286,8 +286,8 @@ void pcb_layervis_restore_stack(void)
 		fprintf(stderr, "pcb_layervis_restore_stack()  layerstack save count is" " wrong.  cnt = %d\n", SavedStack.cnt);
 	}
 
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-		if (i < pcb_max_copper_layer)
+	for (i = 0; i < pcb_max_layer; i++) {
+		if (!(pcb_layer_flags(i) & PCB_LYT_SILK))
 			pcb_layer_stack[i] = SavedStack.pcb_layer_stack[i];
 		PCB->Data->Layer[i].On = SavedStack.LayerOn[i];
 	}
diff --git a/src/main.c b/src/main.c
index d062f5c..d233ce2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -28,8 +28,10 @@
 /* main program, initializes some stuff and handles user input
  */
 #include "config.h"
-
 #include <stdlib.h>
+
+static const char *EXPERIMENTAL = NULL;
+
 #include <string.h>
 #include <signal.h>
 #include <sys/stat.h>
@@ -464,10 +466,10 @@ int main(int argc, char *argv[])
 	pcb_gui->parse_arguments(&hid_argc, &hid_argv);
 
 	/* Create a new PCB object in memory */
-	PCB = pcb_board_new();
+	PCB = pcb_board_new(0);
 
 	if (PCB == NULL) {
-		pcb_message(PCB_MSG_ERROR, "Can't load the default pcb for creating an empty layout\n");
+		pcb_message(PCB_MSG_ERROR, "Can't create an empty layout, exiting\n");
 		exit(1);
 	}
 
@@ -522,6 +524,13 @@ int main(int argc, char *argv[])
 
 	/* main loop */
 	do {
+		if (EXPERIMENTAL != NULL) {
+			pcb_message(PCB_MSG_ERROR, "******************************** IMPORTANT ********************************\n");
+			pcb_message(PCB_MSG_ERROR, "This revision of pcb-rnd is experimental, unstable, do NOT attempt to use\n");
+			pcb_message(PCB_MSG_ERROR, "it for production. The reason for this state is:\n");
+			pcb_message(PCB_MSG_ERROR, "%s\n", EXPERIMENTAL);
+			pcb_message(PCB_MSG_ERROR, "******************************** IMPORTANT ********************************\n");
+		}
 		pcb_gui->do_export(0);
 		pcb_gui = pcb_next_gui;
 		pcb_next_gui = NULL;
diff --git a/src/math_helper.h b/src/math_helper.h
index c950082..0c3cf05 100644
--- a/src/math_helper.h
+++ b/src/math_helper.h
@@ -43,6 +43,7 @@
 #define	PCB_TAN_60_DEGREE		1.732050808	/* tan(60) */
 #define PCB_LN_2_OVER_2		0.346573590
 #define PCB_TO_RADIANS(degrees)	(PCB_M180 * (degrees))
+#define PCB_SQRT2	1.41421356237309504880	/* sqrt(2) */
 
 #define PCB_CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
 #define PCB_ABS(a)	   (((a) < 0) ? -(a) : (a))
diff --git a/src/obj_arc.c b/src/obj_arc.c
index c382900..5b71e57 100644
--- a/src/obj_arc.c
+++ b/src/obj_arc.c
@@ -69,29 +69,30 @@ pcb_arc_t *pcb_element_arc_alloc(pcb_element_t *Element)
 
 
 /* computes the bounding box of an arc */
-void pcb_arc_bbox(pcb_arc_t *Arc)
+static pcb_box_t pcb_arc_bbox_(const pcb_arc_t *Arc, int mini)
 {
 	double ca1, ca2, sa1, sa2;
-	double minx, maxx, miny, maxy;
+	double minx, maxx, miny, maxy, delta;
 	pcb_angle_t ang1, ang2;
 	pcb_coord_t width;
+	pcb_box_t res;
 
 	/* first put angles into standard form:
 	 *  ang1 < ang2, both angles between 0 and 720 */
-	Arc->Delta = PCB_CLAMP(Arc->Delta, -360, 360);
+	delta = PCB_CLAMP(Arc->Delta, -360, 360);
 
-	if (Arc->Delta > 0) {
+	if (delta > 0) {
 		ang1 = pcb_normalize_angle(Arc->StartAngle);
-		ang2 = pcb_normalize_angle(Arc->StartAngle + Arc->Delta);
+		ang2 = pcb_normalize_angle(Arc->StartAngle + delta);
 	}
 	else {
-		ang1 = pcb_normalize_angle(Arc->StartAngle + Arc->Delta);
+		ang1 = pcb_normalize_angle(Arc->StartAngle + delta);
 		ang2 = pcb_normalize_angle(Arc->StartAngle);
 	}
 	if (ang1 > ang2)
 		ang2 += 360;
 	/* Make sure full circles aren't treated as zero-length arcs */
-	if (Arc->Delta == 360 || Arc->Delta == -360)
+	if (delta == 360 || delta == -360)
 		ang2 = ang1 + 360;
 
 	/* calculate sines, cosines */
@@ -116,21 +117,31 @@ void pcb_arc_bbox(pcb_arc_t *Arc)
 		miny = -1;
 
 	/* Finally, calculate bounds, converting sane geometry into pcb geometry */
-	Arc->BoundingBox.X1 = Arc->X - Arc->Width * maxx;
-	Arc->BoundingBox.X2 = Arc->X - Arc->Width * minx;
-	Arc->BoundingBox.Y1 = Arc->Y + Arc->Height * miny;
-	Arc->BoundingBox.Y2 = Arc->Y + Arc->Height * maxy;
+	res.X1 = Arc->X - Arc->Width * maxx;
+	res.X2 = Arc->X - Arc->Width * minx;
+	res.Y1 = Arc->Y + Arc->Height * miny;
+	res.Y2 = Arc->Y + Arc->Height * maxy;
+
+	if (!mini) {
+		width = (Arc->Thickness + Arc->Clearance) / 2;
+		/* Adjust for our discrete polygon approximation */
+		width = (double) width *MAX(PCB_POLY_CIRC_RADIUS_ADJ, (1.0 + PCB_POLY_ARC_MAX_DEVIATION)) + 0.5;
+	}
+	else
+		width = Arc->Thickness / 2;
 
-	width = (Arc->Thickness + Arc->Clearance) / 2;
+	res.X1 -= width;
+	res.X2 += width;
+	res.Y1 -= width;
+	res.Y2 += width;
+	pcb_close_box(&res);
+	return res;
+}
 
-	/* Adjust for our discrete polygon approximation */
-	width = (double) width *MAX(PCB_POLY_CIRC_RADIUS_ADJ, (1.0 + PCB_POLY_ARC_MAX_DEVIATION)) + 0.5;
 
-	Arc->BoundingBox.X1 -= width;
-	Arc->BoundingBox.X2 += width;
-	Arc->BoundingBox.Y1 -= width;
-	Arc->BoundingBox.Y2 += width;
-	pcb_close_box(&Arc->BoundingBox);
+void pcb_arc_bbox(pcb_arc_t *Arc)
+{
+	Arc->BoundingBox = pcb_arc_bbox_(Arc, 0);
 }
 
 
@@ -261,6 +272,10 @@ double pcb_arc_area(const pcb_arc_t *arc)
 		+ (double)arc->Thickness * (double)arc->Thickness * (double)M_PI); /* cap circles */
 }
 
+pcb_box_t pcb_arc_mini_bbox(const pcb_arc_t *arc)
+{
+	return pcb_arc_bbox_(arc, 1);
+}
 
 /***** operations *****/
 
@@ -323,6 +338,8 @@ void *ChangeArcClearSize(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc)
 
 	if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc) || !PCB_FLAG_TEST(PCB_FLAG_CLEARLINE, Arc))
 		return (NULL);
+	if (value < 0)
+		value = 0;
 	value = MIN(PCB_MAX_LINESIZE, MAX(value, PCB->Bloat * 2 + 2));
 	if (value != Arc->Clearance) {
 		pcb_undo_add_obj_to_clear_size(PCB_TYPE_ARC, Layer, Arc, Arc);
@@ -555,6 +572,11 @@ void *RemoveArc_op(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc)
 	return NULL;
 }
 
+void *RemoveArcPoint_op(pcb_opctx_t *ctx, pcb_layer_t *l, pcb_arc_t *a, int *end_id)
+{
+	return RemoveArc_op(ctx, l, a);
+}
+
 void *pcb_arc_destroy(pcb_layer_t *Layer, pcb_arc_t *Arc)
 {
 	pcb_opctx_t ctx;
@@ -661,6 +683,8 @@ void _draw_arc(pcb_arc_t * arc)
 	if (!arc->Thickness)
 		return;
 
+	PCB_DRAW_BBOX(arc);
+
 	if (conf_core.editor.thin_draw)
 		pcb_gui->set_line_width(Output.fgGC, 0);
 	else
diff --git a/src/obj_arc.h b/src/obj_arc.h
index 77b6d45..b731152 100644
--- a/src/obj_arc.h
+++ b/src/obj_arc.h
@@ -58,6 +58,8 @@ void pcb_arc_rotate90(pcb_arc_t *Arc, pcb_coord_t X, pcb_coord_t Y, unsigned Num
 void pcb_arc_rotate(pcb_layer_t *layer, pcb_arc_t *arc, pcb_coord_t X, pcb_coord_t Y, double cosa, double sina, pcb_angle_t angle);
 void pcb_arc_mirror(pcb_layer_t *layer, pcb_arc_t *arc);
 void pcb_arc_flip_side(pcb_layer_t *layer, pcb_arc_t *arc);
+pcb_box_t pcb_arc_mini_bbox(const pcb_arc_t *arc);
+
 
 /*** hash ***/
 int pcb_arc_eq(const pcb_element_t *e1, const pcb_arc_t *a1, const pcb_element_t *e2, const pcb_arc_t *a2);
@@ -94,29 +96,30 @@ extern int *pcb_arc_start_ptr, *pcb_arc_end_ptr;
 #define PCB_ARC_ALL_LOOP(top) do {		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l =0; l < pcb_max_copper_layer + 2; l++, layer++)		\
+	for (l =0; l < pcb_max_layer; l++, layer++)		\
 	{ \
 		PCB_ARC_LOOP(layer)
 
 #define PCB_ARC_COPPER_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l =0; l < pcb_max_copper_layer; l++, layer++)		\
+	for (l =0; l < pcb_max_layer; l++, layer++)		\
 	{ \
+		if (!(pcb_layer_flags(l) & PCB_LYT_COPPER)) continue; \
 		PCB_ARC_LOOP(layer)
 
 #define PCB_ARC_SILK_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	layer += pcb_max_copper_layer;			\
-	for (l = 0; l < 2; l++, layer++)		\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
+		if (!(pcb_layer_flags(l) & PCB_LYT_SILK)) continue; \
 		PCB_ARC_LOOP(layer)
 
 #define PCB_ARC_VISIBLE_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l = 0; l < pcb_max_copper_layer + 2; l++, layer++)	\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
 		if (layer->On)				\
 			PCB_ARC_LOOP(layer)
diff --git a/src/obj_arc_op.h b/src/obj_arc_op.h
index 0036d56..00662da 100644
--- a/src/obj_arc_op.h
+++ b/src/obj_arc_op.h
@@ -43,6 +43,7 @@ void *MoveArcToLayerLowLevel(pcb_opctx_t *ctx, pcb_layer_t * Source, pcb_arc_t *
 void *MoveArcToLayer(pcb_opctx_t *ctx, pcb_layer_t * Layer, pcb_arc_t * Arc);
 void *DestroyArc(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc);
 void *RemoveArc_op(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc);
+void *RemoveArcPoint_op(pcb_opctx_t *ctx, pcb_layer_t *l, pcb_arc_t *a, int *end_id);
 void *Rotate90Arc(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc);
 
 void *pcb_arc_insert_point(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *arc);
diff --git a/src/obj_elem.c b/src/obj_elem.c
index a063b03..7974875 100644
--- a/src/obj_elem.c
+++ b/src/obj_elem.c
@@ -161,7 +161,7 @@ int pcb_element_load_footprint_by_name(pcb_buffer_t *Buffer, const char *Footpri
 pcb_bool pcb_element_smash_buffer(pcb_buffer_t *Buffer)
 {
 	pcb_element_t *element;
-	pcb_layergrp_id_t group;
+	pcb_layergrp_id_t group, gbottom, gtop;
 	pcb_layer_t *clayer, *slayer;
 
 	if (elementlist_length(&Buffer->Data->Element) != 1) {
@@ -204,10 +204,15 @@ pcb_bool pcb_element_smash_buffer(pcb_buffer_t *Buffer)
 		pcb_via_new(Buffer->Data, pin->X, pin->Y, pin->Thickness, pin->Clearance, pin->Mask, pin->DrillingHole, pin->Number, f);
 	}
 	PCB_END_LOOP;
-	group = pcb_layer_get_group(PCB_SWAP_IDENT ? pcb_solder_silk_layer : pcb_component_silk_layer);
-	clayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
-	group = pcb_layer_get_group(PCB_SWAP_IDENT ? pcb_component_silk_layer : pcb_solder_silk_layer);
-	slayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
+
+	gbottom = gtop = -1;
+	pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &gbottom, 1);
+	pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER,    &gtop, 1);
+
+	group = (PCB_SWAP_IDENT ? gbottom : gtop);
+	clayer = &Buffer->Data->Layer[PCB->LayerGroups.grp[group].lid[0]];
+	group = (PCB_SWAP_IDENT ? gbottom : gtop);
+	slayer = &Buffer->Data->Layer[PCB->LayerGroups.grp[group].lid[0]];
 	PCB_PAD_LOOP(element);
 	{
 		pcb_line_t *line;
@@ -256,12 +261,16 @@ static int polygon_is_rectangle(pcb_polygon_t *poly)
 pcb_bool pcb_element_convert_from_buffer(pcb_buffer_t *Buffer)
 {
 	pcb_element_t *Element;
-	pcb_layergrp_id_t group;
+	pcb_layergrp_id_t group, gbottom, gtop;
 	pcb_cardinal_t pin_n = 1;
 	pcb_bool hasParts = pcb_false, crooked = pcb_false;
 	int onsolder;
 	pcb_bool warned = pcb_false;
 
+	gbottom = gtop = -1;
+	pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &gbottom, 1);
+	pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER,    &gtop, 1);
+
 	if (Buffer->Data->pcb == 0)
 		Buffer->Data->pcb = PCB;
 
@@ -294,11 +303,11 @@ pcb_bool pcb_element_convert_from_buffer(pcb_buffer_t *Buffer)
 		int onsolderflag;
 
 		if ((!onsolder) == (!PCB_SWAP_IDENT)) {
-			silk_layer = pcb_component_silk_layer;
+			silk_layer = gtop;
 			onsolderflag = PCB_FLAG_NO;
 		}
 		else {
-			silk_layer = pcb_solder_silk_layer;
+			silk_layer = gbottom;
 			onsolderflag = PCB_FLAG_ONSOLDER;
 		}
 
@@ -314,7 +323,7 @@ pcb_bool pcb_element_convert_from_buffer(pcb_buffer_t *Buffer)
 
 		/* get the component-side SM pads */
 		group = pcb_layer_get_group(silk_layer);
-		GROUP_LOOP(Buffer->Data, group);
+		PCB_COPPER_GROUP_LOOP(Buffer->Data, group);
 		{
 			char num[8];
 			PCB_LINE_LOOP(layer);
@@ -715,6 +724,15 @@ void pcb_element_mirror(pcb_data_t *Data, pcb_element_t *Element, pcb_coord_t yo
 	pcb_poly_clear_from_poly(Data, PCB_TYPE_ELEMENT, Element, Element);
 }
 
+int pcb_element_is_empty(pcb_element_t *Element)
+{
+	return
+		(pinlist_length(&Element->Pin) == 0)
+		&& (padlist_length(&Element->Pad) == 0)
+		&& (linelist_length(&Element->Line) == 0)
+		&& (arclist_length(&Element->Arc) == 0);
+}
+
 /* sets the bounding box of an elements */
 void pcb_element_bbox(pcb_data_t *Data, pcb_element_t *Element, pcb_font_t *Font)
 {
@@ -722,6 +740,13 @@ void pcb_element_bbox(pcb_data_t *Data, pcb_element_t *Element, pcb_font_t *Font
 
 	if (Data && Data->element_tree)
 		pcb_r_delete_entry(Data->element_tree, (pcb_box_t *) Element);
+
+	if (pcb_element_is_empty(Element)) {
+		pcb_message(PCB_MSG_ERROR, "Internal error: can not calculate bounding box of empty element. Please report this bug.\n");
+		assert(!"empty elem");
+		return;
+	}
+
 	/* first update the text objects */
 	PCB_ELEMENT_PCB_TEXT_LOOP(Element);
 	{
diff --git a/src/obj_elem.h b/src/obj_elem.h
index 964f189..aa40e5a 100644
--- a/src/obj_elem.h
+++ b/src/obj_elem.h
@@ -62,6 +62,9 @@ void pcb_element_destroy(pcb_element_t * element);
 pcb_line_t *pcb_element_line_alloc(pcb_element_t *Element);
 
 
+/* returns non-zero if the element has no objects in it */
+int pcb_element_is_empty(pcb_element_t *Element);
+
 void pcb_element_bbox(pcb_data_t *Data, pcb_element_t *Element, pcb_font_t *Font);
 void pcb_element_rotate90(pcb_data_t *Data, pcb_element_t *Element, pcb_coord_t X, pcb_coord_t Y, unsigned Number);
 void pcb_element_rotate(pcb_data_t *Data, pcb_element_t *Element, pcb_coord_t X, pcb_coord_t Y, double cosa, double sina, pcb_angle_t angle);
diff --git a/src/obj_line.c b/src/obj_line.c
index 2babd90..f63ca86 100644
--- a/src/obj_line.c
+++ b/src/obj_line.c
@@ -338,6 +338,8 @@ void *ChangeLineClearSize(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_line_t *Line
 
 	if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Line) || !PCB_FLAG_TEST(PCB_FLAG_CLEARLINE, Line))
 		return (NULL);
+	if (value < 0)
+		value = 0;
 	value = MIN(PCB_MAX_LINESIZE, MAX(value, PCB->Bloat * 2 + 2));
 	if (value != Line->Clearance) {
 		pcb_undo_add_obj_to_clear_size(PCB_TYPE_LINE, Layer, Line, Line);
@@ -539,7 +541,7 @@ void *MoveLineToLayer(pcb_opctx_t *ctx, pcb_layer_t * Layer, pcb_line_t * Line)
 	pcb_draw();
 	if (!PCB->ViaOn || ctx->move.more_to_come ||
 			pcb_layer_get_group_(Layer) ==
-			pcb_layer_get_group_(ctx->move.dst_layer) || TEST_SILK_LAYER(Layer) || TEST_SILK_LAYER(ctx->move.dst_layer))
+			pcb_layer_get_group_(ctx->move.dst_layer) || !(pcb_layer_flags(pcb_layer_id(PCB->Data, Layer)) & PCB_LYT_COPPER) || !(pcb_layer_flags(pcb_layer_id(PCB->Data, ctx->move.dst_layer)) & PCB_LYT_COPPER))
 		return (newone);
 	/* consider via at Point1 */
 	sb.X1 = newone->Point1.X - newone->Thickness / 2;
@@ -794,6 +796,7 @@ void *InsertPointIntoLine(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_line_t *Line
 /*** draw ***/
 void _draw_line(pcb_line_t * line)
 {
+	PCB_DRAW_BBOX(line);
 	pcb_gui->set_line_cap(Output.fgGC, Trace_Cap);
 	if (conf_core.editor.thin_draw)
 		pcb_gui->set_line_width(Output.fgGC, 0);
diff --git a/src/obj_line.h b/src/obj_line.h
index 70e53b3..3f372d5 100644
--- a/src/obj_line.h
+++ b/src/obj_line.h
@@ -99,29 +99,30 @@ void pcb_line_enforce_drc(void);
 #define PCB_LINE_ALL_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l = 0; l < pcb_max_copper_layer + 2; l++, layer++)	\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
 		PCB_LINE_LOOP(layer)
 
 #define PCB_LINE_COPPER_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l = 0; l < pcb_max_copper_layer; l++, layer++)	\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
+		if (!(pcb_layer_flags(l) & PCB_LYT_COPPER)) continue; \
 		PCB_LINE_LOOP(layer)
 
 #define PCB_LINE_SILK_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	layer += pcb_max_copper_layer;			\
-	for (l = 0; l < 2; l++, layer++)		\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
+		if (!(pcb_layer_flags(l) & PCB_LYT_SILK)) continue; \
 		PCB_LINE_LOOP(layer)
 
 #define PCB_LINE_VISIBLE_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l = 0; l < pcb_max_copper_layer + 2; l++, layer++)	\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
 		if (layer->On)				\
 			PCB_LINE_LOOP(layer)
diff --git a/src/obj_line_drcenf.c b/src/obj_line_drcenf.c
index 0e64c05..eb5a632 100644
--- a/src/obj_line_drcenf.c
+++ b/src/obj_line_drcenf.c
@@ -280,11 +280,11 @@ static double drc_lines(pcb_point_t *end, pcb_bool way)
 	}
 	group = pcb_layer_get_group(INDEXOFCURRENT);
 	comp = pcb_max_group + 10;				/* this out-of-range group might save a call */
-	if (pcb_layer_get_group(pcb_solder_silk_layer) == group)
+	if (pcb_layergrp_flags(group) & PCB_LYT_BOTTOM)
 		info.solder = pcb_true;
 	else {
 		info.solder = pcb_false;
-		comp = pcb_layer_get_group(pcb_component_silk_layer);
+		pcb_layer_list(PCB_LYT_TOP | PCB_LYT_SILK, &comp, 1);
 	}
 	temp = length;
 	/* assume the worst */
@@ -360,7 +360,7 @@ static double drc_lines(pcb_point_t *end, pcb_bool way)
 					if (info.solder || comp == group)
 						pcb_r_search(PCB->Data->pad_tree, &line2.BoundingBox, NULL, drcPad_callback, &info, NULL);
 				}
-				GROUP_LOOP(PCB->Data, group);
+				PCB_COPPER_GROUP_LOOP(PCB->Data, group);
 				{
 					info.line = &line1;
 					pcb_r_search(layer->line_tree, &line1.BoundingBox, NULL, drcLine_callback, &info, NULL);
@@ -435,11 +435,11 @@ static void drc_line(pcb_point_t *end)
 	/* prepare for the intersection search */
 	group = pcb_layer_get_group(INDEXOFCURRENT);
 	comp = pcb_max_group + 10;  /* this out-of-range group might save a call */
-	if (pcb_layer_get_group(pcb_solder_silk_layer) == group)
+	if (pcb_layergrp_flags(group) & PCB_LYT_BOTTOM)
 		info.solder = pcb_true;
 	else {
 		info.solder = pcb_false;
-		comp = pcb_layer_get_group(pcb_component_silk_layer);
+		pcb_layer_list(PCB_LYT_TOP | PCB_LYT_SILK, &comp, 1);
 	}
 
 	/* search for intersection */
@@ -450,7 +450,7 @@ static void drc_line(pcb_point_t *end)
 		pcb_r_search(PCB->Data->pin_tree, &line.BoundingBox, NULL, drcVia_callback, &info, NULL);
 		if (info.solder || comp == group)
 			pcb_r_search(PCB->Data->pad_tree, &line.BoundingBox, NULL, drcPad_callback, &info, NULL);
-		GROUP_LOOP(PCB->Data, group);
+		PCB_COPPER_GROUP_LOOP(PCB->Data, group);
 		{
 			info.line = &line;
 			pcb_r_search(layer->line_tree, &line.BoundingBox, NULL, drcLine_callback, &info, NULL);
@@ -476,9 +476,12 @@ void pcb_line_enforce_drc(void)
 	double r1, r2;
 
 	/* Silence a bogus compiler warning by storing this in a variable */
-	int layer_idx = INDEXOFCURRENT;
+	pcb_layer_id_t layer_idx = INDEXOFCURRENT;
 
-	if (pcb_gui->mod1_is_pressed() || pcb_gui->control_is_pressed() || PCB->RatDraw || layer_idx >= pcb_max_copper_layer)
+	if (pcb_gui->mod1_is_pressed() || pcb_gui->control_is_pressed() || PCB->RatDraw)
+		return;
+
+	if (!(pcb_layer_flags(layer_idx) & PCB_LYT_COPPER))
 		return;
 
 	rs.X = r45.X = pcb_crosshair.X;
diff --git a/src/obj_pad.c b/src/obj_pad.c
index 0874156..5a59192 100644
--- a/src/obj_pad.c
+++ b/src/obj_pad.c
@@ -207,9 +207,10 @@ void *ChangePadClearSize(pcb_opctx_t *ctx, pcb_element_t *Element, pcb_pad_t *Pa
 
 	if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Pad))
 		return (NULL);
-	value = MIN(PCB_MAX_LINESIZE, value);
 	if (value < 0)
 		value = 0;
+	else
+		value = MIN(PCB_MAX_LINESIZE, value);
 	if (ctx->chgsize.delta < 0 && value < PCB->Bloat * 2)
 		value = 0;
 	if ((ctx->chgsize.delta > 0 || ctx->chgsize.absolute) && value < PCB->Bloat * 2)
@@ -374,6 +375,8 @@ static void _draw_pad(pcb_hid_gc_t gc, pcb_pad_t * pad, pcb_bool clear, pcb_bool
 	if (clear && !mask && pad->Clearance <= 0)
 		return;
 
+	PCB_DRAW_BBOX(pad);
+
 	if (conf_core.editor.thin_draw || (clear && conf_core.editor.thin_draw_poly))
 		pcb_gui->thindraw_pcb_pad(gc, pad, clear, mask);
 	else
diff --git a/src/obj_pinvia.c b/src/obj_pinvia.c
index 4ca890c..7686198 100644
--- a/src/obj_pinvia.c
+++ b/src/obj_pinvia.c
@@ -415,9 +415,9 @@ void *ChangeViaClearSize(pcb_opctx_t *ctx, pcb_pin_t *Via)
 
 	if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Via))
 		return (NULL);
-	value = MIN(PCB_MAX_LINESIZE, value);
 	if (value < 0)
 		value = 0;
+	value = MIN(PCB_MAX_LINESIZE, value);
 	if (ctx->chgsize.delta < 0 && value < PCB->Bloat * 2)
 		value = 0;
 	if ((ctx->chgsize.delta > 0 || ctx->chgsize.absolute) && value < PCB->Bloat * 2)
@@ -470,9 +470,9 @@ void *ChangePinClearSize(pcb_opctx_t *ctx, pcb_element_t *Element, pcb_pin_t *Pi
 
 	if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Pin))
 		return (NULL);
-	value = MIN(PCB_MAX_LINESIZE, value);
 	if (value < 0)
 		value = 0;
+	value = MIN(PCB_MAX_LINESIZE, value);
 	if (ctx->chgsize.delta < 0 && value < PCB->Bloat * 2)
 		value = 0;
 	if ((ctx->chgsize.delta > 0 || ctx->chgsize.absolute) && value < PCB->Bloat * 2)
@@ -851,6 +851,8 @@ static void _draw_pv_name(pcb_pin_t * pv)
 	char buff[128];
 	const char *pn;
 
+	PCB_DRAW_BBOX(pv);
+
 	if (!pv->Name || !pv->Name[0]) {
 		pn = PCB_EMPTY(pv->Number);
 	}
diff --git a/src/obj_pinvia_therm.c b/src/obj_pinvia_therm.c
index da99fcc..1484c75 100644
--- a/src/obj_pinvia_therm.c
+++ b/src/obj_pinvia_therm.c
@@ -210,11 +210,11 @@ static pcb_polyarea_t *square_therm(pcb_pin_t *pin, pcb_cardinal_t style)
 			pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		}
 		else
-			pcb_poly_frac_cicle(c, v[0] + pin->Clearance / 4, v[1], v, 2);
+			pcb_poly_frac_circle(c, v[0] + pin->Clearance / 4, v[1], v, 2);
 		v[1] = pin->Y + in;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		/* pivot 1/4 circle to next point */
-		pcb_poly_frac_cicle(c, pin->X + in, pin->Y + in, v, 4);
+		pcb_poly_frac_circle(c, pin->X + in, pin->Y + in, v, 4);
 		v[0] = pin->X + d;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		if (style == 2) {
@@ -223,7 +223,7 @@ static pcb_polyarea_t *square_therm(pcb_pin_t *pin, pcb_cardinal_t style)
 			pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		}
 		else
-			pcb_poly_frac_cicle(c, v[0], v[1] - pin->Clearance / 4, v, 2);
+			pcb_poly_frac_circle(c, v[0], v[1] - pin->Clearance / 4, v, 2);
 		p = pcb_poly_from_contour(c);
 		/* bottom right */
 		v[0] = pin->X + in;
@@ -239,15 +239,15 @@ static pcb_polyarea_t *square_therm(pcb_pin_t *pin, pcb_cardinal_t style)
 			pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		}
 		else
-			pcb_poly_frac_cicle(c, v[0], v[1] - pin->Clearance / 4, v, 2);
+			pcb_poly_frac_circle(c, v[0], v[1] - pin->Clearance / 4, v, 2);
 		v[0] = pin->X + in;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		/* pivot 1/4 circle to next point */
-		pcb_poly_frac_cicle(c, pin->X + in, pin->Y - in, v, 4);
+		pcb_poly_frac_circle(c, pin->X + in, pin->Y - in, v, 4);
 		v[1] = pin->Y - d;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		if (style == 5)
-			pcb_poly_frac_cicle(c, v[0] - pin->Clearance / 4, v[1], v, 2);
+			pcb_poly_frac_circle(c, v[0] - pin->Clearance / 4, v[1], v, 2);
 		p2 = pcb_poly_from_contour(c);
 		p->f = p2;
 		p2->b = p;
@@ -265,15 +265,15 @@ static pcb_polyarea_t *square_therm(pcb_pin_t *pin, pcb_cardinal_t style)
 			pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		}
 		else
-			pcb_poly_frac_cicle(c, v[0] - pin->Clearance / 4, v[1], v, 2);
+			pcb_poly_frac_circle(c, v[0] - pin->Clearance / 4, v[1], v, 2);
 		v[1] = pin->Y - in;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		/* pivot 1/4 circle to next point */
-		pcb_poly_frac_cicle(c, pin->X - in, pin->Y - in, v, 4);
+		pcb_poly_frac_circle(c, pin->X - in, pin->Y - in, v, 4);
 		v[0] = pin->X - d;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		if (style == 5)
-			pcb_poly_frac_cicle(c, v[0], v[1] + pin->Clearance / 4, v, 2);
+			pcb_poly_frac_circle(c, v[0], v[1] + pin->Clearance / 4, v, 2);
 		p2 = pcb_poly_from_contour(c);
 		p->f->f = p2;
 		p2->b = p->f;
@@ -285,7 +285,7 @@ static pcb_polyarea_t *square_therm(pcb_pin_t *pin, pcb_cardinal_t style)
 		v[0] = pin->X - in;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		/* pivot 1/4 circle to next point (x-out, y+in) */
-		pcb_poly_frac_cicle(c, pin->X - in, pin->Y + in, v, 4);
+		pcb_poly_frac_circle(c, pin->X - in, pin->Y + in, v, 4);
 		v[1] = pin->Y + d;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		if (style == 2) {
@@ -293,13 +293,13 @@ static pcb_polyarea_t *square_therm(pcb_pin_t *pin, pcb_cardinal_t style)
 			pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		}
 		else
-			pcb_poly_frac_cicle(c, v[0] + pin->Clearance / 4, v[1], v, 2);
+			pcb_poly_frac_circle(c, v[0] + pin->Clearance / 4, v[1], v, 2);
 		v[1] = pin->Y + in;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		v[0] = pin->X - d;
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 		if (style == 5)
-			pcb_poly_frac_cicle(c, v[0], v[1] + pin->Clearance / 4, v, 2);
+			pcb_poly_frac_circle(c, v[0], v[1] + pin->Clearance / 4, v, 2);
 		p2 = pcb_poly_from_contour(c);
 		p->f->f->f = p2;
 		p2->f = p;
diff --git a/src/obj_poly.h b/src/obj_poly.h
index 3402e16..82e7b56 100644
--- a/src/obj_poly.h
+++ b/src/obj_poly.h
@@ -89,29 +89,30 @@ double pcb_poly_area(const pcb_polygon_t *poly);
 #define	PCB_POLY_ALL_LOOP(top)	do {		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l = 0; l < pcb_max_copper_layer + 2; l++, layer++)	\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
 		PCB_POLY_LOOP(layer)
 
 #define	PCB_POLY_COPPER_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l = 0; l < pcb_max_copper_layer; l++, layer++)	\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
+		if (!(pcb_layer_flags(l) & PCB_LYT_COPPER)) continue; \
 		PCB_POLY_LOOP(layer)
 
 #define	PCB_POLY_SILK_LOOP(top) do	{		\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	layer += pcb_max_copper_layer;			\
-	for (l = 0; l < 2; l++, layer++)		\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
+		if (!(pcb_layer_flags(l) & PCB_LYT_SILK)) continue; \
 		PCB_POLY_LOOP(layer)
 
 #define	PCB_POLY_VISIBLE_LOOP(top) do	{	\
 	pcb_cardinal_t		l;			\
 	pcb_layer_t *layer = (top)->Layer;		\
-	for (l = 0; l < pcb_max_copper_layer + 2; l++, layer++)	\
+	for (l = 0; l < pcb_max_layer; l++, layer++)	\
 	{ \
 		if (layer->On)				\
 			PCB_POLY_LOOP(layer)
diff --git a/src/obj_text.c b/src/obj_text.c
index f618905..443de97 100644
--- a/src/obj_text.c
+++ b/src/obj_text.c
@@ -361,8 +361,8 @@ void *MoveTextToLayerLowLevel(pcb_opctx_t *ctx, pcb_layer_t * Source, pcb_text_t
 	textlist_remove(text);
 	textlist_append(&Destination->Text, text);
 
-	if (pcb_layer_get_group(pcb_solder_silk_layer) == pcb_layer_get_group_(Destination))
-		PCB_FLAG_SET(PCB_FLAG_ONSOLDER, text);
+	if (pcb_layer_flags(pcb_layer_id(PCB->Data, Destination)) & PCB_LYT_BOTTOM)
+		PCB_FLAG_SET(PCB_FLAG_ONSOLDER, text); /* get the text mirrored on display */
 	else
 		PCB_FLAG_CLEAR(PCB_FLAG_ONSOLDER, text);
 
@@ -556,12 +556,17 @@ pcb_r_dir_t draw_text_callback(const pcb_box_t * b, void *cl)
 	pcb_layer_t *layer = cl;
 	pcb_text_t *text = (pcb_text_t *) b;
 	int min_silk_line;
+	unsigned int flg = 0;
 
 	if (PCB_FLAG_TEST(PCB_FLAG_SELECTED, text))
 		pcb_gui->set_color(Output.fgGC, layer->SelectedColor);
 	else
 		pcb_gui->set_color(Output.fgGC, layer->Color);
-	if (layer == &PCB->Data->SILKLAYER || layer == &PCB->Data->BACKSILKLAYER)
+
+	if (layer->grp >= 0)
+		flg = pcb_layergrp_flags(layer->grp);
+
+	if (flg & PCB_LYT_SILK)
 		min_silk_line = PCB->minSlk;
 	else
 		min_silk_line = PCB->minWid;
diff --git a/src/obj_text.h b/src/obj_text.h
index d5c55ba..3c0e6f4 100644
--- a/src/obj_text.h
+++ b/src/obj_text.h
@@ -75,14 +75,14 @@ void pcb_text_flip_side(pcb_layer_t *layer, pcb_text_t *text);
 #define	PCB_TEXT_ALL_LOOP(top) do {                        \
 	pcb_cardinal_t l;                                   \
 	pcb_layer_t *layer = (top)->Layer;                  \
-	for (l = 0; l < pcb_max_copper_layer + 2; l++, layer++) \
+	for (l = 0; l < pcb_max_layer; l++, layer++) \
 	{                                                   \
 		PCB_TEXT_LOOP(layer)
 
 #define PCB_TEXT_VISIBLE_LOOP(board) do {                       \
 	pcb_cardinal_t l;                                        \
 	pcb_layer_t *layer = (board)->Data->Layer;               \
-	for (l = 0; l < pcb_max_copper_layer + 2; l++, layer++)      \
+	for (l = 0; l < pcb_max_layer; l++, layer++)      \
 	{                                                        \
 		PCB_TEXT_LOOP(layer);                                      \
 		if (pcb_text_is_visible((board), layer, text))
diff --git a/src/object_act.c b/src/object_act.c
index 870f9be..08582f2 100644
--- a/src/object_act.c
+++ b/src/object_act.c
@@ -127,7 +127,7 @@ static int pcb_act_Attributes(int argc, const char **argv, pcb_coord_t x, pcb_co
 			if (layername) {
 				int i;
 				layer = NULL;
-				for (i = 0; i < pcb_max_copper_layer; i++)
+				for (i = 0; i < pcb_max_layer; i++)
 					if (strcmp(PCB->Data->Layer[i].Name, layername) == 0) {
 						layer = &(PCB->Data->Layer[i]);
 						break;
@@ -1042,7 +1042,6 @@ Creates a new layer.
 @end table
 
 %end-doc */
-
 int pcb_act_MoveLayer(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
 	int old_index, new_index;
@@ -1071,7 +1070,7 @@ int pcb_act_MoveLayer(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 	}
 	else if (strcmp(argv[1], "down") == 0) {
 		new_index = INDEXOFCURRENT + 1;
-		if (new_index >= pcb_max_copper_layer)
+		if (new_index >= pcb_max_layer)
 			return 1;
 		new_top = new_index;
 	}
@@ -1083,7 +1082,7 @@ int pcb_act_MoveLayer(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 
 	if (new_index == -1) {
 		new_top = old_index;
-		if (new_top >= pcb_max_copper_layer)
+		if (new_top >= pcb_max_layer)
 			new_top--;
 		new_index = new_top;
 	}
diff --git a/src/pcb-menu-gtk.lht b/src/pcb-menu-gtk.lht
index 8b365a4..2fd8bec 100644
--- a/src/pcb-menu-gtk.lht
+++ b/src/pcb-menu-gtk.lht
@@ -44,17 +44,29 @@ ha:{
 		ha:File {
 			m=F
 			li:submenu {
-				ha:Save Layout                       = { m=S; a={Ctrl<Key>s};        action=Save(Layout); tip=Saves current layout }
-				ha:Save Layout As...                 = { m=A; a={Shift Ctrl<Key>s};  action=Save(LayoutAs); tip=Saves current layout into a new file }
-				-
+				ha:Start New Layout                  = { a=Ctrl<Key>n; action=New() }
 				ha:Revert                            = {                             action=Load(Revert,none); tip=Revert to the layout stored on disk }
 				-
-				ha:Import Schematics                 = {                             action=Import() }
 				ha:Load layout                       = {                             action=Load(Layout); tip=Load a layout from a file }
-				ha:Load element data to paste-buffer = {                             li:action={PasteBuffer(Clear); Load(ElementTobuffer)} }
-				ha:Load layout data to paste-buffer  = {                             li:action={PasteBuffer(Clear); Load(LayoutTobuffer)} }
-				ha:Load netlist file                 = {                             action=Load(Netlist) }
-				ha:Load vendor resource file         = {                             action=LoadVendorFrom() }
+				-
+				ha:Save Layout                       = { m=S; a={Ctrl<Key>s};        action=Save(Layout); tip=Saves current layout }
+				ha:Save Layout As...                 = { m=A; a={Shift Ctrl<Key>s};  action=Save(LayoutAs); tip=Saves current layout into a new file }
+				-
+				ha:Import {
+					m=I
+					li:submenu {
+						ha:Import Schematics                 = {                             action=Import() }
+						ha:Load element data to paste-buffer = {                             li:action={PasteBuffer(Clear); Load(ElementTobuffer)} }
+						ha:Load layout data to paste-buffer  = {                             li:action={PasteBuffer(Clear); Load(LayoutTobuffer)} }
+						ha:Load netlist file                 = {                             action=Load(Netlist) }
+						ha:Load vendor resource file         = {                             action=LoadVendorFrom() }
+						ha:Load routed dsn or ses file       = {                             action=LoadDsnFrom() }
+						ha:Load MUCS pl file                 = {                             action=LoadMucsFrom() }
+						ha:Load TinyCAD .net file            = {                             action=LoadTinyCADFrom() }
+						ha:Load LTSpice .net and .asc files  = {                             action=LoadLTSpiceFrom() }
+						ha:Load hyp                          = {                             action=LoadHypFrom() }
+					}
+				}
 				-
 				ha:Save connection data of {
 					li:submenu {
@@ -64,9 +76,10 @@ ha:{
 						ha:netlist patch for back annotation = {a=Alt Ctrl<Key>b; action=SavePatch() }
 					}
 				}
-				-
 				ha:Print layout...      = {               action=Print()}
 				ha:Export layout...     = {               action=ExportGUI()}
+				-
+				ha:Preferences...       = {               action=DoWindows(Preferences)}
 				ha:Maintenance {
 					li:submenu {
 						ha:Calibrate Printer...           = { action=PrintCalibrate() }
@@ -74,10 +87,6 @@ ha:{
 					}
 				}
 				-
-				ha:Start New Layout     = { a=Ctrl<Key>n; action=New() }
-				-
-				ha:Preferences...       = {               action=DoWindows(Preferences)}
-				-
 				ha:Quit Program         = { a=Ctrl<Key>q; action=Quit() }
 			}
 		}
diff --git a/src/pcb-menu-lesstif.lht b/src/pcb-menu-lesstif.lht
index 329d617..9046295 100644
--- a/src/pcb-menu-lesstif.lht
+++ b/src/pcb-menu-lesstif.lht
@@ -36,12 +36,21 @@ ha:{
 				ha:Save layout = { m=S; a=Ctrl<Key>s; action=Save(Layout) }
 				ha:Save layout as... = { m=A; a=Shift Ctrl<Key>s; action=Save(LayoutAs) }
 				ha:Revert = { action=Load(Revert,none) }
-				ha:Import Schematics = { action=Import() }
 				ha:Load layout = { action=Load(Layout) }
-				ha:Load element data to paste-buffer = { li:action={PasteBuffer(Clear); Load(ElementTobuffer)} }
-				ha:Load layout data to paste-buffer = { li:action={PasteBuffer(Clear); Load(LayoutTobuffer)} }
-				ha:Load netlist file = { action=Load(Netlist) }
-				ha:Load vendor resource file = { action=LoadVendor() }
+				ha:Import = {
+					li:submenu {
+						ha:Import Schematics                 = { action=Import() }
+						ha:Load element data to paste-buffer = { li:action={PasteBuffer(Clear); Load(ElementTobuffer)} }
+						ha:Load layout data to paste-buffer  = { li:action={PasteBuffer(Clear); Load(LayoutTobuffer)} }
+						ha:Load netlist file                 = { action=Load(Netlist) }
+						ha:Load vendor resource file         = { action=LoadVendor() }
+						ha:Load routed dsn or ses file       = { action=LoadDsnFrom() }
+						ha:Load MUCS pl file                 = { action=LoadMucsFrom() }
+						ha:Load TinyCAD .net file            = { action=LoadTinyCADFrom() }
+						ha:Load LTSpice .net and .asc files  = { action=LoadLTSpiceFrom() }
+						ha:Load hyp                          = { action=LoadHypFrom() }
+					}
+				}
 				ha:Print layout... = { action=Print() }
 				ha:Export layout... = { action=ExportGUI() }
 				ha:Maintenance {
@@ -69,7 +78,7 @@ ha:{
 				ha:Spin 180� = { a=Ctrl<Key>Tab; action=SwapSides(R) }
 				ha:Swap Sides = { a=Ctrl Shift<Key>Tab; action=SwapSides() }
 				ha:Center cursor = { a=<Key>c; action=Center() }
-				ha:Show soldermask = { checked=showmask; action=Display(ToggleMask) }
+				ha:Show soldermask = { checked=editor/show_mask; action=Display(ToggleMask) }
 				-
 				ha:Displayed element-name... = { foreground=grey50; sensitive=false }
 				ha:Description = { checked=ChkElementName(1); action=Display(Description) }
diff --git a/src/pcb-menu-mkey.lht b/src/pcb-menu-mkey.lht
index be3a48b..ca14e2c 100644
--- a/src/pcb-menu-mkey.lht
+++ b/src/pcb-menu-mkey.lht
@@ -44,17 +44,29 @@ ha:{
 		ha:File {
 			m=F
 			li:submenu {
-				ha:Save Layout                       = { m=S; li:a={{<key>f;<key>s}; {Ctrl<Key>s};};        action=Save(Layout); tip=Saves current layout }
-				ha:Save Layout As...                 = { m=A; li:a={{<key>f;<key>a}; {Shift Ctrl<Key>s};};  action=Save(LayoutAs); tip=Saves current layout into a new file }
-				-
+				ha:Start New Layout     = { li:a={{<key>f;<key>n}; {Ctrl<Key>n};}; action=New() }
 				ha:Revert                            = { a={<key>f;<key>r};          action=Load(Revert,none); tip=Revert to the layout stored on disk }
 				-
-				ha:Import Schematics                 = {                             action=Import() }
 				ha:Load layout                       = { a={<key>f;<key>o};          action=Load(Layout); tip=Load a layout from a file }
-				ha:Load element data to paste-buffer = {                             li:action={PasteBuffer(Clear); Load(ElementTobuffer)} }
-				ha:Load layout data to paste-buffer  = {                             li:action={PasteBuffer(Clear); Load(LayoutTobuffer)} }
-				ha:Load netlist file                 = {                             action=Load(Netlist) }
-				ha:Load vendor resource file         = {                             action=LoadVendorFrom() }
+				-
+				ha:Save Layout                       = { m=S; li:a={{<key>f;<key>s}; {Ctrl<Key>s};};        action=Save(Layout); tip=Saves current layout }
+				ha:Save Layout As...                 = { m=A; li:a={{<key>f;<key>a}; {Shift Ctrl<Key>s};};  action=Save(LayoutAs); tip=Saves current layout into a new file }
+				-
+				ha:Import {
+					m=I
+					li:submenu {
+						ha:Import Schematics                 = {                             action=Import() }
+						ha:Load element data to paste-buffer = {                             li:action={PasteBuffer(Clear); Load(ElementTobuffer)} }
+						ha:Load layout data to paste-buffer  = {                             li:action={PasteBuffer(Clear); Load(LayoutTobuffer)} }
+						ha:Load netlist file                 = {                             action=Load(Netlist) }
+						ha:Load vendor resource file         = {                             action=LoadVendorFrom() }
+						ha:Load routed dsn or ses file       = {                             action=LoadDsnFrom() }
+						ha:Load MUCS pl file                 = {                             action=LoadMucsFrom() }
+						ha:Load TinyCAD .net file            = {                             action=LoadTinyCADFrom() }
+						ha:Load LTSpice .net and .asc files  = {                             action=LoadLTSpiceFrom() }
+						ha:Load hyp                          = {                             action=LoadHypFrom() }
+					}
+				}
 				-
 				ha:Save connection data of {
 					li:submenu {
@@ -64,9 +76,10 @@ ha:{
 						ha:netlist patch for back annotation = {a=Alt Ctrl<Key>b; action=SavePatch() }
 					}
 				}
-				-
 				ha:Print layout...      = { a={<key>f;<key>p}; action=Print()}
 				ha:Export layout...     = { a={<key>f;<key>i}; action=ExportGUI()}
+				-
+				ha:Preferences...       = {               action=DoWindows(Preferences)}
 				ha:Maintenance {
 					li:submenu {
 						ha:Calibrate Printer...           = { action=PrintCalibrate() }
@@ -74,10 +87,6 @@ ha:{
 					}
 				}
 				-
-				ha:Start New Layout     = { li:a={{<key>f;<key>n}; {Ctrl<Key>n};}; action=New() }
-				-
-				ha:Preferences...       = {               action=DoWindows(Preferences)}
-				-
 				ha:Quit Program         = { li:a={{<key>f;<key>c}; {Ctrl<Key>q};}; action=Quit() }
 			}
 		}
diff --git a/src/plug_footprint.c b/src/plug_footprint.c
index 88b77c8..19026fe 100644
--- a/src/plug_footprint.c
+++ b/src/plug_footprint.c
@@ -111,7 +111,7 @@ FILE *pcb_fp_fopen(const char *path, const char *name, pcb_fp_fopen_ctx_t *fctx)
 
 void pcb_fp_fclose(FILE * f, pcb_fp_fopen_ctx_t *fctx)
 {
-	if (fctx->backend->fclose != NULL)
+	if ((fctx->backend != NULL) && (fctx->backend->fclose != NULL))
 		fctx->backend->fclose(fctx->backend, f, fctx);
 }
 
diff --git a/src/plug_io.c b/src/plug_io.c
index 10567b6..99c4b22 100644
--- a/src/plug_io.c
+++ b/src/plug_io.c
@@ -443,7 +443,8 @@ static int real_load_pcb(const char *Filename, const char *fmt, pcb_bool revert,
 		}
 	}
 
-	pcb_board_changed(0);
+	if (!(how & PCB_INHIBIT_BOARD_CHANGED))
+		pcb_board_changed(0);
 
 	/* release unused memory */
 	pcb_board_remove(newPCB);
diff --git a/src/plug_io.h b/src/plug_io.h
index 3f3fa87..f32cc4f 100644
--- a/src/plug_io.h
+++ b/src/plug_io.h
@@ -112,7 +112,8 @@ int pcb_write_element_data(FILE *f, pcb_data_t *e, const char *fmt);
 FILE *pcb_check_and_open_file(const char *, pcb_bool, pcb_bool, pcb_bool *, pcb_bool *);
 FILE *pcb_open_connection_file(void);
 int pcb_save_pcb(const char *, const char *fmt);
-int pcb_load_pcb(const char *name, const char *fmt, pcb_bool, int how); /* how: 0=normal pcb; 1=default.pcb, 2=misc (do not load settings) | 0x10: ignore missing file */
+#define PCB_INHIBIT_BOARD_CHANGED 0x20
+int pcb_load_pcb(const char *name, const char *fmt, pcb_bool, int how); /* how: 0=normal pcb; 1=default.pcb, 2=misc (do not load settings) | 0x10: ignore missing file, | PCB_INHIBIT_BOARD_CHANGED: do not send a board changed event */
 void pcb_enable_autosave(void);
 void pcb_backup(void);
 void pcb_save_in_tmp(void);
diff --git a/src/polygon.c b/src/polygon.c
index 8f2b756..4169a94 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -390,19 +390,16 @@ pcb_polyarea_t *pcb_poly_from_octagon(pcb_coord_t x, pcb_coord_t y, pcb_coord_t
 	return pcb_poly_from_contour(contour);
 }
 
-/* add vertices in a fractional-circle starting from v
- * centered at X, Y and going counter-clockwise
- * does not include the first point
- * last argument is 1 for a full circle
- * 2 for a half circle
- * or 4 for a quarter circle
- */
-void pcb_poly_frac_cicle(pcb_pline_t * c, pcb_coord_t X, pcb_coord_t Y, pcb_vector_t v, int range)
+static void pcb_poly_frac_circle_(pcb_pline_t * c, pcb_coord_t X, pcb_coord_t Y, pcb_vector_t v, int range, int add_last)
 {
-	double e1, e2, t1;
-	int i;
+	double oe1, oe2, e1, e2, t1;
+	int i, orange = range;
+
+	oe1 = (v[0] - X);
+	oe2 = (v[1] - Y);
 
 	pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
+
 	/* move vector to origin */
 	e1 = (v[0] - X) * PCB_POLY_CIRC_RADIUS_ADJ;
 	e2 = (v[1] - Y) * PCB_POLY_CIRC_RADIUS_ADJ;
@@ -418,8 +415,34 @@ void pcb_poly_frac_cicle(pcb_pline_t * c, pcb_coord_t X, pcb_coord_t Y, pcb_vect
 		v[1] = Y + ROUND(e2);
 		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
 	}
+
+	if ((add_last) && (orange == 4)) {
+		v[0] = X - ROUND(oe2);
+		v[1] = Y + ROUND(oe1);
+		pcb_poly_vertex_include(c->head.prev, pcb_poly_node_create(v));
+	}
+}
+
+
+/* add vertices in a fractional-circle starting from v
+ * centered at X, Y and going counter-clockwise
+ * does not include the first point
+ * last argument is 1 for a full circle
+ * 2 for a half circle
+ * or 4 for a quarter circle
+ */
+void pcb_poly_frac_circle(pcb_pline_t * c, pcb_coord_t X, pcb_coord_t Y, pcb_vector_t v, int range)
+{
+	pcb_poly_frac_circle_(c, X, Y, v, range, 0);
 }
 
+/* same but adds the last vertex */
+void pcb_poly_frac_circle_end(pcb_pline_t * c, pcb_coord_t X, pcb_coord_t Y, pcb_vector_t v, int range)
+{
+	pcb_poly_frac_circle_(c, X, Y, v, range, 1);
+}
+
+
 /* create a circle approximation from lines */
 pcb_polyarea_t *pcb_poly_from_circle(pcb_coord_t x, pcb_coord_t y, pcb_coord_t radius)
 {
@@ -432,7 +455,7 @@ pcb_polyarea_t *pcb_poly_from_circle(pcb_coord_t x, pcb_coord_t y, pcb_coord_t r
 	v[1] = y;
 	if ((contour = pcb_poly_contour_new(v)) == NULL)
 		return NULL;
-	pcb_poly_frac_cicle(contour, x, y, v, 1);
+	pcb_poly_frac_circle(contour, x, y, v, 1);
 	contour->is_round = pcb_true;
 	contour->cx = x;
 	contour->cy = y;
@@ -452,19 +475,19 @@ pcb_polyarea_t *RoundRect(pcb_coord_t x1, pcb_coord_t x2, pcb_coord_t y1, pcb_co
 	v[1] = y1;
 	if ((contour = pcb_poly_contour_new(v)) == NULL)
 		return NULL;
-	pcb_poly_frac_cicle(contour, x1, y1, v, 4);
+	pcb_poly_frac_circle_end(contour, x1, y1, v, 4);
 	v[0] = x2;
 	v[1] = y1 - t;
 	pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
-	pcb_poly_frac_cicle(contour, x2, y1, v, 4);
+	pcb_poly_frac_circle_end(contour, x2, y1, v, 4);
 	v[0] = x2 + t;
 	v[1] = y2;
 	pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
-	pcb_poly_frac_cicle(contour, x2, y2, v, 4);
+	pcb_poly_frac_circle_end(contour, x2, y2, v, 4);
 	v[0] = x1;
 	v[1] = y2 + t;
 	pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
-	pcb_poly_frac_cicle(contour, x1, y2, v, 4);
+	pcb_poly_frac_circle_end(contour, x1, y2, v, 4);
 	return pcb_poly_from_contour(contour);
 }
 
@@ -518,7 +541,7 @@ static pcb_polyarea_t *ArcPolyNoIntersect(pcb_arc_t * a, pcb_coord_t thick)
 	v[0] = a->X - rx * cos(ang * PCB_M180) * (1 - radius_adj);
 	v[1] = a->Y + ry * sin(ang * PCB_M180) * (1 - radius_adj);
 	/* add the round cap at the end */
-	pcb_poly_frac_cicle(contour, ends.X2, ends.Y2, v, 2);
+	pcb_poly_frac_circle(contour, ends.X2, ends.Y2, v, 2);
 	/* and now do the outer arc (going backwards) */
 	rx = (a->Width + half) * (1 + radius_adj);
 	ry = (a->Width + half) * (1 + radius_adj);
@@ -533,7 +556,7 @@ static pcb_polyarea_t *ArcPolyNoIntersect(pcb_arc_t * a, pcb_coord_t thick)
 	ang = a->StartAngle;
 	v[0] = a->X - rx * cos(ang * PCB_M180) * (1 - radius_adj);
 	v[1] = a->Y + ry * sin(ang * PCB_M180) * (1 - radius_adj);
-	pcb_poly_frac_cicle(contour, ends.X1, ends.Y1, v, 2);
+	pcb_poly_frac_circle(contour, ends.X1, ends.Y1, v, 2);
 	/* now we have the whole contour */
 	if (!(np = pcb_poly_from_contour(contour)))
 		return NULL;
@@ -609,7 +632,7 @@ pcb_polyarea_t *pcb_poly_from_line(pcb_line_t * L, pcb_coord_t thick)
 	if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, l))
 		pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
 	else
-		pcb_poly_frac_cicle(contour, l->Point2.X, l->Point2.Y, v, 2);
+		pcb_poly_frac_circle(contour, l->Point2.X, l->Point2.Y, v, 2);
 	v[0] = l->Point2.X + dx;
 	v[1] = l->Point2.Y + dy;
 	pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
@@ -618,7 +641,7 @@ pcb_polyarea_t *pcb_poly_from_line(pcb_line_t * L, pcb_coord_t thick)
 	if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, l))
 		pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
 	else
-		pcb_poly_frac_cicle(contour, l->Point1.X, l->Point1.Y, v, 2);
+		pcb_poly_frac_circle(contour, l->Point1.X, l->Point1.Y, v, 2);
 	/* now we have the line contour */
 	if (!(np = pcb_poly_from_contour(contour)))
 		return NULL;
@@ -673,22 +696,22 @@ pcb_polyarea_t *SquarePadPoly(pcb_pad_t * pad, pcb_coord_t clear)
 	v[1] = c->Point1.Y - ty;
 	if ((contour = pcb_poly_contour_new(v)) == NULL)
 		return 0;
-	pcb_poly_frac_cicle(contour, (t->Point1.X - tx), (t->Point1.Y - ty), v, 4);
+	pcb_poly_frac_circle_end(contour, (t->Point1.X - tx), (t->Point1.Y - ty), v, 4);
 
 	v[0] = t->Point2.X - cx;
 	v[1] = t->Point2.Y - cy;
 	pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
-	pcb_poly_frac_cicle(contour, (t->Point2.X - tx), (t->Point2.Y - ty), v, 4);
+	pcb_poly_frac_circle_end(contour, (t->Point2.X - tx), (t->Point2.Y - ty), v, 4);
 
 	v[0] = c->Point2.X + tx;
 	v[1] = c->Point2.Y + ty;
 	pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
-	pcb_poly_frac_cicle(contour, (t->Point2.X + tx), (t->Point2.Y + ty), v, 4);
+	pcb_poly_frac_circle_end(contour, (t->Point2.X + tx), (t->Point2.Y + ty), v, 4);
 
 	v[0] = t->Point1.X + cx;
 	v[1] = t->Point1.Y + cy;
 	pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v));
-	pcb_poly_frac_cicle(contour, (t->Point1.X + tx), (t->Point1.Y + ty), v, 4);
+	pcb_poly_frac_circle_end(contour, (t->Point1.X + tx), (t->Point1.Y + ty), v, 4);
 
 	/* now we have the line contour */
 	if (!(np = pcb_poly_from_contour(contour)))
@@ -729,7 +752,7 @@ static int Subtract(pcb_polyarea_t * np1, pcb_polygon_t * p, pcb_bool fnp)
 	p->Clipped = biggest(merged);
 	assert(!p->Clipped || pcb_poly_valid(p->Clipped));
 	if (!p->Clipped)
-		pcb_message(PCB_MSG_WARNING, "Polygon cleared out of existence near (%d, %d)\n",
+		pcb_message(PCB_MSG_WARNING, "Polygon cleared out of existence near (%$mm, %$mm)\n",
 						(p->BoundingBox.X1 + p->BoundingBox.X2) / 2, (p->BoundingBox.Y1 + p->BoundingBox.Y2) / 2);
 	return 1;
 }
@@ -994,8 +1017,8 @@ static int Group(pcb_data_t *Data, pcb_layer_id_t layer)
 {
 	pcb_cardinal_t i, j;
 	for (i = 0; i < pcb_max_group; i++)
-		for (j = 0; j < ((pcb_board_t *) (Data->pcb))->LayerGroups.Number[i]; j++)
-			if (layer == ((pcb_board_t *) (Data->pcb))->LayerGroups.Entries[i][j])
+		for (j = 0; j < ((pcb_board_t *) (Data->pcb))->LayerGroups.grp[i].len; j++)
+			if (layer == ((pcb_board_t *) (Data->pcb))->LayerGroups.grp[i].lid[j])
 				return i;
 	return i;
 }
@@ -1005,13 +1028,20 @@ static int clearPoly(pcb_data_t *Data, pcb_layer_t *Layer, pcb_polygon_t * polyg
 	int r = 0, seen;
 	pcb_box_t region;
 	struct cpInfo info;
-	pcb_cardinal_t group;
+	pcb_layergrp_id_t group;
+	unsigned int gflg;
 
-	if (!PCB_FLAG_TEST(PCB_FLAG_CLEARPOLY, polygon)
-			|| pcb_layer_id(Data, Layer) >= pcb_max_copper_layer)
+	if (!(pcb_layer_flags(pcb_layer_id(Data, Layer)) & PCB_LYT_COPPER)) {
+		polygon->NoHolesValid = 0;
 		return 0;
+	}
+
+	if (!PCB_FLAG_TEST(PCB_FLAG_CLEARPOLY, polygon))
+		return 0;
+
 	group = Group(Data, pcb_layer_id(Data, Layer));
-	info.solder = (group == Group(Data, pcb_solder_silk_layer));
+	gflg = pcb_layergrp_flags(group);
+	info.solder = (gflg & PCB_LYT_BOTTOM);
 	info.data = Data;
 	info.other = here;
 	info.layer = Layer;
@@ -1023,14 +1053,15 @@ static int clearPoly(pcb_data_t *Data, pcb_layer_t *Layer, pcb_polygon_t * polyg
 	region = pcb_bloat_box(&region, expand);
 
 	if (setjmp(info.env) == 0) {
+
 		r = 0;
 		info.accumulate = NULL;
 		info.batch_size = 0;
-		if (info.solder || group == Group(Data, pcb_component_silk_layer)) {
+		if (info.solder || (gflg & PCB_LYT_TOP)) {
 			pcb_r_search(Data->pad_tree, &region, NULL, pad_sub_callback, &info, &seen);
 			r += seen;
 		}
-		GROUP_LOOP(Data, group);
+		PCB_COPPER_GROUP_LOOP(Data, group);
 		{
 			pcb_r_search(layer->line_tree, &region, NULL, line_sub_callback, &info, &seen);
 			r += seen;
@@ -1057,7 +1088,7 @@ static int Unsubtract(pcb_polyarea_t * np1, pcb_polygon_t * p)
 	pcb_polyarea_t *orig_poly, *clipped_np;
 	int x;
 	assert(np);
-	assert(p && p->Clipped);
+	assert(p); /* NOTE: p->clipped might be NULL if a poly is "cleared out of existence" and is now coming back */
 
 	orig_poly = original_poly(p);
 
@@ -1329,6 +1360,12 @@ void pcb_polygon_close_poly(void)
 		pcb_message(PCB_MSG_ERROR, _("A polygon has to have at least 3 points\n"));
 }
 
+static void poly_copy_data(pcb_polygon_t *dst, pcb_polygon_t *src)
+{
+	pcb_polygon_t p;
+	memcpy(dst, src, ((char *)&p.link - (char *)&p));
+}
+
 /* ---------------------------------------------------------------------------
  * moves the data of the attached (new) polygon to the current layer
  */
@@ -1340,16 +1377,15 @@ void pcb_polygon_copy_attached_to_layer(void)
 	/* move data to layer and clear attached struct */
 	polygon = pcb_poly_new(CURRENT, pcb_no_flags());
 	saveID = polygon->ID;
-	*polygon = pcb_crosshair.AttachedPolygon;
+	poly_copy_data(polygon, &pcb_crosshair.AttachedPolygon);
 	polygon->ID = saveID;
 	PCB_FLAG_SET(PCB_FLAG_CLEARPOLY, polygon);
 	if (conf_core.editor.full_poly)
 		PCB_FLAG_SET(PCB_FLAG_FULLPOLY, polygon);
 	memset(&pcb_crosshair.AttachedPolygon, 0, sizeof(pcb_polygon_t));
-	pcb_poly_bbox(polygon);
-	if (!CURRENT->polygon_tree)
-		CURRENT->polygon_tree = pcb_r_create_tree(NULL, 0, 0);
-	pcb_r_insert_entry(CURRENT->polygon_tree, (pcb_box_t *) polygon, 0);
+
+	pcb_add_polygon_on_layer(CURRENT, polygon);
+
 	pcb_poly_init_clip(PCB->Data, CURRENT, polygon);
 	DrawPolygon(CURRENT, polygon);
 	pcb_board_set_changed_flag(pcb_true);
@@ -1475,8 +1511,10 @@ pcb_poly_plows(pcb_data_t * Data, int type, void *ptr1, void *ptr2,
 	case PCB_TYPE_PIN:
 	case PCB_TYPE_VIA:
 		if (type == PCB_TYPE_PIN || ptr1 == ptr2 || ptr1 == NULL) {
-			LAYER_LOOP(Data, pcb_max_copper_layer);
+			LAYER_LOOP(Data, pcb_max_layer);
 			{
+				if (!(pcb_layer_flags(pcb_layer_id(Data, layer)) & PCB_LYT_COPPER))
+					continue;
 				info.layer = layer;
 				pcb_r_search(layer->polygon_tree, &sb, NULL, plow_callback, &info, &seen);
 				r += seen;
@@ -1484,7 +1522,7 @@ pcb_poly_plows(pcb_data_t * Data, int type, void *ptr1, void *ptr2,
 			PCB_END_LOOP;
 		}
 		else {
-			GROUP_LOOP(Data, pcb_layer_get_group(pcb_layer_id(Data, ((pcb_layer_t *) ptr1))));
+			PCB_COPPER_GROUP_LOOP(Data, pcb_layer_get_group(pcb_layer_id(Data, ((pcb_layer_t *) ptr1))));
 			{
 				info.layer = layer;
 				pcb_r_search(layer->polygon_tree, &sb, NULL, plow_callback, &info, &seen);
@@ -1499,10 +1537,10 @@ pcb_poly_plows(pcb_data_t * Data, int type, void *ptr1, void *ptr2,
 		/* the cast works equally well for lines and arcs */
 		if (!PCB_FLAG_TEST(PCB_FLAG_CLEARLINE, (pcb_line_t *) ptr2))
 			return 0;
-		/* silk doesn't plow */
-		if (pcb_layer_id(Data, (pcb_layer_t *) ptr1) >= pcb_max_copper_layer)
+		/* non-copper (e.g. silk, outline) doesn't plow */
+		if (!(pcb_layer_flags(pcb_layer_id(Data, (pcb_layer_t *) ptr1) & PCB_LYT_COPPER)))
 			return 0;
-		GROUP_LOOP(Data, pcb_layer_get_group(pcb_layer_id(Data, ((pcb_layer_t *) ptr1))));
+		PCB_COPPER_GROUP_LOOP(Data, pcb_layer_get_group(pcb_layer_id(Data, ((pcb_layer_t *) ptr1))));
 		{
 			info.layer = layer;
 			pcb_r_search(layer->polygon_tree, &sb, NULL, plow_callback, &info, &seen);
@@ -1512,9 +1550,13 @@ pcb_poly_plows(pcb_data_t * Data, int type, void *ptr1, void *ptr2,
 		break;
 	case PCB_TYPE_PAD:
 		{
-			pcb_layergrp_id_t group = pcb_layer_get_group(PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, (pcb_pad_t *) ptr2) ?
-																									 pcb_solder_silk_layer : pcb_component_silk_layer);
-			GROUP_LOOP(Data, group);
+			pcb_layergrp_id_t SLayer, CLayer, group;
+	
+			SLayer = CLayer = -1;
+			pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &SLayer, 1);
+			pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &CLayer, 1);
+			group = PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, (pcb_pad_t *) ptr2) ? SLayer : CLayer;
+			PCB_COPPER_GROUP_LOOP(Data, group);
 			{
 				info.layer = layer;
 				pcb_r_search(layer->polygon_tree, &sb, NULL, plow_callback, &info, &seen);
diff --git a/src/polygon.h b/src/polygon.h
index e6b1906..3c61032 100644
--- a/src/polygon.h
+++ b/src/polygon.h
@@ -77,7 +77,7 @@ pcb_polyarea_t *pcb_poly_from_arc(pcb_arc_t * l, pcb_coord_t thick);
 pcb_polyarea_t *pcb_poly_from_pin(pcb_pin_t * l, pcb_coord_t thick, pcb_coord_t clear);
 pcb_polyarea_t *pcb_poly_from_box_bloated(pcb_box_t * box, pcb_coord_t radius);
 
-void pcb_poly_frac_cicle(pcb_pline_t *, pcb_coord_t, pcb_coord_t, pcb_vector_t, int);
+void pcb_poly_frac_circle(pcb_pline_t *, pcb_coord_t, pcb_coord_t, pcb_vector_t, int);
 int pcb_poly_init_clip(pcb_data_t * d, pcb_layer_t * l, pcb_polygon_t * p);
 void pcb_poly_restore_to_poly(pcb_data_t *, int, void *, void *);
 void pcb_poly_clear_from_poly(pcb_data_t *, int, void *, void *);
diff --git a/src/rats.c b/src/rats.c
index 5c162c5..ab099a2 100644
--- a/src/rats.c
+++ b/src/rats.c
@@ -195,8 +195,9 @@ pcb_netlist_t *pcb_rat_proc_netlist(pcb_lib_t *net_menu)
 	badnet = pcb_false;
 
 	/* find layer groups of the component side and solder side */
-	SLayer = pcb_layer_get_group(pcb_solder_silk_layer);
-	CLayer = pcb_layer_get_group(pcb_component_silk_layer);
+	SLayer = CLayer = -1;
+	pcb_layer_list(PCB_LYT_BOTTOM | PCB_LYT_SILK, &SLayer, 1);
+	pcb_layer_list(PCB_LYT_TOP | PCB_LYT_SILK, &CLayer, 1);
 
 	Wantlist = (pcb_netlist_t *) calloc(1, sizeof(pcb_netlist_t));
 	if (Wantlist) {
@@ -831,8 +832,7 @@ pcb_rat_t *pcb_rat_add_net(void)
 	}
 
 	/* will work for pins to since the FLAG is common */
-	group1 = (PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, (pcb_pad_t *) ptr2) ?
-						pcb_layer_get_group(pcb_solder_silk_layer) : pcb_layer_get_group(pcb_component_silk_layer));
+	group1 = (PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, (pcb_pad_t *) ptr2) ? SLayer : CLayer);
 	strcpy(name1, pcb_connection_name(found, ptr1, ptr2));
 	found = pcb_search_obj_by_location(PCB_TYPE_PAD | PCB_TYPE_PIN, &ptr1, &ptr2, &ptr3,
 																 pcb_crosshair.AttachedLine.Point2.X, pcb_crosshair.AttachedLine.Point2.Y, 5);
@@ -844,8 +844,7 @@ pcb_rat_t *pcb_rat_add_net(void)
 		pcb_message(PCB_MSG_ERROR, _("You must name the ending element first\n"));
 		return (NULL);
 	}
-	group2 = (PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, (pcb_pad_t *) ptr2) ?
-						pcb_layer_get_group(pcb_solder_silk_layer) : pcb_layer_get_group(pcb_component_silk_layer));
+	group2 = (PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, (pcb_pad_t *) ptr2) ? SLayer : CLayer);
 	name2 = pcb_connection_name(found, ptr1, ptr2);
 
 	menu = pcb_netnode_to_netname(name1);
diff --git a/src/rats.h b/src/rats.h
index 67bf991..5ef24ee 100644
--- a/src/rats.h
+++ b/src/rats.h
@@ -34,6 +34,7 @@
 #include "config.h"
 #include "netlist.h"
 #include "layer.h"
+#include "layer_grp.h"
 
 /* ---------------------------------------------------------------------------
  * structure used by device drivers
diff --git a/src/remove.c b/src/remove.c
index 30ff2a7..4cf8f88 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -52,7 +52,7 @@ static pcb_opfunc_t RemoveFunctions = {
 	RemovePolygonPoint,
 	RemoveArc_op,
 	RemoveRat,
-	NULL
+	RemoveArcPoint_op,
 };
 
 static pcb_opfunc_t DestroyFunctions = {
diff --git a/src/search.c b/src/search.c
index 95b07af..f6f8ef0 100644
--- a/src/search.c
+++ b/src/search.c
@@ -951,6 +951,12 @@ pcb_bool pcb_is_point_in_box(pcb_coord_t X, pcb_coord_t Y, pcb_box_t *box, pcb_c
 	return range < Radius;
 }
 
+pcb_bool pcb_arc_in_box(pcb_arc_t *arc, pcb_box_t *b)
+{
+	pcb_box_t ab = pcb_arc_mini_bbox(arc);
+	return PCB_BOX_IN_BOX(&ab, b);
+}
+
 /* TODO: this code is BROKEN in the case of non-circular arcs,
  *       and in the case that the arc thickness is greater than
  *       the radius.
@@ -1085,11 +1091,14 @@ int pcb_search_obj_by_location(unsigned Type, void **Result1, void **Result2, vo
 		HigherAvail = PCB_TYPE_ELEMENT;
 	}
 
-	for (i = -1; i < pcb_max_copper_layer + 1; i++) {
+	for (i = -1; i < pcb_max_layer + 1; i++) {
+		if (pcb_layer_flags(i) & PCB_LYT_SILK) /* special order: silks are i=-1 and i=max+1, if we meet them elsewhere, skip */
+			continue;
 		if (i < 0)
 			SearchLayer = &PCB->Data->SILKLAYER;
-		else if (i < pcb_max_copper_layer)
+		else if (i < pcb_max_layer)
 			SearchLayer = LAYER_ON_STACK(i);
+
 		else {
 			SearchLayer = &PCB->Data->BACKSILKLAYER;
 			if (!PCB->InvisibleObjectsOn)
diff --git a/src/search.h b/src/search.h
index ac86c14..d279f3a 100644
--- a/src/search.h
+++ b/src/search.h
@@ -34,6 +34,7 @@
 #include "misc_util.h"
 
 int pcb_lines_intersect(pcb_coord_t ax1, pcb_coord_t ay1, pcb_coord_t ax2, pcb_coord_t ay2, pcb_coord_t bx1, pcb_coord_t by1, pcb_coord_t bx2, pcb_coord_t by2);
+pcb_bool pcb_arc_in_box(pcb_arc_t *arc, pcb_box_t *b);
 
 #define PCB_SLOP 5
 /* ---------------------------------------------------------------------------
@@ -70,8 +71,10 @@ int pcb_lines_intersect(pcb_coord_t ax1, pcb_coord_t ay1, pcb_coord_t ax2, pcb_c
 #define	PCB_ELEMENT_IN_BOX(e,b)	\
 	(PCB_BOX_IN_BOX(&((e)->BoundingBox), (b)))
 
+/* the bounding box is much larger than the minimum, use it to decide it
+   it is worth doing the expensive precise calculations */
 #define PCB_ARC_IN_BOX(a,b)		\
-	(PCB_BOX_IN_BOX(&((a)->BoundingBox), (b)))
+	((PCB_BOX_TOUCHES_BOX(&((a)->BoundingBox), (b))) && (pcb_arc_in_box(a,b)))
 
 /* == the same but accept if any part of the object touches the box == */
 #define PCB_POINT_IN_CIRCLE(x, y, cx, cy, r) \
diff --git a/src/select.c b/src/select.c
index 8b78a52..1fd5896 100644
--- a/src/select.c
+++ b/src/select.c
@@ -296,13 +296,15 @@ do { \
 	PCB_END_LOOP;
 
 	/* check layers */
-	LAYER_LOOP(PCB->Data, pcb_max_copper_layer + 2);
+	LAYER_LOOP(PCB->Data, pcb_max_layer);
 	{
-		if (layer == &PCB->Data->SILKLAYER) {
+		unsigned int lflg = pcb_layer_flags(layer);
+
+		if ((lflg & PCB_LYT_SILK) && (PCB_LAYERFLG_ON_VISIBLE_SIDE(lflg))) {
 			if (!(PCB->ElementOn || !Flag))
 				continue;
 		}
-		else if (layer == &PCB->Data->BACKSILKLAYER) {
+		else if ((lflg & PCB_LYT_SILK) && !(PCB_LAYERFLG_ON_VISIBLE_SIDE(lflg))) {
 			if (!(PCB->InvisibleObjectsOn || !Flag))
 				continue;
 		}
diff --git a/src/stub_draw_csect.c b/src/stub_draw_csect.c
new file mode 100644
index 0000000..34cdc09
--- /dev/null
+++ b/src/stub_draw_csect.c
@@ -0,0 +1,54 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* stub for drawing cross section of the board */
+
+#include "config.h"
+#include "stub_draw_csect.h"
+#include "obj_text.h"
+#include "obj_text_draw.h"
+
+static void dummy_draw_csect(pcb_hid_gc_t gc)
+{
+	pcb_text_t t;
+	t.X = 0;
+	t.Y = 0;
+	t.TextString = "Can't render the fab layer: the draw_csect plugin is not compiled and/or not loaded";
+	t.Direction = 0;
+	t.Scale = 150;
+	t.Flags = pcb_no_flags();
+	DrawTextLowLevel(&t, 0);
+}
+
+static pcb_bool dummy_mouse_csect(void *widget, pcb_hid_mouse_ev_t kind, pcb_coord_t x, pcb_coord_t y)
+{
+	return 0;
+}
+
+static void dummy_csect_overlay(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *ctx)
+{
+}
+
+void (*pcb_stub_draw_csect)(pcb_hid_gc_t gc) = dummy_draw_csect;
+pcb_bool (*pcb_stub_draw_csect_mouse_ev)(void *widget, pcb_hid_mouse_ev_t kind, pcb_coord_t x, pcb_coord_t y) = dummy_mouse_csect;
+void (*pcb_stub_draw_csect_overlay)(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *ctx) = dummy_csect_overlay;
+
diff --git a/src/stub_draw_csect.h b/src/stub_draw_csect.h
new file mode 100644
index 0000000..74680f5
--- /dev/null
+++ b/src/stub_draw_csect.h
@@ -0,0 +1,33 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef PCB_STUD_DRAW_CSECT_H
+#define PCB_STUD_DRAW_CSECT_H
+
+#include "hid.h"
+#include "pcb_bool.h"
+
+extern void (*pcb_stub_draw_csect)(pcb_hid_gc_t gc);
+extern pcb_bool (*pcb_stub_draw_csect_mouse_ev)(void *widget, pcb_hid_mouse_ev_t kind, pcb_coord_t x, pcb_coord_t y);
+extern void (*pcb_stub_draw_csect_overlay)(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *ctx);
+
+#endif
diff --git a/src_3rd/gensexpr/gensexpr_impl.c b/src_3rd/gensexpr/gensexpr_impl.c
index 4790058..c3ccd1c 100644
--- a/src_3rd/gensexpr/gensexpr_impl.c
+++ b/src_3rd/gensexpr/gensexpr_impl.c
@@ -147,6 +147,7 @@ void GSX(init_)(GSX(dom_t) *dom, size_t node_size)
 	dom->dump_allow_sq = 0;
 
 	gsx_parse_init(&dom->parse);
+	dom->parse.line_comment_char = '\0';
 	dom->parse.user_ctx = dom;
 	dom->parse.cb = GSX(parser_ev);
 	dom->parse_current = NULL;
diff --git a/src_3rd/gensexpr/gsx_parse.c b/src_3rd/gensexpr/gsx_parse.c
index 69aa187..b752e3f 100644
--- a/src_3rd/gensexpr/gsx_parse.c
+++ b/src_3rd/gensexpr/gsx_parse.c
@@ -92,6 +92,16 @@ int gsx_parse_char(gsx_parse_t *ctx, int chr)
 	if (chr == EOF) /* we are not in ST_EOE if we got here */
 			error(ctx, chr, "premature end of expression");
 
+	if ((ctx->line_comment_char != 0) && (chr == ctx->line_comment_char) && ctx->last_newline)
+		ctx->in_comment = 1;
+	ctx->last_newline = (chr == '\r') || (chr == '\n');
+	if (ctx->last_newline && ctx->in_comment) {
+		ctx->in_comment = 0;
+		goto skip_comment;
+	}
+	if (ctx->in_comment)
+		goto skip_comment;
+
 	switch(ctx->pstate) {
 		case ST_DQBS:
 			ctx->pstate = ST_DQ;
@@ -190,6 +200,7 @@ int gsx_parse_char(gsx_parse_t *ctx, int chr)
 			
 	}
 
+	skip_comment:;
 	update_loc(ctx, chr);
 	return GSX_RES_NEXT;
 
@@ -223,6 +234,8 @@ void gsx_parse_init(gsx_parse_t *ctx)
 	ctx->atom = NULL;
 	ctx->used = ctx->alloced = 0;
 	ctx->pstate = ST_NORMAL;
+	ctx->in_comment = 0;
+	ctx->last_newline = 0;
 }
 
 void gsx_parse_uninit(gsx_parse_t *ctx)
diff --git a/src_3rd/gensexpr/gsx_parse.h b/src_3rd/gensexpr/gsx_parse.h
index b7bc477..806c9d2 100644
--- a/src_3rd/gensexpr/gsx_parse.h
+++ b/src_3rd/gensexpr/gsx_parse.h
@@ -8,9 +8,12 @@ typedef enum gsx_parse_event_e {
 typedef struct gsx_parse_s gsx_parse_t;
 
 struct gsx_parse_s {
+	/* caller MUST fill in these fields before or after init: */
 	void (*cb)(gsx_parse_t *ctx, gsx_parse_event_t ev, const char *data);
 	void *user_ctx; /* filled in by the caller */
+	char line_comment_char; /* if non-zero, lines starting with this char are comments till the newline */
 
+	/* caller should not chaneg the rest of the fields */
 	/* location */
 	size_t offs, line, col, depth;
 
@@ -18,7 +21,8 @@ struct gsx_parse_s {
 	char *atom;
 	int used, alloced;
 	unsigned char pstate; /* parser state */
-
+	unsigned in_comment:1;
+	unsigned last_newline:1;
 };
 
 typedef enum gsx_parse_res_e {
diff --git a/src_3rd/gts/Makefile.dep b/src_3rd/gts/Makefile.dep
deleted file mode 100644
index 780ecd8..0000000
--- a/src_3rd/gts/Makefile.dep
+++ /dev/null
@@ -1,36 +0,0 @@
-### Generated file, do not edit, run make dep ###
-
-bbtree.o: bbtree.c gts.h
-boolean.o: boolean.c gts.h
-cdt.o: cdt.c ../../config.h gts.h
-container.o: container.c gts.h
-curvature.o: curvature.c gts.h
-edge.o: edge.c gts.h
-eheap.o: eheap.c gts.h
-face.o: face.c gts.h
-fifo.o: fifo.c gts.h
-graph.o: graph.c gts.h
-heap.o: heap.c gts.h
-hsurface.o: hsurface.c gts.h
-iso.o: iso.c gts.h
-isotetra.o: isotetra.c gts.h
-kdtree.o: kdtree.c gts.h
-matrix.o: matrix.c gts.h
-misc.o: misc.c gts.h gts-private.h ../../config.h
-named.o: named.c gts.h
-object.o: object.c gts.h gts-private.h
-oocs.o: oocs.c gts.h
-partition.o: partition.c gts.h
-pgraph.o: pgraph.c gts.h
-point.o: point.c gts.h gts-private.h predicates.h
-predicates.o: predicates.c predicates.h rounding.h ../../config.h
-psurface.o: psurface.c gts.h
-refine.o: refine.c gts.h
-segment.o: segment.c gts.h
-split.o: split.c gts.h
-stripe.o: stripe.c gts.h
-surface.o: surface.c gts.h gts-private.h
-triangle.o: triangle.c gts.h
-tribox3.o: tribox3.c
-vertex.o: vertex.c gts.h
-vopt.o: vopt.c gts.h
diff --git a/src_3rd/gts/Makefile.in b/src_3rd/gts/Makefile.in
deleted file mode 100644
index 261f19e..0000000
--- a/src_3rd/gts/Makefile.in
+++ /dev/null
@@ -1,74 +0,0 @@
-if /local/gts/enable
-then
-put /local/gts/CFLAGS [@-I. -I.. -I../.. -DG_LOG_DOMAIN=\"Gts\" @libs/sul/glib/cflags@@]
-put /local/gts/OBJS [@
-	object.o
-	point.o
-	vertex.o
-	segment.o
-	edge.o
-	triangle.o
-	face.o
-	kdtree.o
-	bbtree.o
-	misc.o
-	predicates.o
-	heap.o
-	eheap.o
-	fifo.o
-	matrix.o
-	surface.o
-	stripe.o
-	vopt.o
-	refine.o
-	iso.o
-	isotetra.o
-	split.o
-	psurface.o
-	hsurface.o
-	cdt.o
-	boolean.o
-	named.o
-	oocs.o
-	container.o
-	graph.o
-	pgraph.o
-	partition.o
-	curvature.o
-	tribox3.o
-@]
-
-put /tmpasm/OFS { }
-uniq /local/gts/OBJS
-put /local/gts/SRCS /local/gts/OBJS
-gsub /local/gts/SRCS {.o } {.c }
-
-print [@
-CFLAGS = @/local/gts/CFLAGS@
-OBJS = @/local/gts/OBJS@
-CC=@cc/cc@
-
-libgts.a: $(OBJS)
-	@/host/fstools/ar@ rvu libgts.a $(OBJS)
-
-clean:
-	-@/host/fstools/rm@ $(OBJS) libgts.a
-@]
-
-# generate explicit rules for .c -> .o
-put /local/comp/OBJS /local/gts/OBJS
-include {../../scconfig/Makefile.comp.inc}
-
-# generate deps
-put /local/dep/CFLAGS /local/gts/CFLAGS
-put /local/dep/SRCS /local/gts/SRCS
-include {../../scconfig/Makefile.dep.inc}
-else
-print [@
-all:
-
-libgts.a:
-
-clean:
-@]
-end
diff --git a/src_3rd/gts/bbtree.c b/src_3rd/gts/bbtree.c
deleted file mode 100644
index cec93e4..0000000
--- a/src_3rd/gts/bbtree.c
+++ /dev/null
@@ -1,1289 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include "gts.h"
-
-static void bbox_init (GtsBBox * bbox)
-{
-  bbox->bounded = NULL;
-}
-
-/**
- * gts_bbox_class:
- *
- * Returns: the #GtsBBoxClass.
- */
-GtsBBoxClass * gts_bbox_class (void)
-{
-  static GtsBBoxClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo bbox_info = {
-      "GtsBBox",
-      sizeof (GtsBBox),
-      sizeof (GtsBBoxClass),
-      (GtsObjectClassInitFunc) NULL,
-      (GtsObjectInitFunc) bbox_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), &bbox_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_bbox_set:
- * @bbox: a #GtsBBox.
- * @bounded: the object to be bounded.
- * @x1: x-coordinate of the lower left corner.
- * @y1: y-coordinate of the lower left corner.
- * @z1: z-coordinate of the lower left corner.
- * @x2: x-coordinate of the upper right corner.
- * @y2: y-coordinate of the upper right corner.
- * @z2: z-coordinate of the upper right corner.
- *
- * Sets fields of @bbox.
- */
-void gts_bbox_set (GtsBBox * bbox,
-		   gpointer bounded,
-		   gdouble x1, gdouble y1, gdouble z1,
-		   gdouble x2, gdouble y2, gdouble z2)
-{
-  g_return_if_fail (bbox != NULL);
-  g_return_if_fail (x2 >= x1 && y2 >= y1 && z2 >= z1);
-
-  bbox->x1 = x1; bbox->y1 = y1; bbox->z1 = z1;
-  bbox->x2 = x2; bbox->y2 = y2; bbox->z2 = z2;
-  bbox->bounded = bounded;
-}
-
-/**
- * gts_bbox_new:
- * @klass: a #GtsBBoxClass.
- * @bounded: the object to be bounded.
- * @x1: x-coordinate of the lower left corner.
- * @y1: y-coordinate of the lower left corner.
- * @z1: z-coordinate of the lower left corner.
- * @x2: x-coordinate of the upper right corner.
- * @y2: y-coordinate of the upper right corner.
- * @z2: z-coordinate of the upper right corner.
- *
- * Returns: a new #GtsBBox.
- */
-GtsBBox * gts_bbox_new (GtsBBoxClass * klass,
-			gpointer bounded,
-			gdouble x1, gdouble y1, gdouble z1,
-			gdouble x2, gdouble y2, gdouble z2)
-{
-  GtsBBox * bbox;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  bbox = GTS_BBOX (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  gts_bbox_set (bbox, bounded, x1, y1, z1, x2, y2, z2);
-  return bbox;
-}
-
-/**
- * gts_bbox_triangle:
- * @klass: a #GtsBBoxClass.
- * @t: a #GtsTriangle.
- *
- * Returns: a new #GtsBBox bounding box of @t.
- */
-GtsBBox * gts_bbox_triangle (GtsBBoxClass * klass,
-			     GtsTriangle * t)
-{
-  GtsBBox * bbox;
-  GtsPoint * p;
-
-  g_return_val_if_fail (t != NULL, NULL);
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  p = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
-  bbox = gts_bbox_new (klass, t, p->x, p->y, p->z, p->x, p->y, p->z);
-
-  p = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-  if (p->x > bbox->x2) bbox->x2 = p->x;
-  if (p->x < bbox->x1) bbox->x1 = p->x;
-  if (p->y > bbox->y2) bbox->y2 = p->y;
-  if (p->y < bbox->y1) bbox->y1 = p->y;
-  if (p->z > bbox->z2) bbox->z2 = p->z;
-  if (p->z < bbox->z1) bbox->z1 = p->z;
-  p = GTS_POINT (gts_triangle_vertex (t));
-  if (p->x > bbox->x2) bbox->x2 = p->x;
-  if (p->x < bbox->x1) bbox->x1 = p->x;
-  if (p->y > bbox->y2) bbox->y2 = p->y;
-  if (p->y < bbox->y1) bbox->y1 = p->y;
-  if (p->z > bbox->z2) bbox->z2 = p->z;
-  if (p->z < bbox->z1) bbox->z1 = p->z;
-  
-  return bbox;
-}
-
-/**
- * gts_bbox_segment:
- * @klass: a #GtsBBoxClass.
- * @s: a #GtsSegment.
- * 
- * Returns: a new #GtsBBox bounding box of @s.
- */
-GtsBBox * gts_bbox_segment (GtsBBoxClass * klass, GtsSegment * s)
-{
-  GtsBBox * bbox;
-  GtsPoint * p1, * p2;
-
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  bbox = gts_bbox_new (klass, s, 0., 0., 0., 0., 0., 0.);
-
-  p1 = GTS_POINT (s->v1); 
-  p2 = GTS_POINT (s->v2);
-  if (p1->x > p2->x) {
-    bbox->x2 = p1->x; bbox->x1 = p2->x;
-  }
-  else {
-    bbox->x1 = p1->x; bbox->x2 = p2->x;
-  }
-  if (p1->y > p2->y) {
-    bbox->y2 = p1->y; bbox->y1 = p2->y;
-  }
-  else {
-    bbox->y1 = p1->y; bbox->y2 = p2->y;
-  }
-  if (p1->z > p2->z) {
-    bbox->z2 = p1->z; bbox->z1 = p2->z;
-  }
-  else {
-    bbox->z1 = p1->z; bbox->z2 = p2->z;
-  }
-
-  return bbox;
-}
-
-static void bbox_foreach_vertex (GtsPoint * p, GtsBBox * bb)
-{
-  if (p->x < bb->x1) bb->x1 = p->x;
-  if (p->y < bb->y1) bb->y1 = p->y;
-  if (p->z < bb->z1) bb->z1 = p->z;
-  if (p->x > bb->x2) bb->x2 = p->x;
-  if (p->y > bb->y2) bb->y2 = p->y;
-  if (p->z > bb->z2) bb->z2 = p->z;
-}
-
-/**
- * gts_bbox_surface:
- * @klass: a #GtsBBoxClass.
- * @surface: a #GtsSurface.
- *
- * Returns: a new #GtsBBox bounding box of @surface.
- */
-GtsBBox * gts_bbox_surface (GtsBBoxClass * klass, GtsSurface * surface)
-{
-  GtsBBox * bbox;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (surface != NULL, NULL);
-
-  bbox = gts_bbox_new (klass, surface, 0., 0., 0., 0., 0., 0.);
-  bbox->x1 = bbox->y1 = bbox->z1 = G_MAXDOUBLE;
-  bbox->x2 = bbox->y2 = bbox->z2 = -G_MAXDOUBLE;
-
-  gts_surface_foreach_vertex (surface, (GtsFunc) bbox_foreach_vertex, bbox);
-
-  return bbox;
-}
-
-/**
- * gts_bbox_bboxes:
- * @klass: a #GtsBBoxClass.
- * @bboxes: a list of #GtsBBox.
- * 
- * Returns: a new #GtsBBox bounding box of all the bounding boxes in
- * @bboxes.  
- */
-GtsBBox * gts_bbox_bboxes (GtsBBoxClass * klass, GSList * bboxes)
-{
-  GtsBBox * bbox;
-  GtsBBox * bb;
-
-  g_return_val_if_fail (bboxes != NULL, NULL);
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  bb = bboxes->data;
-  bbox = gts_bbox_new (klass, bboxes, 
-		       bb->x1, bb->y1, bb->z1, bb->x2, bb->y2, bb->z2);
-  bboxes = bboxes->next;
-  while (bboxes) {
-    bb = bboxes->data;
-    if (bb->x1 < bbox->x1) bbox->x1 = bb->x1;
-    if (bb->y1 < bbox->y1) bbox->y1 = bb->y1;
-    if (bb->z1 < bbox->z1) bbox->z1 = bb->z1;
-    if (bb->x2 > bbox->x2) bbox->x2 = bb->x2;
-    if (bb->y2 > bbox->y2) bbox->y2 = bb->y2;
-    if (bb->z2 > bbox->z2) bbox->z2 = bb->z2;
-    bboxes = bboxes->next;
-  }
-
-  return bbox;
-}
-
-/**
- * gts_bbox_points:
- * @klass: a #GtsBBoxClass.
- * @points: a list of #GtsPoint.
- *
- * Returns: a new #GtsBBox bounding box of @points.
- */
-GtsBBox * gts_bbox_points (GtsBBoxClass * klass, GSList * points)
-{
-  GtsPoint * p;
-  GtsBBox * bbox;
-  GSList * i;
-
-  if (points == NULL) 
-    return NULL;
-
-  p = points->data;  
-  bbox = gts_bbox_new (klass, points, p->x, p->y, p->z, p->x, p->y, p->z);
-
-  i = points->next;
-  while (i) {
-    p = i->data;
-    if (p->x > bbox->x2) 
-      bbox->x2 = p->x;
-    else if (p->x < bbox->x1) 
-      bbox->x1 = p->x;
-    if (p->y > bbox->y2) 
-      bbox->y2 = p->y;
-    else if (p->y < bbox->y1) 
-      bbox->y1 = p->y;
-    if (p->z > bbox->z2) 
-      bbox->z2 = p->z;
-    else if (p->z < bbox->z1) 
-      bbox->z1 = p->z;
-    i = i->next;
-  }
-  
-  return bbox;
-}
-
-/**
- * gts_bboxes_are_overlapping:
- * @bb1: a #GtsBBox.
- * @bb2: a #GtsBBox.
- *
- * Returns: %TRUE if the bounding boxes @bb1 and @bb2 are overlapping
- * (including just touching), %FALSE otherwise.
- */
-gboolean gts_bboxes_are_overlapping (GtsBBox * bb1, GtsBBox * bb2)
-{
-  if (bb1 == bb2)
-    return TRUE;
-  if (bb1->x1 > bb2->x2)
-    return FALSE;
-  if (bb2->x1 > bb1->x2)
-    return FALSE;
-  if (bb1->y1 > bb2->y2)
-    return FALSE;
-  if (bb2->y1 > bb1->y2)
-    return FALSE;
-  if (bb1->z1 > bb2->z2)
-    return FALSE;
-  if (bb2->z1 > bb1->z2)
-    return FALSE;  
-  return TRUE;
-}
-
-#define bbox_volume(bb) (((bb)->x2 -\
-                          (bb)->x1)*\
-                         ((bb)->y2 -\
-                          (bb)->y1)*\
-                         ((bb)->z2 -\
-                          (bb)->z1))
-
-/**
- * gts_bbox_diagonal2:
- * @bb: a #GtsBBox.
- *
- * Returns: the squared length of the diagonal of @bb.
- */
-gdouble gts_bbox_diagonal2 (GtsBBox * bb)
-{
-  gdouble x, y, z;
-
-  g_return_val_if_fail (bb != NULL, 0.);
-
-  x = bb->x2 - bb->x1;
-  y = bb->y2 - bb->y1;
-  z = bb->z2 - bb->z1;
-
-  return x*x + y*y + z*z;
-}
-
-/**
- * gts_bbox_draw:
- * @bb: a #GtsBBox.
- * @fptr: a file pointer.
- * 
- * Writes in file @fptr an OOGL (Geomview) description of @bb.
- */
-void gts_bbox_draw (GtsBBox * bb, FILE * fptr)
-{
-  g_return_if_fail (bb != NULL);
-
-  fprintf (fptr, "OFF 8 6 12\n");
-  fprintf (fptr, "%g %g %g\n",
-	   bb->x1, bb->y1, bb->z1);
-  fprintf (fptr, "%g %g %g\n",
-	   bb->x2, bb->y1, bb->z1);
-  fprintf (fptr, "%g %g %g\n",
-	   bb->x2, bb->y2, bb->z1);
-  fprintf (fptr, "%g %g %g\n",
-	   bb->x1, bb->y2, bb->z1);
-  fprintf (fptr, "%g %g %g\n",
-	   bb->x1, bb->y1, bb->z2);
-  fprintf (fptr, "%g %g %g\n",
-	   bb->x2, bb->y1, bb->z2);
-  fprintf (fptr, "%g %g %g\n",
-	   bb->x2, bb->y2, bb->z2);
-  fprintf (fptr, "%g %g %g\n",
-	   bb->x1, bb->y2, bb->z2);
-  fputs ("4 3 2 1 0\n"
-	 "4 4 5 6 7\n"
-	 "4 2 3 7 6\n"
-	 "4 0 1 5 4\n"
-	 "4 0 4 7 3\n"
-	 "4 1 2 6 5\n",
-	 fptr);
-}
-
-#define MINMAX(x1, x2, xmin, xmax) { if (x1 < x2) { xmin = x1; xmax = x2; }\
-                                     else { xmin = x2; xmax = x1; } }
-
-/**
- * gts_bbox_point_distance2:
- * @bb: a #GtsBBox.
- * @p: a #GtsPoint.
- * @min: a pointer on a gdouble.
- * @max: a pointer on a gdouble.
- * 
- * Sets @min and @max to lower and upper bounds for the square of the
- * Euclidean distance between the object contained in @bb and @p. For these
- * bounds to make any sense the bounding box must be "tight" i.e. each of the
- * 6 faces of the box must at least be touched by one point of the bounded
- * object.
- */
-void gts_bbox_point_distance2 (GtsBBox * bb, GtsPoint * p,
-			       gdouble * min, gdouble * max)
-{
-  gdouble x1, y1, z1, x2, y2, z2, x, y, z;
-  gdouble dmin, dmax, xd1, xd2, yd1, yd2, zd1, zd2;
-  gdouble mx, Mx, my, My, mz, Mz;
-    
-  g_return_if_fail (bb != NULL);
-  g_return_if_fail (p != NULL);
-  g_return_if_fail (min != NULL);
-  g_return_if_fail (max != NULL);
-
-  x1 = bb->x1; y1 = bb->y1; z1 = bb->z1; 
-  x2 = bb->x2; y2 = bb->y2; z2 = bb->z2;
-  x = p->x; y = p->y; z = p->z;
-
-  xd1 = (x1 - x)*(x1 - x);
-  xd2 = (x - x2)*(x - x2);
-  yd1 = (y1 - y)*(y1 - y);
-  yd2 = (y - y2)*(y - y2);
-  zd1 = (z1 - z)*(z1 - z);
-  zd2 = (z - z2)*(z - z2);
-  
-  dmin = x < x1 ? xd1 : x > x2 ? xd2 : 0.0;
-  dmin += y < y1 ? yd1 : y > y2 ? yd2 : 0.0;
-  dmin += z < z1 ? zd1 : z > z2 ? zd2 : 0.0;
-
-  MINMAX (xd1, xd2, mx, Mx);
-  MINMAX (yd1, yd2, my, My);
-  MINMAX (zd1, zd2, mz, Mz);
-  
-  dmax = mx + My + Mz;
-  dmax = MIN (dmax, Mx + my + Mz);
-  dmax = MIN (dmax, Mx + My + mz);
-  
-  *min = dmin;
-  *max = dmax;
-}
-
-/**
- * gts_bbox_is_stabbed:
- * @bb: a #GtsBBox.
- * @p: a #GtsPoint.
- *
- * Returns: %TRUE if the ray starting at @p and ending at (+infty,
- * @p->y, @p->z) intersects with @bb, %FALSE otherwise.
- */
-gboolean gts_bbox_is_stabbed (GtsBBox * bb, GtsPoint * p)
-{
-  g_return_val_if_fail (bb != NULL, FALSE);
-  g_return_val_if_fail (p != NULL, FALSE);
-
-  if (p->x > bb->x2 ||
-      p->y < bb->y1 || p->y > bb->y2 ||
-      p->z < bb->z1 || p->z > bb->z2)
-    return FALSE;
-  return TRUE;
-}
-
-extern int triBoxOverlap (double boxcenter[3],
-			  double boxhalfsize[3],
-			  double triverts[3][3]);
-
-/**
- * gts_bbox_overlaps_triangle:
- * @bb: a #GtsBBox.
- * @t: a #GtsTriangle.
- *
- * This is a wrapper around the fast overlap test of Tomas
- * Akenine-Moller (http://www.cs.lth.se/home/Tomas_Akenine_Moller/).
- *
- * Returns: %TRUE if @bb overlaps with @t, %FALSE otherwise.
- */
-gboolean gts_bbox_overlaps_triangle (GtsBBox * bb, GtsTriangle * t)
-{
-  double bc[3], bh[3], tv[3][3];
-  GtsPoint * p1, * p2, * p3;
-
-  g_return_val_if_fail (bb != NULL, FALSE);
-  g_return_val_if_fail (t != NULL, FALSE);
-
-  bc[0] = (bb->x2 + bb->x1)/2.;
-  bh[0] = (bb->x2 - bb->x1)/2.;
-  bc[1] = (bb->y2 + bb->y1)/2.;
-  bh[1] = (bb->y2 - bb->y1)/2.;
-  bc[2] = (bb->z2 + bb->z1)/2.;
-  bh[2] = (bb->z2 - bb->z1)/2.;
-  p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
-  p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-  p3 = GTS_POINT (gts_triangle_vertex (t));
-  tv[0][0] = p1->x; tv[0][1] = p1->y; tv[0][2] = p1->z;
-  tv[1][0] = p2->x; tv[1][1] = p2->y; tv[1][2] = p2->z;
-  tv[2][0] = p3->x; tv[2][1] = p3->y; tv[2][2] = p3->z;
-
-  return triBoxOverlap (bc, bh, tv);
-}
-
-/**
- * gts_bbox_overlaps_segment:
- * @bb: a #GtsBBox.
- * @s: a #GtsSegment.
- *
- * This functions uses gts_bbox_overlaps_triangle() with a degenerate
- * triangle.
- *
- * Returns: %TRUE if @bb overlaps with @s, %FALSE otherwise.
- */
-gboolean gts_bbox_overlaps_segment (GtsBBox * bb, GtsSegment * s)
-{
-  double bc[3], bh[3], tv[3][3];
-  GtsPoint * p1, * p2, * p3;
-
-  g_return_val_if_fail (bb != NULL, FALSE);
-  g_return_val_if_fail (s != NULL, FALSE);
-
-  bc[0] = (bb->x2 + bb->x1)/2.;
-  bh[0] = (bb->x2 - bb->x1)/2.;
-  bc[1] = (bb->y2 + bb->y1)/2.;
-  bh[1] = (bb->y2 - bb->y1)/2.;
-  bc[2] = (bb->z2 + bb->z1)/2.;
-  bh[2] = (bb->z2 - bb->z1)/2.;
-  p1 = GTS_POINT (s->v1);
-  p2 = GTS_POINT (s->v2);
-  p3 = p1;
-  tv[0][0] = p1->x; tv[0][1] = p1->y; tv[0][2] = p1->z;
-  tv[1][0] = p2->x; tv[1][1] = p2->y; tv[1][2] = p2->z;
-  tv[2][0] = p3->x; tv[2][1] = p3->y; tv[2][2] = p3->z;
-
-  return triBoxOverlap (bc, bh, tv);
-}
-
-/**
- * gts_bb_tree_new:
- * @bboxes: a list of #GtsBBox.
- *
- * Builds a new hierarchy of bounding boxes for @bboxes. At each
- * level, the GNode->data field contains a #GtsBBox bounding box of
- * all the children. The tree is binary and is built by repeatedly
- * cutting in two approximately equal halves the bounding boxes at
- * each level until a leaf node (i.e. a bounding box given in @bboxes)
- * is reached. In order to minimize the depth of the tree, the cutting
- * direction is always chosen as perpendicular to the longest
- * dimension of the bounding box.
- *
- * Returns: a new hierarchy of bounding boxes.  
- */
-GNode * gts_bb_tree_new (GSList * bboxes)
-{
-  GSList * i, * positive = NULL, * negative = NULL;
-  GNode * node;
-  GtsBBox * bbox;
-  guint dir, np = 0, nn = 0;
-  gdouble * p1, * p2;
-  gdouble cut;
-  
-  g_return_val_if_fail (bboxes != NULL, NULL);
-
-  if (bboxes->next == NULL) /* leaf node */
-    return g_node_new (bboxes->data);
-
-  bbox = gts_bbox_bboxes (gts_bbox_class (), bboxes);
-  node = g_node_new (bbox);
-
-  if (bbox->x2 - bbox->x1 > bbox->y2 - bbox->y1) {
-    if (bbox->z2 - bbox->z1 > bbox->x2 - bbox->x1)
-      dir = 2;
-    else
-      dir = 0;
-  }
-  else if (bbox->z2 - bbox->z1 > bbox->y2 - bbox->y1)
-    dir = 2;
-  else
-    dir = 1;
-
-  p1 = (gdouble *) &bbox->x1;
-  p2 = (gdouble *) &bbox->x2;
-  cut = (p1[dir] + p2[dir])/2.;
-  i = bboxes;
-  while (i) {
-    bbox = i->data; 
-    p1 = (gdouble *) &bbox->x1;
-    p2 = (gdouble *) &bbox->x2;
-    if ((p1[dir] + p2[dir])/2. > cut) {
-      positive = g_slist_prepend (positive, bbox);
-      np++;
-    }
-    else {
-      negative = g_slist_prepend (negative, bbox);
-      nn++;
-    }
-    i = i->next;
-  }
-  if (!positive) {
-    GSList * last = g_slist_nth (negative, (nn - 1)/2);
-    positive = last->next;
-    last->next = NULL;
-  }
-  else if (!negative) {
-    GSList * last = g_slist_nth (positive, (np - 1)/2);
-    negative = last->next;
-    last->next = NULL;
-  }
-  g_node_prepend (node, gts_bb_tree_new (positive));
-  g_slist_free (positive);
-  g_node_prepend (node, gts_bb_tree_new (negative));
-  g_slist_free (negative);
-  
-  return node;
-}
-
-static void prepend_triangle_bbox (GtsTriangle * t, GSList ** bboxes)
-{
-  *bboxes = g_slist_prepend (*bboxes, 
-			     gts_bbox_triangle (gts_bbox_class (), t));
-}
-
-/**
- * gts_bb_tree_surface:
- * @s: a #GtsSurface.
- *
- * Returns: a new hierarchy of bounding boxes bounding the faces of @s.
- */
-GNode * gts_bb_tree_surface (GtsSurface * s)
-{
-  GSList * bboxes = NULL;
-  GNode * tree;
-
-  g_return_val_if_fail (s != NULL, NULL);
-
-  gts_surface_foreach_face (s, (GtsFunc) prepend_triangle_bbox, &bboxes);
-  tree = gts_bb_tree_new (bboxes);
-  g_slist_free (bboxes);
-
-  return tree;
-}
-
-/**
- * gts_bb_tree_stabbed:
- * @tree: a bounding box tree.
- * @p: a #GtsPoint.
- *
- * Returns: a list of bounding boxes, leaves of @tree which are
- * stabbed by the ray defined by @p (see gts_bbox_is_stabbed()).
- */
-GSList * gts_bb_tree_stabbed (GNode * tree, GtsPoint * p)
-{
-  GSList * list = NULL;
-  GtsBBox * bb;
-  GNode * i;
-
-  g_return_val_if_fail (tree != NULL, NULL);
-  g_return_val_if_fail (p != NULL, NULL);
-
-  bb = tree->data;
-  if (!gts_bbox_is_stabbed (bb, p))
-    return NULL;
-  if (tree->children == NULL) /* leaf node */
-    return g_slist_prepend (NULL, bb);
-  i = tree->children;
-  while (i) {
-    list = g_slist_concat (list, gts_bb_tree_stabbed (i, p));
-    i = i->next;
-  }
-  return list;
-}
-
-/**
- * gts_bb_tree_overlap:
- * @tree: a bounding box tree.
- * @bbox: a #GtsBBox.
- *
- * Returns: a list of bounding boxes, leaves of @tree which overlap @bbox.
- */
-GSList * gts_bb_tree_overlap (GNode * tree, GtsBBox * bbox)
-{
-  GSList * list = NULL;
-  GtsBBox * bb;
-  GNode * i;
-
-  g_return_val_if_fail (tree != NULL, NULL);
-  g_return_val_if_fail (bbox != NULL, NULL);
-
-  bb = tree->data;
-  if (!gts_bboxes_are_overlapping (bbox, bb))
-    return NULL;
-  if (tree->children == NULL) /* leaf node */
-    return g_slist_prepend (NULL, bb);
-  i = tree->children;
-  while (i) {
-    list = g_slist_concat (list, gts_bb_tree_overlap (i, bbox));
-    i = i->next;
-  }
-  return list;
-}
-
-/**
- * gts_bb_tree_is_overlapping:
- * @tree: a bounding box tree.
- * @bbox: a #GtsBBox.
- *
- * Returns: %TRUE if any leaf of @tree overlaps @bbox, %FALSE otherwise.
- */
-gboolean gts_bb_tree_is_overlapping (GNode * tree, GtsBBox * bbox)
-{
-  GtsBBox * bb;
-  GNode * i;
-
-  g_return_val_if_fail (tree != NULL, FALSE);
-  g_return_val_if_fail (bbox != NULL, FALSE);
-
-  bb = tree->data;
-  if (!gts_bboxes_are_overlapping (bbox, bb))
-    return FALSE;
-  if (tree->children == NULL) /* leaf node */
-    return TRUE;
-  i = tree->children;
-  while (i) {
-    if (gts_bb_tree_is_overlapping (i, bbox))
-      return TRUE;
-    i = i->next;
-  }
-  return FALSE;
-}
-
-/**
- * gts_bb_tree_traverse_overlapping:
- * @tree1: a bounding box tree.
- * @tree2: a bounding box tree.
- * @func: a #GtsBBTreeTraverseFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func for each overlapping pair of leaves of @tree1 and @tree2.
- */
-void gts_bb_tree_traverse_overlapping (GNode * tree1, GNode * tree2,
-				       GtsBBTreeTraverseFunc func,
-				       gpointer data)
-{
-  GtsBBox * bb1, * bb2;
-
-  g_return_if_fail (tree1 != NULL && tree2 != NULL);
-
-  bb1 = tree1->data; bb2 = tree2->data;
-  if (!gts_bboxes_are_overlapping (bb1, bb2))
-    return;
-
-  if (tree1->children == NULL && tree2->children == NULL)
-    (*func) (tree1->data, tree2->data, data);
-  else if (tree2->children == NULL || 
-	   (tree1->children != NULL && 
-	    bbox_volume (bb1) > bbox_volume (bb2))) {
-    GNode * i = tree1->children;
-    while (i) {
-      gts_bb_tree_traverse_overlapping (i, tree2, func, data);
-      i = i->next;
-    }
-  }
-  else {
-    GNode * i = tree2->children;
-    while (i) {
-      gts_bb_tree_traverse_overlapping (tree1, i, func, data);
-      i = i->next;
-    }
-  }
-}
-
-/**
- * gts_bb_tree_draw:
- * @tree: a bounding box tree.
- * @depth: a specified depth.
- * @fptr: a file pointer.
- *
- * Write in @fptr an OOGL (Geomview) description of @tree for the
- * depth specified by @depth.
- */
-void gts_bb_tree_draw (GNode * tree, guint depth, FILE * fptr)
-{
-  guint d;
-
-  g_return_if_fail (tree != NULL);
-  g_return_if_fail (fptr != NULL);
-
-  d = g_node_depth (tree);
-
-  if (d == 1)
-    fprintf (fptr, "{ LIST");
-
-  if (d == depth)
-    gts_bbox_draw (tree->data, fptr);
-  else if (d < depth) {
-    GNode * i = tree->children;
-    while (i) {
-      gts_bb_tree_draw (i, depth, fptr);
-      i = i->next;
-    }
-  }
-
-  if (d == 1)
-    fprintf (fptr, "}\n");
-}
-
-static void bb_tree_free (GNode * tree, gboolean free_leaves)
-{
-  GNode * i;
-
-  g_return_if_fail (tree != NULL);
-
-  if (!free_leaves && tree->children == NULL) /* leaf node */
-    return;
-
-  gts_object_destroy (tree->data);
-
-  i = tree->children;
-  while (i) {
-    bb_tree_free (i, free_leaves);
-    i = i->next;
-  }
-}
-
-/**
- * gts_bb_tree_destroy:
- * @tree: a bounding box tree.
- * @free_leaves: if %TRUE the bounding boxes given by the user are freed.
- *
- * Destroys all the bounding boxes created by @tree and destroys the
- * tree itself. If @free_leaves is set to %TRUE, destroys boxes given
- * by the user when creating the tree (i.e. leaves of the tree).  
- */
-void gts_bb_tree_destroy (GNode * tree, gboolean free_leaves)
-{
-  g_return_if_fail (tree != NULL);
-  
-  bb_tree_free (tree, free_leaves);
-  g_node_destroy (tree);
-}
-
-static gdouble bb_tree_min_max (GNode * tree,
-				GtsPoint * p,
-				gdouble min_max,
-				GSList ** list)
-{
-  GNode * tree1, * tree2;
-  gdouble min1, max1, min2, max2;
-
-  if (tree->children == NULL) {
-    *list = g_slist_prepend (*list, tree->data);
-    return min_max;
-  }
-  tree1 = tree->children;
-  gts_bbox_point_distance2 (tree1->data, p, &min1, &max1);
-  if (max1 < min_max)
-    min_max = max1;
-
-  tree2 = tree1->next;
-  gts_bbox_point_distance2 (tree2->data, p, &min2, &max2);
-  if (max2 < min_max)
-    min_max = max2;
-
-  if (min1 < min2) {
-    if (min1 <= min_max) {
-      min_max = bb_tree_min_max (tree1, p, min_max, list);
-      if (min2 <= min_max)
-	min_max = bb_tree_min_max (tree2, p, min_max, list);
-    }
-  }
-  else {
-    if (min2 <= min_max) {
-      min_max = bb_tree_min_max (tree2, p, min_max, list);
-      if (min1 <= min_max)
-	min_max = bb_tree_min_max (tree1, p, min_max, list);
-    }
-  }
-
-  return min_max;
-}
-
-/**
- * gts_bb_tree_point_closest_bboxes:
- * @tree: a bounding box tree.
- * @p: a #GtsPoint.
- *
- * Returns: a list of #GtsBBox. One of the bounding boxes is assured to contain
- * the object of @tree closest to @p.
- */
-GSList * gts_bb_tree_point_closest_bboxes (GNode * tree, 
-					   GtsPoint * p)
-{
-  gdouble min, min_max;
-  GSList * list = NULL, * i, * prev = NULL;
-
-  g_return_val_if_fail (tree != NULL, NULL);
-  g_return_val_if_fail (p != NULL, NULL);
-
-  gts_bbox_point_distance2 (tree->data, p, &min, &min_max);
-  min_max = bb_tree_min_max (tree, p, min_max, &list);
-
-  i = list;
-  while (i) {
-    GSList * next = i->next;
-    gdouble min, max;
-
-    gts_bbox_point_distance2 (i->data, p, &min, &max);
-
-    if (min > min_max) {
-      if (prev == NULL)
-	list = next;
-      else
-	prev->next = next;
-      g_slist_free_1 (i);
-    }
-    else
-      prev = i;
-    i = next;
-  }
-
-  return list;
-}
-
-/**
- * gts_bb_tree_point_distance:
- * @tree: a bounding box tree.
- * @p: a #GtsPoint.
- * @distance: a #GtsBBoxDistFunc.
- * @bbox: if not %NULL is set to the bounding box containing the closest 
- * object.
- *
- * Returns: the distance as evaluated by @distance between @p and the closest
- * object in @tree.
- */
-gdouble gts_bb_tree_point_distance (GNode * tree, 
-				    GtsPoint * p,
-				    GtsBBoxDistFunc distance,
-				    GtsBBox ** bbox)
-{
-  GSList * list, * i;
-  gdouble dmin = G_MAXDOUBLE;
-
-  g_return_val_if_fail (tree != NULL, dmin);
-  g_return_val_if_fail (p != NULL, dmin);
-  g_return_val_if_fail (distance != NULL, dmin);
-
-  i = list = gts_bb_tree_point_closest_bboxes (tree, p);
-  while (i) {
-    gdouble d = (*distance) (p, GTS_BBOX (i->data)->bounded);
-
-    if (fabs (d) < fabs (dmin)) {
-      dmin = d;
-      if (bbox)
-	*bbox = i->data;
-    }
-    i = i->next;
-  }
-  g_slist_free (list);
-
-  return dmin;
-}
-
-/**
- * gts_bb_tree_point_closest:
- * @tree: a bounding box tree.
- * @p: a #GtsPoint.
- * @closest: a #GtsBBoxClosestFunc.
- * @distance: if not %NULL is set to the distance between @p and the 
- * new #GtsPoint.
- *
- * Returns: a new #GtsPoint, closest point to @p and belonging to an object of
- * @tree.
- */
-GtsPoint * gts_bb_tree_point_closest (GNode * tree, 
-				      GtsPoint * p,
-				      GtsBBoxClosestFunc closest,
-				      gdouble * distance)
-{
-  GSList * list, * i;
-  gdouble dmin = G_MAXDOUBLE;
-  GtsPoint * np = NULL;
-
-  g_return_val_if_fail (tree != NULL, NULL);
-  g_return_val_if_fail (p != NULL, NULL);
-  g_return_val_if_fail (closest != NULL, NULL);
-
-  i = list = gts_bb_tree_point_closest_bboxes (tree, p);
-  while (i) {
-    GtsPoint * tp = (*closest) (p, GTS_BBOX (i->data)->bounded);
-    gdouble d = gts_point_distance2 (tp, p);
-
-    if (d < dmin) {
-      if (np)
-	gts_object_destroy (GTS_OBJECT (np));
-      np = tp;
-      dmin = d;
-    }
-    else
-      gts_object_destroy (GTS_OBJECT (tp));
-    i = i->next;
-  }
-  g_slist_free (list);
-
-  if (distance)
-    *distance = dmin;
-
-  return np;  
-}
-
-/**
- * gts_bb_tree_triangle_distance:
- * @tree: a bounding box tree.
- * @t: a #GtsTriangle.
- * @distance: a #GtsBBoxDistFunc.
- * @delta: spatial scale of the sampling to be used.
- * @range: a #GtsRange to be filled with the results.
- * 
- * Given a triangle @t, points are sampled regularly on its surface
- * using @delta as increment. The distance from each of these points
- * to the closest object of @tree is computed using @distance and the
- * gts_bb_tree_point_distance() function. The fields of @range are
- * filled with the number of points sampled, the minimum, average and
- * maximum value and the standard deviation.  
- */
-void gts_bb_tree_triangle_distance (GNode * tree,
-				    GtsTriangle * t,
-				    GtsBBoxDistFunc distance,
-				    gdouble delta,
-				    GtsRange * range)
-{
-  GtsPoint * p1, * p2, * p3, * p;
-  GtsVector p1p2, p1p3;
-  gdouble l1, t1, dt1;
-  guint i, n1;
-
-  g_return_if_fail (tree != NULL);
-  g_return_if_fail (t != NULL);
-  g_return_if_fail (distance != NULL);
-  g_return_if_fail (delta > 0.);
-  g_return_if_fail (range != NULL);
-
-  gts_triangle_vertices (t, 
-			 (GtsVertex **) &p1, 
-			 (GtsVertex **) &p2, 
-			 (GtsVertex **) &p3);
-
-  gts_vector_init (p1p2, p1, p2);
-  gts_vector_init (p1p3, p1, p3);
-  gts_range_init (range);
-  p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ())));
-
-  l1 = sqrt (gts_vector_scalar (p1p2, p1p2));
-  n1 = l1/delta + 1;
-  dt1 = 1.0/(gdouble) n1;
-  t1 = 0.0;
-  for (i = 0; i <= n1; i++, t1 += dt1) {
-    gdouble t2 = 1. - t1;
-    gdouble x = t2*p1p3[0];
-    gdouble y = t2*p1p3[1];
-    gdouble z = t2*p1p3[2];
-    gdouble l2 = sqrt (x*x + y*y + z*z);
-    guint j, n2 = (guint) (l2/delta + 1);
-    gdouble dt2 = t2/(gdouble) n2;
-
-    x = t2*p1->x + t1*p2->x;
-    y = t2*p1->y + t1*p2->y;
-    z = t2*p1->z + t1*p2->z;
-    
-    t2 = 0.0;
-    for (j = 0; j <= n2; j++, t2 += dt2) {
-      p->x = x + t2*p1p3[0];
-      p->y = y + t2*p1p3[1];
-      p->z = z + t2*p1p3[2];
-
-      gts_range_add_value (range,
-		    gts_bb_tree_point_distance (tree, p, distance, NULL));
-    }
-  }
-
-  gts_object_destroy (GTS_OBJECT (p));
-  gts_range_update (range);
-}
-
-/**
- * gts_bb_tree_segment_distance:
- * @tree: a bounding box tree.
- * @s: a #GtsSegment.
- * @distance: a #GtsBBoxDistFunc.
- * @delta: spatial scale of the sampling to be used.
- * @range: a #GtsRange to be filled with the results.
- * 
- * Given a segment @s, points are sampled regularly on its length
- * using @delta as increment. The distance from each of these points
- * to the closest object of @tree is computed using @distance and the
- * gts_bb_tree_point_distance() function. The fields of @range are
- * filled with the number of points sampled, the minimum, average and
- * maximum value and the standard deviation.  
- */
-void gts_bb_tree_segment_distance (GNode * tree,
-				   GtsSegment * s,
-				   gdouble (*distance) (GtsPoint *, 
-							gpointer),
-				   gdouble delta,
-				   GtsRange * range)
-{
-  GtsPoint * p1, * p2, * p;
-  GtsVector p1p2;
-  gdouble l, t, dt;
-  guint i, n;
-
-  g_return_if_fail (tree != NULL);
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (distance != NULL);
-  g_return_if_fail (delta > 0.);
-  g_return_if_fail (range != NULL);
-
-  p1 = GTS_POINT (s->v1);
-  p2 = GTS_POINT (s->v2);
-
-  gts_vector_init (p1p2, p1, p2);
-  gts_range_init (range);
-  p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class())));
-
-  l = sqrt (gts_vector_scalar (p1p2, p1p2));
-  n = (guint) (l/delta + 1);
-  dt = 1.0/(gdouble) n;
-  t = 0.0;
-  for (i = 0; i <= n; i++, t += dt) {
-    p->x = p1->x + t*p1p2[0];
-    p->y = p1->y + t*p1p2[1];
-    p->z = p1->z + t*p1p2[2];
-    
-    gts_range_add_value (range,
-			 gts_bb_tree_point_distance (tree, p, distance, NULL));
-  }
-
-  gts_object_destroy (GTS_OBJECT (p));
-  gts_range_update (range);
-}
-
-static void surface_distance_foreach_triangle (GtsTriangle * t, 
-					       gpointer * data)
-{
-  gdouble * delta = data[1];
-  GtsRange * range = data[2];
-  gdouble * total_area = data[3], area;
-  GtsRange range_triangle;
-
-  gts_bb_tree_triangle_distance (data[0], t, data[4], *delta, &range_triangle);
-
-  if (range_triangle.min < range->min)
-    range->min = range_triangle.min;
-  if (range_triangle.max > range->max)
-    range->max = range_triangle.max;
-  range->n += range_triangle.n;
-
-  area = gts_triangle_area (t);
-  *total_area += area;
-  range->sum += area*range_triangle.mean;
-  range->sum2 += area*range_triangle.mean*range_triangle.mean;
-}
-
-/**
- * gts_bb_tree_surface_distance:
- * @tree: a bounding box tree.
- * @s: a #GtsSurface.
- * @distance: a #GtsBBoxDistFunc.
- * @delta: a sampling increment defined as the percentage of the diagonal
- * of the root bounding box of @tree.
- * @range: a #GtsRange to be filled with the results.
- *
- * Calls gts_bb_tree_triangle_distance() for each face of @s. The
- * fields of @range are filled with the minimum, maximum and average
- * distance. The average distance is defined as the sum of the average
- * distances for each triangle weighthed by their area and divided by
- * the total area of the surface. The standard deviation is defined
- * accordingly. The @n field of @range is filled with the number of
- * sampled points used.  
- */
-void gts_bb_tree_surface_distance (GNode * tree,
-				   GtsSurface * s,
-				   GtsBBoxDistFunc distance,
-				   gdouble delta,
-				   GtsRange * range)
-{
-  gpointer data[5];
-  gdouble total_area = 0.;
-
-  g_return_if_fail (tree != NULL);
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (delta > 0. && delta < 1.);
-  g_return_if_fail (range != NULL);
-
-  gts_range_init (range);
-  delta *= sqrt (gts_bbox_diagonal2 (tree->data));
-  data[0] = tree;
-  data[1] = δ
-  data[2] = range;
-  data[3] = &total_area;
-  data[4] = distance;
-
-  gts_surface_foreach_face (s, 
-			    (GtsFunc) surface_distance_foreach_triangle, 
-			    data);
-
-  if (total_area > 0.) {
-    if (range->sum2 - range->sum*range->sum/total_area >= 0.)
-      range->stddev = sqrt ((range->sum2 - range->sum*range->sum/total_area)
-			    /total_area);
-    else
-      range->stddev = 0.;
-    range->mean = range->sum/total_area;
-  }
-  else
-    range->min = range->max = range->mean = range->stddev = 0.;
-}
-
-static void surface_distance_foreach_boundary (GtsEdge * e,
-					       gpointer * data)
-{
-  gdouble * delta = data[1];
-  GtsRange * range = data[2];
-  gdouble * total_length = data[3], length;
-  GtsRange range_edge;
-
-  if (gts_edge_is_boundary (e, NULL)) {
-    GtsSegment * s =  GTS_SEGMENT (e);
-
-    gts_bb_tree_segment_distance (data[0], s, data[4], *delta, &range_edge);
-
-    if (range_edge.min < range->min)
-      range->min = range_edge.min;
-    if (range_edge.max > range->max)
-      range->max = range_edge.max;
-    range->n += range_edge.n;
-    
-    length = gts_point_distance (GTS_POINT (s->v1), GTS_POINT (s->v2));
-    *total_length += length;
-    range->sum += length*range_edge.mean;
-    range->sum2 += length*range_edge.mean*range_edge.mean;
-  }
-}
-
-/**
- * gts_bb_tree_surface_boundary_distance:
- * @tree: a bounding box tree.
- * @s: a #GtsSurface.
- * @distance: a #GtsBBoxDistFunc.
- * @delta: a sampling increment defined as the percentage of the diagonal
- * of the root bounding box of @tree.
- * @range: a #GtsRange to be filled with the results.
- *
- * Calls gts_bb_tree_segment_distance() for each edge boundary of @s.
- * The fields of @range are filled with the minimum, maximum and
- * average distance. The average distance is defined as the sum of the
- * average distances for each boundary edge weighthed by their length
- * and divided by the total length of the boundaries. The standard
- * deviation is defined accordingly. The @n field of @range is filled
- * with the number of sampled points used.  
- */
-void gts_bb_tree_surface_boundary_distance (GNode * tree,
-					    GtsSurface * s,
-					    gdouble (*distance) (GtsPoint *,
-								 gpointer),
-					    gdouble delta,
-					    GtsRange * range)
-{
-  gpointer data[5];
-  gdouble total_length = 0.;
-
-  g_return_if_fail (tree != NULL);
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (delta > 0. && delta < 1.);
-  g_return_if_fail (range != NULL);
-
-  gts_range_init (range);
-  delta *= sqrt (gts_bbox_diagonal2 (tree->data));
-  data[0] = tree;
-  data[1] = δ
-  data[2] = range;
-  data[3] = &total_length;
-  data[4] = distance;
-
-  gts_surface_foreach_edge (s, 
-			    (GtsFunc) surface_distance_foreach_boundary, 
-			    data);
-
-  if (total_length > 0.) {
-    if (range->sum2 - range->sum*range->sum/total_length >= 0.)
-      range->stddev = sqrt ((range->sum2 - 
-			     range->sum*range->sum/total_length)
-			    /total_length);
-    else
-      range->stddev = 0.;
-    range->mean = range->sum/total_length;
-  }
-  else
-    range->min = range->max = range->mean = range->stddev = 0.;
-}
diff --git a/src_3rd/gts/boolean.c b/src_3rd/gts/boolean.c
deleted file mode 100644
index 79f3e0c..0000000
--- a/src_3rd/gts/boolean.c
+++ /dev/null
@@ -1,2048 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999--2002 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include "gts.h"
-
-/*#define DEBUG*/
-/*#define DEBUG_BOOLEAN*/
-/*#define CHECK_ORIENTED*/
-
-#ifdef DEBUG
-#  include "gts-private.h"
-#endif /* DEBUG */
-
-static void surface_inter_destroy (GtsObject * object)
-{
-  GtsSurfaceInter * si = GTS_SURFACE_INTER (object);
-
-  gts_object_destroy (GTS_OBJECT (si->s1));
-  gts_object_destroy (GTS_OBJECT (si->s2));
-  g_slist_free (si->edges);
-
-  (* GTS_OBJECT_CLASS (gts_surface_inter_class ())->parent_class->destroy)
-    (object);
-}
-
-static void surface_inter_class_init (GtsObjectClass * klass)
-{
-  klass->destroy = surface_inter_destroy;
-}
-
-static void surface_inter_init (GtsSurfaceInter * si)
-{
-  si->s1 = si->s2 = NULL;
-  si->edges = NULL;
-}
-
-/**
- * gts_surface_inter_class:
- *
- * Returns: the #GtsSurfaceInterClass.
- */
-GtsSurfaceInterClass * gts_surface_inter_class (void)
-{
-  static GtsSurfaceInterClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo surface_inter_info = {
-      "GtsSurfaceInter",
-      sizeof (GtsSurfaceInter),
-      sizeof (GtsSurfaceInterClass),
-      (GtsObjectClassInitFunc) surface_inter_class_init,
-      (GtsObjectInitFunc) surface_inter_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), &surface_inter_info);
-  }
-
-  return klass;
-}
-
-/* EdgeInter: Header */
-
-typedef struct _EdgeInter         EdgeInter;
-
-struct _EdgeInter {
-  GtsEdge parent;
-
-  GtsTriangle * t1, * t2;
-};
-
-#define EDGE_INTER(obj)            GTS_OBJECT_CAST (obj,\
-					         EdgeInter,\
-					         edge_inter_class ())
-#define IS_EDGE_INTER(obj)         (gts_object_is_from_class (obj,\
-						 edge_inter_class ()))
-
-static GtsEdgeClass * edge_inter_class  (void);
-static EdgeInter * edge_inter_new    (GtsVertex * v1, GtsVertex * v2,
-				      GtsTriangle * t1, GtsTriangle * t2);
-
-/* EdgeInter: Object */
-
-static GtsEdgeClass * edge_inter_class (void)
-{
-  static GtsEdgeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo edge_inter_info = {
-      "EdgeInter",
-      sizeof (EdgeInter),
-      sizeof (GtsEdgeClass),
-      (GtsObjectClassInitFunc) NULL,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_constraint_class ()),
-				  &edge_inter_info);
-  }
-
-  return klass;
-}
-
-static EdgeInter * edge_inter_new (GtsVertex * v1, GtsVertex * v2,
-				   GtsTriangle * t1, GtsTriangle * t2)
-{
-  EdgeInter * object;
-
-  object = EDGE_INTER (gts_edge_new (GTS_EDGE_CLASS (edge_inter_class ()), 
-				     v1, v2));
-  object->t1 = t1;
-  object->t2 = t2;
-
-  return object;
-}
-
-#ifdef DEBUG
-static void write_surface_graph (GtsSurface * s, FILE * fp)
-{
-  GSList * l = NULL;
-  GtsGraph * g;
-  static void add_to_list (gpointer data, GSList ** l) {
-    *l = g_slist_prepend (*l, data);
-  }
-
-  gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL);
-  gts_surface_foreach_edge (s, (GtsFunc) gts_object_reset_reserved, NULL);
-  gts_surface_foreach_edge (s, (GtsFunc) add_to_list, &l);
-  g = gts_segments_graph_new (gts_graph_class (), l);
-  gts_graph_write_dot (g, fp);
-  gts_object_destroy (GTS_OBJECT (g));
-  g_slist_free (l);
-}
-#endif /* DEBUG */
-
-static GtsPoint * segment_triangle_intersection (GtsSegment * s,
-						 GtsTriangle * t,
-						 GtsPointClass * klass)
-{
-  GtsPoint * A, * B, * C, * D, * E;
-  gint ABCE, ABCD, ADCE, ABDE, BCDE;
-  GtsEdge * AB, * BC, * CA;
-  gdouble a, b, c;
-
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (t != NULL, NULL);
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  gts_triangle_vertices_edges (t, NULL, 
-			       (GtsVertex **) &A, 
-			       (GtsVertex **) &B, 
-			       (GtsVertex **) &C, 
-			       &AB, &BC, &CA);
-  D = GTS_POINT (s->v1);
-  E = GTS_POINT (s->v2);
-
-  ABCE = gts_point_orientation_3d_sos (A, B, C, E);
-  ABCD = gts_point_orientation_3d_sos (A, B, C, D);
-  if (ABCE < 0 || ABCD > 0) {
-    GtsPoint * tmpp;
-    gint tmp;
-
-    tmpp = E; E = D; D = tmpp;
-    tmp = ABCE; ABCE = ABCD; ABCD = tmp;
-  }
-  if (ABCE < 0 || ABCD > 0)
-    return NULL;
-  ADCE = gts_point_orientation_3d_sos (A, D, C, E);
-  if (ADCE < 0)
-    return NULL;
-  ABDE = gts_point_orientation_3d_sos (A, B, D, E);
-  if (ABDE < 0)
-    return NULL;
-  BCDE = gts_point_orientation_3d_sos (B, C, D, E);
-  if (BCDE < 0)
-    return NULL;
-  a = gts_point_orientation_3d (A, B, C, E);
-  b = gts_point_orientation_3d (A, B, C, D);
-  if (a != b) {
-    c = a/(a - b);
-    return gts_point_new (klass,
-			  E->x + c*(D->x - E->x),
-			  E->y + c*(D->y - E->y),
-			  E->z + c*(D->z - E->z));
-  }
-  /* D and E are contained within ABC */
-#ifdef DEBUG
-  fprintf (stderr, 
-	   "segment: %p:%s triangle: %p:%s intersection\n"
-	   "D and E contained in ABC\n",
-	   s, GTS_NEDGE (s)->name, t, GTS_NFACE (t)->name);
-#endif /* DEBUG */  
-  g_assert (a == 0.); 
-  return gts_point_new (klass,
-			(E->x + D->x)/2.,
-			(E->y + D->y)/2.,
-			(E->z + D->z)/2.);
-}
-
-static gint triangle_triangle_orientation (GtsPoint * p1, 
-					   GtsPoint * p2, GtsPoint * p3,
-					   GtsPoint * p4, GtsPoint * p5,
-					   GtsPoint * p6)
-{
-  gint o4 = 0, o5 = 0, o6 = 0;
-
-  if (p4 != p1 && p4 != p2 && p4 != p3)
-    o4 = gts_point_orientation_3d_sos (p1, p2, p3, p4);
-  if (p5 != p1 && p5 != p2 && p5 != p3)
-    o5 = gts_point_orientation_3d_sos (p1, p2, p3, p5);
-  if (o4*o5 < 0)
-    return 0;
-  if (p6 != p1 && p6 != p2 && p6 != p3)
-    o6 = gts_point_orientation_3d_sos (p1, p2, p3, p6);
-  if (o4*o6 < 0 || o5*o6 < 0)
-    return 0;
-  if (o4) return o4;
-  if (o5) return o5;
-  g_assert (o6);
-  return o6;
-}
-
-static gint triangle_point_orientation (GtsTriangle * t1, 
-					GtsTriangle * t2,
-					gint o1,
-					GtsPoint * p)
-{
-  GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t1->e1)->v1);
-  GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (t1->e1)->v2);
-  GtsPoint * p3 = GTS_POINT (gts_triangle_vertex (t1));
-  GtsPoint * p4 = GTS_POINT (GTS_SEGMENT (t2->e1)->v1);
-  GtsPoint * p5 = GTS_POINT (GTS_SEGMENT (t2->e1)->v2);
-  GtsPoint * p6 = GTS_POINT (gts_triangle_vertex (t2));
-  gint o = triangle_triangle_orientation (p1, p2, p3, p4, p5, p6);
-
-  if (o != 0)
-    return o;
-  o = triangle_triangle_orientation (p4, p5, p6, p1, p2, p3);
-  if (o != 0) {
-    gint o2 = gts_point_orientation_3d_sos (p4, p5, p6, p);
-
-    return - o*o1*o2;
-  }
-  return 0;
-}
-
-static void add_edge_inter (GtsEdge * e,
-			    GtsTriangle * t,
-			    GtsVertex * v)
-{
-  GtsVertex * ev1 = GTS_SEGMENT (e)->v1, * ev2 = GTS_SEGMENT (e)->v2;
-  GList * i = GTS_OBJECT (e)->reserved;
-
-  GTS_OBJECT (v)->reserved = t;
-  if (i == NULL) {
-    GTS_OBJECT (e)->reserved = g_list_prepend (NULL, v);
-#ifdef DEBUG
-    fprintf (stderr, "add_edge_inter: inserting %p (%p,%p)\n", v, e, t);
-#endif /* DEBUG */
-  }
-  else {
-    GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
-    GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-    GtsPoint * p3 = GTS_POINT (gts_triangle_vertex (t));
-    gint o1, oref = gts_point_orientation_3d_sos (p1, p2, p3, GTS_POINT (ev1));
-    
-    o1 = oref;
-    while (i) {
-      gint o2 = triangle_point_orientation (t, GTS_OBJECT (i->data)->reserved,
-					    oref, GTS_POINT (ev1));
-
-      if (o2 == 0) {
-#ifdef DEBUG
-	g_warning ("add_edge_inter: safe sign evaluation failed\n");
-#endif /* DEBUG */
-	o2 = gts_point_orientation_3d_sos (p1, p2, p3, i->data);
-      }
-
-      if (o1*o2 < 0)
-	break;
-      ev1 = i->data;
-      o1 = o2;
-      i = i->next;
-    }
-    if (i != NULL) {
-      GList * n = g_list_prepend (NULL, v);
-
-      ev2 = i->data;
-      n->next = i;
-      n->prev = i->prev;
-      i->prev = n;
-      if (n->prev == NULL)
-	GTS_OBJECT (e)->reserved = n;
-      else
-	n->prev->next = n;
-    }
-    else {
-      g_assert (o1*gts_point_orientation_3d_sos (p1, p2, p3, GTS_POINT (ev2))
-		< 0);
-      GTS_OBJECT (e)->reserved = g_list_append (GTS_OBJECT (e)->reserved, v);
-    }
-#ifdef DEBUG
-    fprintf (stderr, 
-	     "add_edge_inter: inserting %p (%p,%p) between %p and %p\n", 
-	     v, e, t, ev1, ev2);
-    i = GTS_OBJECT (e)->reserved;
-    while (i) {
-      fprintf (stderr, " %p", i->data);
-      i = i->next;
-    }
-    fprintf (stderr, "\n");
-#endif /* DEBUG */
-  }
-}
-
-static GtsVertex * intersects (GtsEdge * e,
-			       GtsTriangle * t,
-			       GtsSurface * s)
-{
-  GList * i = GTS_OBJECT (e)->reserved;
-  GtsVertex * v;
-
-  while (i) {
-    if (GTS_OBJECT (i->data)->reserved == t)
-      return i->data;
-    i = i->next;
-  }
-
-  v = GTS_VERTEX (segment_triangle_intersection (GTS_SEGMENT (e), t, 
-				    GTS_POINT_CLASS (s->vertex_class)));
-  if (v != NULL) {
-#ifdef DEBUG
-    if (GTS_IS_NVERTEX (v) && GTS_IS_NEDGE (e) && GTS_IS_NFACE (t) &&
-	GTS_NVERTEX (v)->name[0] == '\0')
-      g_snprintf (GTS_NVERTEX (v)->name, GTS_NAME_LENGTH, "%s|%s",
-		  GTS_NEDGE (e)->name, GTS_NFACE (t)->name);
-#endif /* DEBUG */
-    if (s->vertex_class->intersection_attributes)
-      (*s->vertex_class->intersection_attributes)
-	(v, GTS_OBJECT (e), GTS_OBJECT (t));
-    add_edge_inter (e, t, v);
-  }
-  return v;
-}
-
-/* see figure misc/orientation.fig */
-static gint intersection_orientation (GtsTriangle * t1, 
-				      GtsEdge * e,
-				      GtsTriangle * t2)
-{
-  GtsVertex * v1, * v2, * v3;
-  GtsEdge * e2, * e3;
-  GtsVertex * v4, * v5, * v6;
-
-  gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e2, &e3);
-  gts_triangle_vertices (t2, &v4, &v5, &v6);
-
-  return gts_point_orientation_3d_sos (GTS_POINT (v4), 
-				       GTS_POINT (v5), 
-				       GTS_POINT (v6),
-				       GTS_POINT (v2));
-}
-
-#define UPDATE_ORIENTATION if (o > 0) { vi2 = v; /* e2 = e; */ } else { vi2 = vi1;\
-                                                                        /* e2 = e1; */\
-                                                                        vi1 = v;\
-                                                                        /* e1 = e; */ }
-
-static void intersect_edges (GtsBBox * bb1, GtsBBox * bb2,
-			     GtsSurfaceInter * si)
-{
-  GtsSurface * s1 = GTS_OBJECT (si->s1)->reserved;
-  GtsTriangle * t1 = GTS_TRIANGLE (bb1->bounded);
-  GtsTriangle * t2 = GTS_TRIANGLE (bb2->bounded);
-  GtsVertex * v, * vi1 = NULL, * vi2 = NULL;
-  //GtsEdge * e1 = NULL, * e2 = NULL, * e;
-
-  vi1 = intersects (t2->e1, t1, s1);
-  //e1 = t2->e1;
-  v = intersects (t2->e2, t1, s1);
-  //e = t2->e2;
-  if (!vi1) {
-    vi1 = v;
-    //e1 = e;
-  }
-  else if (v) {
-    gint o = intersection_orientation (t2, t2->e2, t1);
-    UPDATE_ORIENTATION;
-  }
-  if (!vi2) {
-    v = intersects (t2->e3, t1, s1);
-    //e = t2->e3;
-    if (!vi1) {
-      vi1 = v;
-      //e1 = e;
-    }
-    else if (v) {
-      gint o = intersection_orientation (t2, t2->e3, t1);
-      UPDATE_ORIENTATION;
-    }
-  }
-  if (!vi2) {
-    v = intersects (t1->e1, t2, s1);
-    //e = t1->e1;
-    if (!vi1) {
-      vi1 = v;
-      //e1 = e;
-    }
-    else if (v) {
-      gint o = - intersection_orientation (t1, t1->e1, t2);
-      UPDATE_ORIENTATION;
-    }
-  }
-  if (!vi2) {
-    v = intersects (t1->e2, t2, s1);
-    //e = t1->e2;
-    if (!vi1) {
-      vi1 = v;
-      //e1 = e;
-    }
-    else if (v) {
-      gint o = - intersection_orientation (t1, t1->e2, t2);
-      UPDATE_ORIENTATION;
-    }
-  }
-  if (!vi2) {
-    v = intersects (t1->e3, t2, s1);
-    //e = t1->e3;
-    if (!vi1) {
-      vi1 = v;
-      //e1 = e;
-    }
-    else if (v) {
-      gint o = - intersection_orientation (t1, t1->e3, t2);
-      UPDATE_ORIENTATION;
-    }
-  }
-
-  g_assert ((!vi1 && !vi2) || (vi1 && vi2));
-  if (vi1) {
-    GtsEdge * e = GTS_EDGE (edge_inter_new (vi1, vi2, t1, t2));
-
-#ifdef DEBUG
-    fprintf (stderr, "creating constraint %p: %p->%p: %p/%p\n", 
-	     e, vi1, vi2, t1, t2);
-#endif /* DEBUG */
-    gts_surface_add_face (si->s1, GTS_FACE (t1));
-    gts_surface_add_face (si->s2, GTS_FACE (t2));
-    si->edges = g_slist_prepend (si->edges, e);
-    GTS_OBJECT (t1)->reserved = g_slist_prepend (GTS_OBJECT (t1)->reserved, e);
-    GTS_OBJECT (t2)->reserved = g_slist_prepend (GTS_OBJECT (t2)->reserved, e);
-  }
-}
-
-static GtsSurfaceInter * surface_inter_new (GtsSurfaceInterClass * klass,
-					    GtsSurface * s1,
-					    GtsSurface * s2,
-					    GNode * faces_tree1,
-					    GNode * faces_tree2)
-{
-  GtsSurfaceInter * si;
-
-  si = GTS_SURFACE_INTER (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  si->s1 = gts_surface_new (gts_surface_class (),
-			    s1->face_class,
-			    s1->edge_class,
-			    s1->vertex_class);
-  GTS_OBJECT (si->s1)->reserved = s1;
-  si->s2 = gts_surface_new (gts_surface_class (),
-			    s2->face_class,
-			    s2->edge_class,
-			    s2->vertex_class);
-  GTS_OBJECT (si->s2)->reserved = s2;
-  gts_bb_tree_traverse_overlapping (faces_tree1, faces_tree2,
-				    (GtsBBTreeTraverseFunc) intersect_edges, 
-				    si);
-
-  return si;
-}
-
-static void free_slist (GtsObject * o)
-{
-  g_slist_free (o->reserved);
-  o->reserved = NULL;
-}
-
-static void free_glist (GtsObject * o)
-{
-  g_list_foreach (o->reserved, (GFunc) gts_object_reset_reserved, NULL);
-  g_list_free (o->reserved);
-  o->reserved = NULL;
-}
-
-/**
- * gts_surface_intersection:
- * @s1: a #GtsSurface.
- * @s2: a #GtsSurface.
- * @faces_tree1: a bounding box tree (see gts_bb_tree_new()) for
- * the faces of @s1.
- * @faces_tree2: a bounding box tree for the faces of @s2.
- *
- * Returns: a list of #GtsEdge defining the curve intersection of the
- * two surfaces.
- */
-GSList * gts_surface_intersection (GtsSurface * s1,
-				   GtsSurface * s2,
-				   GNode * faces_tree1,
-				   GNode * faces_tree2)
-{
-  GtsSurfaceInter * si;
-  GSList * inter;
-
-  g_return_val_if_fail (s1 != NULL, NULL);
-  g_return_val_if_fail (s2 != NULL, NULL);
-  g_return_val_if_fail (faces_tree1 != NULL, NULL);
-  g_return_val_if_fail (faces_tree2 != NULL, NULL);
-
-  si = surface_inter_new (gts_surface_inter_class (),
-			  s1, s2, faces_tree1, faces_tree2);
-
-  gts_surface_foreach_face (si->s1, (GtsFunc) free_slist, NULL);
-  gts_surface_foreach_face (si->s2, (GtsFunc) free_slist, NULL);
-  gts_surface_foreach_edge (si->s1, (GtsFunc) free_glist, NULL);
-  gts_surface_foreach_edge (si->s2, (GtsFunc) free_glist, NULL);
-  inter = si->edges;
-  si->edges = NULL;
-  gts_object_destroy (GTS_OBJECT (si));
-
-  return inter;  
-}
-
-typedef enum {
-  INTERIOR = 1 << (GTS_USER_FLAG),
-  RELEVANT = 1 << (GTS_USER_FLAG + 1)
-} CurveFlag;
-
-#define IS_SET(s, f) ((GTS_OBJECT_FLAGS (s) & (f)) != 0)
-#define SET(s, f)   (GTS_OBJECT_FLAGS (s) |= (f))
-#define UNSET(s, f) (GTS_OBJECT_FLAGS (s) &= ~(f))
-#define NEXT(s)  (GTS_OBJECT (s)->reserved)
-
-#ifdef DEBUG
-static void print_segment (GtsSegment * s)
-{
-  fprintf (stderr, "%p: %s->%s ", s,
-	   GTS_NVERTEX (s->v1)->name,
-	   GTS_NVERTEX (s->v2)->name);
-  if (NEXT (s)) {
-    GtsSegment * next = NEXT (s);
-
-    fprintf (stderr, "next %p: %s->%s\n", next,
-	     GTS_NVERTEX (next->v1)->name,
-	     GTS_NVERTEX (next->v2)->name);
-  }
-  else
-    fprintf (stderr, "next NULL\n");
-}
-
-static void write_nodes (GSList * i, GHashTable * hash, guint * nn,
-			 FILE * fp)
-{
-  while (i) {
-    GtsSegment * s = i->data;
-
-    if (!g_hash_table_lookup (hash, s->v1)) {
-      fprintf (fp, "  %u [ label = \"%p\" ];\n", *nn, s->v1);
-      g_hash_table_insert (hash, s->v1, GUINT_TO_POINTER ((*nn)++));
-    }
-    if (!g_hash_table_lookup (hash, s->v2)) {
-      fprintf (fp, "  %u [ label = \"%p\" ];\n", *nn, s->v2);
-      g_hash_table_insert (hash, s->v2, GUINT_TO_POINTER ((*nn)++));
-    }
-    i = i->next;
-  }
-}
-
-static void write_edges (GSList * i, GHashTable * hash, 
-			 GtsSurface * surface,
-			 FILE * fp)
-{
-  while (i) {
-    GtsSegment * s = i->data;
-
-    fprintf (fp, "  %u -> %u [ label = \"%p:%d\" ];\n",
-	     GPOINTER_TO_UINT (g_hash_table_lookup (hash, s->v1)),
-	     GPOINTER_TO_UINT (g_hash_table_lookup (hash, s->v2)),
-	     s,
-	     gts_edge_face_number (GTS_EDGE (s), surface));
-    i = i->next;
-  }
-}
-
-static void write_graph (GSList * boundary, GSList * interior,
-			 GtsSurface * surface,
-			 FILE * fp)
-{
-  GHashTable * hash = g_hash_table_new (NULL, NULL);
-  guint nn = 1;
-  
-  fprintf (fp, "digraph oriented_curve {\n");
-  write_nodes (boundary, hash, &nn, fp);
-  write_nodes (interior, hash, &nn, fp);
-  write_edges (boundary, hash, surface, fp);
-  fprintf (fp, "  edge [ color = red ];\n");
-  write_edges (interior, hash, surface, fp);
-  fprintf (fp, "}\n");
-  g_hash_table_destroy (hash);
-}
-
-static void write_graph1 (GtsSegment * start, GSList * i,
-			  GtsSurface * surface,
-			  FILE * fp)
-{
-  GSList * boundary = NULL, * interior = NULL;
-  GtsSegment * s = start;
-
-  do {
-    boundary = g_slist_prepend (boundary, s);
-    s = NEXT (s);
-  } while (s != start);
-  while (i) {
-    if (IS_SET (i->data, INTERIOR))
-      interior = g_slist_prepend (interior, i->data);
-    i = i->next;
-  }
-  write_graph (boundary, interior, surface, fp);
-  g_slist_free (boundary);
-  g_slist_free (interior);
-}
-
-static void print_loop (GtsSegment * start, FILE * fp)
-{
-  GtsSegment * s = start;
-
-  do {
-    fprintf (fp, "  %p: %p:%s -> %p:%s\n",
-	     s, 
-	     s->v1, GTS_NVERTEX (s->v1)->name, 
-	     s->v2, GTS_NVERTEX (s->v2)->name);
-    s = NEXT (s);
-  } while (s != start && s != NULL);
-}
-
-static void draw_vector (GtsPoint * p1, GtsPoint * p2, FILE * fp)
-{
-  gdouble x = p2->x - p1->x;
-  gdouble y = p2->y - p1->y;
-  gdouble z = p2->z - p1->z;
-
-  fprintf (fp, "VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n",
-	   p1->x + x - (x - y/2.)/5.,
-	   p1->y + y - (x/2. + y)/5.,
-	   p1->z + z - (x/2. + z)/5.,
-	   p1->x + x,
-	   p1->y + y,
-	   p1->z + z,
-	   p1->x + x - (x + y/2.)/5.,
-	   p1->y + y + (x/2. - y)/5.,
-	   p1->z + z + (x/2. - z)/5.);
-  fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n",
-	   p1->x, p1->y, p1->z,
-	   p1->x + x,
-	   p1->y + y,
-	   p1->z + z);
-}
-
-static void draw_vector1 (GtsPoint * p1, GtsPoint * p2, GtsPoint * o,
-			  FILE * fp)
-{
-  gdouble x1 = o->x + 0.9*(p1->x - o->x);
-  gdouble y1 = o->y + 0.9*(p1->y - o->y);
-  gdouble z1 = o->z + 0.9*(p1->z - o->z);
-  gdouble x2 = o->x + 0.9*(p2->x - o->x);
-  gdouble y2 = o->y + 0.9*(p2->y - o->y);
-  gdouble z2 = o->z + 0.9*(p2->z - o->z);
-  gdouble x = x2 - x1;
-  gdouble y = y2 - y1;
-  gdouble z = z2 - z1;
-
-  fprintf (fp, "VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n",
-	   x1 + x - (x - y/2.)/5.,
-	   y1 + y - (x/2. + y)/5.,
-	   z1 + z - (x/2. + z)/5.,
-	   x1 + x,
-	   y1 + y,
-	   z1 + z,
-	   x1 + x - (x + y/2.)/5.,
-	   y1 + y + (x/2. - y)/5.,
-	   z1 + z + (x/2. - z)/5.);
-  fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n",
-	   x1, y1, z1,
-	   x1 + x,
-	   y1 + y,
-	   z1 + z);
-}
-
-static void write_segments (GSList * boundary, GSList * interior,
-			    FILE * fp)
-{
-  GSList * i = boundary;
-
-  fprintf (fp, "LIST {\n");
-  while (i) {
-    GSList * inext = i->next;
-    GtsSegment * s = i->data;
-    GtsSegment * next = inext ? inext->data : boundary->data;
-    GtsVertex * v1, * v2;
-
-    if (s->v1 != next->v1 && s->v1 != next->v2) {
-      v1 = s->v1;
-      v2 = s->v2;
-    }
-    else {
-      v1 = s->v2;
-      v2 = s->v1;
-    }
-    draw_vector (GTS_POINT (v1), GTS_POINT (v2), fp);
-    i = inext;
-  }
-  i = interior;
-  while (i) {
-    GtsSegment * s = i->data;
-
-    draw_vector (GTS_POINT (s->v1), GTS_POINT (s->v2), fp);
-    i = i->next;
-  }
-  fprintf (fp, "}\n");
-}
-
-static void write_loops (GSList * i, FILE * fp)
-{
-  guint nl = 0;
-
-  while (i) {
-    GtsSegment * start = i->data, * s;
-    GtsPoint os;
-    guint n = 0;
-
-    fprintf (fp, "(geometry \"loop%d\" = LIST {\n", nl++);    
-
-    os.x = os.y = os.z = 0.;
-    s = start;
-    do {
-      GtsSegment * next = NEXT (s);
-      GtsPoint * p;
-      
-      if (s->v1 != next->v1 && s->v1 != next->v2)
-	p = GTS_POINT (s->v1);
-       else
-	 p = GTS_POINT (s->v2);
-      os.x += p->x; os.y += p->y; os.z += p->z; n++;
-      s = next;
-     } while (s != start);
-    os.x /= n; os.y /= n; os.z /= n;
-    
-    s = start;
-    do {
-      GtsSegment * next = NEXT (s);
-      
-      if (s->v1 != next->v1 && s->v1 != next->v2)
-	draw_vector1 (GTS_POINT (s->v1), GTS_POINT (s->v2), &os, fp);
-      else
-	 draw_vector1 (GTS_POINT (s->v2), GTS_POINT (s->v1), &os, fp);
-      s = next;
-    } while (s != start);
-    
-    fprintf (fp, "})\n");
-
-    i = i->next;
-  }
-}
-
-#define NAME(v) (GTS_IS_NVERTEX (v) ? GTS_NVERTEX (v)->name : "")
-#endif /* DEBUG */
-
-static GtsSegment * prev_flag (GtsSegment * s, CurveFlag flag)
-{
-  GSList * i = s->v1->segments;
-
-  while (i) {
-    if (i->data != s && IS_SET (i->data, flag))
-      return i->data;
-    i = i->next;
-  }
-  return NULL;
-}
-
-static GtsSegment * next_flag (GtsSegment * s, CurveFlag flag)
-{
-  GSList * i = s->v2->segments;
-
-  while (i) {
-    if (i->data != s && IS_SET (i->data, flag))
-      return i->data;
-    i = i->next;
-  }
-  return NULL;
-}
-
-static GtsSegment * next_interior (GtsVertex * v)
-{
-  GSList * i = v->segments;
-
-  while (i) {
-    GtsSegment * s = i->data;
-
-    if (s->v1 == v && IS_SET (s, INTERIOR))
-      return s;
-    i = i->next;
-  }
-  return NULL;
-}
-
-static GtsSegment * prev_interior (GtsVertex * v)
-{
-  GSList * i = v->segments;
-
-  while (i) {
-    GtsSegment * s = i->data;
-
-    if (s->v2 == v && IS_SET (s, INTERIOR))
-      return s;
-    i = i->next;
-  }
-  return NULL;
-}
-
-static GtsSegment * reverse (GtsSegment * start,
-			     gboolean interior,
-			     gboolean * isloop)
-{
-  GtsSegment * s = start, * prev = NULL, * rprev = NULL;
-  GtsSegment * rstart = NULL, * rstart1 = NULL;
-
-  do {
-    GtsSegment * rs;
-
-    g_assert (IS_EDGE_INTER (s));
-    rs = GTS_SEGMENT (edge_inter_new (s->v2, s->v1,
-				      EDGE_INTER (s)->t1, EDGE_INTER (s)->t2));
-
-    if (rstart == NULL)
-      rstart = rs;
-    else if (rstart1 == NULL)
-      rstart1 = rs;
-    if (interior)
-      SET (rs, INTERIOR);
-    NEXT (rs) = rprev;
-    rprev = rs;
-    prev = s;
-    s = NEXT (s);
-  } while (s != NULL && s != start);
-  if (s == start) {
-    NEXT (rstart) = rprev;
-    *isloop = TRUE;
-  }
-  else {
-    NEXT (rstart) = start;
-    NEXT (prev) = rprev;
-    *isloop = FALSE;
-  }    
-  return rstart1;
-}
-
-static GSList * interior_loops (GSList * interior)
-{
-  GSList * i = interior;
-  GSList * loops = NULL;
-
-  i = interior;
-  while (i) {
-    GtsSegment * s = i->data;
-
-    if (IS_SET (s, RELEVANT)) {
-      GtsSegment * start = s, * end;
-
-      do {
-	GtsSegment * next = next_flag (s, INTERIOR);
-
-	UNSET (s, RELEVANT);
-	end = s; 
-	s = NEXT (s) = next;
-      } while (s != NULL && s != start);
-
-      if (s == start)
-	loops = g_slist_prepend (loops, start);
-      else {
-	GtsSegment * next, * prev;
-	gboolean isloop;
-
-	s = prev_flag (start, INTERIOR);
-	while (s) {
-	  UNSET (s, RELEVANT);
-	  NEXT (s) = start;
-	  start = s;
-	  s = prev_flag (s, INTERIOR);
-	}
-	next = next_flag (end, RELEVANT);
-	prev = prev_flag (start, RELEVANT);
-	if (prev != NULL)
-	  SET (start->v1, INTERIOR);
-	if (next != NULL)
-	  SET (end->v2, INTERIOR);
-	if (next == NULL && prev == NULL)
-	  loops = g_slist_prepend (loops, start);
-	else
-	  reverse (start, TRUE, &isloop);
-      }
-    }
-    i = i->next;
-  }
-  return loops;
-}
-
-#define ORIENTATION(p1,p2,p3,o) (gts_point_orientation_3d (p1, p2, o, p3))
-#define ORIENTATION_SOS(p1,p2,p3,o) (gts_point_orientation_3d_sos (p1, p2, o, p3))
-
-#define ORIENTED_VERTICES(s,next,w1,w2) {\
-  if ((s)->v1 == (next)->v1 || (s)->v1 == (next)->v2) {\
-    w1 = (s)->v2;\
-    w2 = (s)->v1;\
-  }\
-  else {\
-    w1 = (s)->v1;\
-    w2 = (s)->v2;\
-  }\
-}
-
-#if 0
-static GtsSegment * segment_intersects (GtsPoint * p1, GtsPoint * p2,
-					GSList * i,
-					GtsPoint * o)
-{
-  while (i) {
-    GtsSegment * s = i->data;
-    GtsPoint * p3 = GTS_POINT (s->v1);
-    GtsPoint * p4 = GTS_POINT (s->v2);
-
-    if (p3 != p1 && p3 != p2 && p4 != p1 && p4 != p2) {
-      gdouble o1 = ORIENTATION (p3, p4, p1, o);
-      gdouble o2 = ORIENTATION (p3, p4, p2, o);
-
-      if ((o1 < 0. && o2 > 0.) || (o1 > 0. && o2 < 0.)) {
-	o1 = ORIENTATION (p1, p2, p3, o);
-	o2 = ORIENTATION (p1, p2, p4, o);
-
-	if ((o1 <= 0. && o2 >= 0.) || (o1 >= 0. && o2 <= 0.))
-	  return s;
-      }
-    }
-    i = i->next;
-  }
-  return NULL;
-}
-#else
-static GtsSegment * segment_intersects (GtsPoint * p1, GtsPoint * p2,
-					GSList * i,
-					GtsPoint * o)
-{
-  while (i) {
-    GtsSegment * s = i->data;
-    GtsPoint * p3 = GTS_POINT (s->v1);
-    GtsPoint * p4 = GTS_POINT (s->v2);
-
-    if (p3 != p1 && p3 != p2 && p4 != p1 && p4 != p2) {
-      gint o1 = ORIENTATION_SOS (p3, p4, p1, o);
-      gint o2 = ORIENTATION_SOS (p3, p4, p2, o);
-
-      if (o1*o2 < 0) {
-	o1 = ORIENTATION_SOS (p1, p2, p3, o);
-	o2 = ORIENTATION_SOS (p1, p2, p4, o);
-
-	if (o1*o2 < 0)
-	  return s;
-      }
-    }
-    i = i->next;
-  }
-  return NULL;
-}
-#endif
-
-static gboolean is_inside_wedge (GtsSegment * s1, GtsSegment * s2,
-				 GtsPoint * p, GtsPoint * o)
-{
-  GtsVertex * v1, * v2, * v3;
-
-  ORIENTED_VERTICES (s1, s2, v1, v2);
-  v3 = s2->v1 != v2 ? s2->v1 : s2->v2;
-
-  if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), 
-		   GTS_POINT (v3), o) >= 0.) {
-    if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), p, o) <= 0. ||
-	ORIENTATION (GTS_POINT (v2), GTS_POINT (v3), p, o) <= 0.)
-      return FALSE;
-  }
-  else if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), p, o) <= 0. &&
-	   ORIENTATION (GTS_POINT (v2), GTS_POINT (v3), p, o) <= 0.)
-    return FALSE;
-  return TRUE;
-}
-
-static GtsSegment * connection (GtsPoint * p, 
-				GSList * interior,
-				GSList * bloops,
-				GtsPoint * o)
-{
-  while (bloops) {
-    GtsSegment * start = bloops->data, * s = start;
-
-    do {
-      GtsSegment * next = NEXT (s);
-      GtsVertex * v2 = s->v1 == next->v1 || s->v1 == next->v2 ? s->v1 : s->v2;
-
-      if (is_inside_wedge (s, next, p, o) &&
-	  !segment_intersects (p, GTS_POINT (v2), interior, o))
-	return s;
-      s = next;
-    } while (s != start);
-    bloops = bloops->next;
-  }
-  return NULL;
-}
-
-static gdouble loop_orientation (GtsSegment * start,
-				 GtsPoint * p, GtsPoint * o)
-{
-  GtsSegment * s = start;
-  gdouble or = 0.;
-
-  do {
-    GtsSegment * next = NEXT (s);
-    GtsVertex * v1, * v2;
-
-    ORIENTED_VERTICES (s, next, v1, v2);
-    or += ORIENTATION (p, GTS_POINT (v1), GTS_POINT (v2), o);
-    s = next;
-  } while (s != start);
-
-#ifdef DEBUG
-  fprintf (stderr, "loop orientation: %g\n", or);
-#endif /* DEBUG */
-
-  return or;
-}
-
-static void connect_interior_loop (GtsSegment * start,
-				   GSList ** interior,
-				   GSList ** bloops,
-				   GtsSurface * surface,
-				   GtsPoint * o)
-{
-  GtsSegment * s = start, * c = NULL, * next, * s1, * rs1, * rs;
-  GtsVertex * v, * cv;
-  gboolean isloop;
-
-  do {
-    if (!(c = connection (GTS_POINT (s->v2), *interior, *bloops, o)))
-      s = NEXT (s);
-  } while (s != start && !c);
-  g_assert (c);
-  next = NEXT (c);
-  v = c->v1 == next->v1 || c->v1 == next->v2 ? c->v1 : c->v2;
-  cv = s->v2;
-#ifdef DEBUG
-  fprintf (stderr, "connecting %p:%s with %p:%s\n", 
-	   cv, NAME (cv), v, NAME (v));
-  fprintf (stderr, "  c: %p: %p:%s %p:%s\n", c, 
-	   c->v1, NAME (c->v1),
-	   c->v2, NAME (c->v2));
-  fprintf (stderr, "  next: %p: %p:%s %p:%s\n", next,
-	   next->v1, NAME (next->v1),
-	   next->v2, NAME (next->v2));
-#endif /* DEBUG */
-  rs = reverse (s, FALSE, &isloop);
-  if (isloop) {
-    if (loop_orientation (rs, GTS_POINT (v), o) < 0.) {
-      GtsSegment * tmp = s;
-      s = rs;
-      rs = tmp;
-    }
-    *bloops = g_slist_prepend (*bloops, rs);
-  }
-  s1 = GTS_SEGMENT (gts_edge_new (surface->edge_class, v, cv));
-  rs1 = GTS_SEGMENT (gts_edge_new (surface->edge_class, cv, v));
-  NEXT (c) = s1;
-  NEXT (rs1) = next;
-  *interior = g_slist_prepend (*interior, s1);
-  NEXT (s1) = NEXT (s);
-  NEXT (s) = rs1;
-}
-
-static GSList * boundary_loops (GSList * boundary)
-{
-  GSList * i = boundary;  
-  GtsSegment * start = i->data;
-  GSList * loops = NULL;
-
-  while (i) {
-    GtsSegment * s = i->data;
-    GSList * inext = i->next;
-    GtsSegment * next = inext ? inext->data : start;
-    GtsVertex * v = s->v1 == next->v1 || s->v1 == next->v2 ? s->v1 : s->v2;
-
-    if (IS_SET (v, INTERIOR)) {
-      GtsSegment * intprev = prev_interior (v);
-
-      NEXT (intprev) = next;
-      NEXT (s) = next_interior (v);
-      UNSET (v, INTERIOR);
-    }
-    else
-      NEXT (s) = next;
-    i = inext;
-  }
-
-  i = boundary;
-  while (i) {
-    start = i->data;
-    
-    if (IS_SET (start, RELEVANT)) {
-      GtsSegment * s = start;
-
-      do {
-	UNSET (s, RELEVANT);
-	UNSET (s, INTERIOR);
-	s = NEXT (s);
-      } while (s != start);
-      loops = g_slist_prepend (loops, start);
-    }
-    i = i->next;
-  }
-
-  return loops;
-}
-
-typedef struct _Ear    Ear;
-
-struct _Ear {
-  GtsVertex * v1, * v2, * v3;
-  GtsSegment * s1, * s2, * s3;
-};
-
-static gboolean point_in_wedge (GtsPoint * p1, GtsPoint * p2, GtsPoint * p3,
-				GtsPoint * p, gboolean closed, GtsPoint * o)
-{
-  gdouble o1;
-
-  if (p == p2 || p == p3)
-    return FALSE;
-  o1 = ORIENTATION (p1, p2, p, o);
-  if ((closed && o1 < 0.) || (!closed && o1 <= 0.)) return FALSE;
-  o1 = ORIENTATION (p3, p1, p, o);
-  if ((closed && o1 < 0.) || (!closed && o1 <= 0.)) return FALSE;
-  return TRUE;
-}
-
-#if 0
-static gboolean segment_intersects1 (GtsPoint * p1, GtsPoint * p2, 
-				     GtsPoint * p3, GtsPoint * p4,
-				     gboolean closed, GtsPoint * o)
-{
-  gdouble o1 = ORIENTATION (p3, p4, p1, o);
-  gdouble o2 = ORIENTATION (p3, p4, p2, o);
-  gdouble o3, o4;
-
-  if ((closed && ((o1 > 0. && o2 > 0.) || (o1 < 0. && o2 < 0.))) ||
-      (!closed && ((o1 >= 0. && o2 >= 0.) || (o1 <= 0. && o2 <= 0.))))
-    return FALSE;
-  o3 = ORIENTATION (p1, p2, p3, o);
-  o4 = ORIENTATION (p1, p2, p4, o);
-  if ((o3 > 0. && o4 > 0.) || (o3 < 0. && o4 < 0.))
-    return FALSE;
-  if (closed) return TRUE;
-  if ((o3 == 0. && o4 > 0.) || (o4 == 0. && o3 > 0.))
-    return TRUE;
-  return FALSE;
-}
-#else
-static gboolean segment_intersects1 (GtsPoint * p1, GtsPoint * p2, 
-				     GtsPoint * p3, GtsPoint * p4,
-				     gboolean closed, GtsPoint * o)
-{
-  gint o1, o2;
-
-  o1 = ORIENTATION_SOS (p3, p4, p1, o);
-  o2 = ORIENTATION_SOS (p3, p4, p2, o);
-  if (o1*o2 > 0)
-    return FALSE;
-  o1 = ORIENTATION_SOS (p1, p2, p3, o);
-  o2 = ORIENTATION_SOS (p1, p2, p4, o);
-  if (o1*o2 > 0)
-    return FALSE;
-  return TRUE;
-}
-#endif
-
-static GtsSegment * triangle_intersects_segments (GtsPoint * p1,
-						  GtsPoint * p2,
-						  GtsPoint * p3,
-						  gboolean closed,
-						  GtsSegment * start,
-						  GtsPoint * o)
-{
-  GtsSegment * s = start;
-
-  do {
-    GtsPoint * p4 = GTS_POINT (s->v1);
-    GtsPoint * p5 = GTS_POINT (s->v2);
-
-    if (p4 == p1) {
-      if (point_in_wedge (p1, p2, p3, p5, closed, o))
-	return s;
-    }
-    else if (p4 == p2) {
-      if (point_in_wedge (p2, p3, p1, p5, closed, o))
-	return s;
-    }
-    else if (p4 == p3) {
-      if (point_in_wedge (p3, p1, p2, p5, closed, o))
-	return s;
-    }
-    else if (p5 == p1) {
-      if (point_in_wedge (p1, p2, p3, p4, closed, o))
-	return s;
-    }
-    else if (p5 == p2) {
-      if (point_in_wedge (p2, p3, p1, p4, closed, o))
-	return s;
-    }
-    else if (p5 == p3) {
-      if (point_in_wedge (p3, p1, p2, p4, closed, o))
-	return s;
-    }
-    else if (segment_intersects1 (p1, p2, p4, p5, closed, o) ||
-	     segment_intersects1 (p2, p3, p4, p5, closed, o) ||
-	     segment_intersects1 (p3, p1, p4, p5, closed, o))
-      return s;
-    s = NEXT (s);
-  } while (s != start);
-  return NULL;
-}
-
-static gboolean new_ear (GtsSegment * s, 
-			 Ear * e, 
-			 GtsSegment * start,
-			 guint sloppy,
-			 GtsPoint * o)
-{
-  gdouble or;
-
-  e->s1 = s;
-  e->s2 = NEXT (s);
-
-  g_return_val_if_fail (e->s2, FALSE);
-  g_return_val_if_fail (e->s2 != e->s1, FALSE);
-
-  ORIENTED_VERTICES (e->s1, e->s2, e->v1, e->v2);
-  e->v3 = e->s2->v1 != e->v2 ? e->s2->v1 : e->s2->v2;
-  if (e->v3 == e->v1)
-    return FALSE;
-  e->s3 = NEXT (e->s2);
-  if (gts_segment_connect (e->s3, e->v1, e->v3)) {
-    if (NEXT (e->s3) != e->s1)
-      return FALSE;
-  }
-  else if (gts_vertices_are_connected (e->v1, e->v3))
-    return FALSE;
-  else
-    e->s3 = NULL;
-  or = ORIENTATION (GTS_POINT (e->v1), GTS_POINT (e->v2), GTS_POINT (e->v3),o);
-  switch (sloppy) {
-  case 0: 
-    if (or <= 0. ||
-	triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2),
-				      GTS_POINT (e->v3), TRUE, start, o))
-      return FALSE;
-    break;
-  case 1:
-    if (or < 0. || 
-	(or > 0. && 
-	 triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2),
-				       GTS_POINT (e->v3), FALSE, start, o)))
-      return FALSE;
-    break;
-  case 2:
-    if ((or > 0. && 
-	 triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2),
-				       GTS_POINT (e->v3), FALSE, start, o)) ||
-	(or < 0. && 
-	 triangle_intersects_segments (GTS_POINT (e->v2), GTS_POINT (e->v1),
-				       GTS_POINT (e->v3), FALSE, start, o)))
-      return FALSE;
-    break;
-  case 3:
-    if (or < 0.)
-      return FALSE;
-    break;
-  }
-#ifdef DEBUG
-  if (or <= 0.)
-    fprintf (stderr, "or: %g\n", or);
-#endif /* DEBUG */
-  g_assert (or > -1e-6);
-  return TRUE;
-}
-
-static void triangulate_loop (GtsSegment * start,
-			      GtsSurface * surface,
-			      GtsPoint * o)
-{
-  GtsSegment * prev = start, * s;
-  guint sloppy = 0;
-#ifdef DEBUG
-  guint nt = 0;
-#endif /* DEBUG */
-
-  s = NEXT (start);
-  while (NEXT (s) != s) {
-    GtsSegment * next = NEXT (s);
-    Ear e;
-
-#ifdef DEBUG
-    fprintf (stderr, "prev: %p s: %p next: %p\n", prev, s, next);
-#endif /* DEBUG */
-  
-    if (!new_ear (s, &e, start, sloppy, o)) {
-      if (s == start) {
-	sloppy++;
-#ifdef DEBUG
-	fprintf (stderr, "sloppy: %u\n", sloppy);
-#endif /* DEBUG */
-      }
-      prev = s;
-      s = next;
-    }
-    else {
-      GtsFace * f;
-
-      if (!GTS_IS_EDGE (e.s3))
-	e.s3 = GTS_SEGMENT (gts_edge_new (surface->edge_class, e.v1, e.v3));
-      f = gts_face_new (surface->face_class, 
-			GTS_EDGE (e.s1), GTS_EDGE (e.s2), GTS_EDGE (e.s3));
-      gts_surface_add_face (surface, f);
-      UNSET (e.s1, RELEVANT);
-      UNSET (e.s1, INTERIOR);
-      UNSET (e.s2, RELEVANT);
-      UNSET (e.s2, INTERIOR);
-      NEXT (prev) = e.s3;
-      NEXT (e.s3) = NEXT (e.s2);
-      NEXT (e.s1) = NEXT (e.s2) = NULL;
-      start = prev;
-      s = NEXT (prev);
-      sloppy = 0;
-#ifdef DEBUG
-      {
-	gchar name[80];
-	FILE * fp;
-	
-	fprintf (stderr, " t.%u: (%p:%s,%p:%s,%p:%s)\n",
-		 nt, 
-		 e.v1, NAME (e.v1),
-		 e.v2, NAME (e.v2),
-		 e.v3, NAME (e.v3));
-	sprintf (name, "/tmp/t.%u", nt++);
-	fp = fopen (name, "wt");
-	//	gts_surface_write (surface, fp);
-	gts_write_triangle (GTS_TRIANGLE (f), NULL, fp);
-	//	  write_graph1 (start, interior, surface, fp);
-	fclose (fp);
-	print_loop (start, stderr);
-      }
-#endif /* DEBUG */
-    }
-  }
-  UNSET (s, RELEVANT);
-  UNSET (s, INTERIOR);
-  NEXT (s) = NULL;
-}
-
-#ifdef CHECK_ORIENTED
-static void check_object (GtsObject * o)
-{
-  g_assert (o->reserved == NULL);
-  g_assert (o->flags == 0);  
-}
-
-static void check_boundary (GtsEdge * e, GtsSurface * s)
-{
-  check_object (GTS_OBJECT (e));
-  check_object (GTS_OBJECT (GTS_SEGMENT (e)->v1));
-  check_object (GTS_OBJECT (GTS_SEGMENT (e)->v2));
-  g_assert (gts_edge_face_number (e, s) == 1);
-}
-
-static void check_interior (GtsEdge * e, GtsSurface * s)
-{
-  guint n;
-  check_object (GTS_OBJECT (e));
-  check_object (GTS_OBJECT (GTS_SEGMENT (e)->v1));
-  check_object (GTS_OBJECT (GTS_SEGMENT (e)->v2));
-
-  n = gts_edge_face_number (e, s);
-#ifdef DEBUG
-  if (n != 2)
-    gts_surface_print_stats (s, stderr);
-#endif /* DEBUG */
-  g_assert (n == 2);
-}
-
-static void check_boundary_interior_triangulation (GSList * boundary,
-						   GSList * interior,
-						   GtsSurface * surface)
-{
-  g_slist_foreach (boundary, (GFunc) check_boundary, surface);
-  g_slist_foreach (interior, (GFunc) check_interior, surface);
-}
-#endif /*ifdef CHECK_ORIENTED */
-
-static void merge_duplicate (GtsEdge * e)
-{
-  GtsEdge * dup = gts_edge_is_duplicate (e);
-
-  g_assert (dup);
-  gts_edge_replace (dup, e);
-  gts_object_destroy (GTS_OBJECT (dup));
-}
-
-static void triangulate_boundary_interior (GSList * boundary, 
-					   GSList * interior,
-					   GtsSurface * s,
-					   GtsPoint * o)
-{
-  GSList * iloops, * bloops, * i;
-
-  i = boundary;
-  while (i) {
-    SET (i->data, RELEVANT);
-    i = i->next;
-  }
-  i = interior;
-  while (i) {
-    SET (i->data, RELEVANT);
-    SET (i->data, INTERIOR);
-    i = i->next;
-  }
-
-  iloops = interior_loops (interior);
-  bloops = boundary_loops (boundary);
-
-  i = iloops;
-  while (i) {
-#ifdef DEBUG
-    fprintf (stderr, "--- interior loop ---\n");
-    print_loop (i->data, stderr);
-#endif /* DEBUG */
-    connect_interior_loop (i->data, &interior, &bloops, s, o);
-    i = i->next;
-  }
-  
-#ifdef DEBUG
- {
-   FILE * fp = fopen ("/tmp/bloops", "w");
-   write_loops (bloops, fp);
-   fclose (fp);
- }
-#endif /* DEBUG */
-
-  i = bloops;
-  while (i) {
-#ifdef DEBUG
-    fprintf (stderr, "--- boundary loop ---\n");
-    print_loop (i->data, stderr);
-#endif /* DEBUG */
-    triangulate_loop (i->data, s, o);
-    i = i->next;
-  }
-  
-  g_slist_foreach (interior, (GFunc) merge_duplicate, NULL);
-  g_slist_free (iloops);
-  g_slist_free (bloops);
-
-#ifdef CHECK_ORIENTED
-  check_boundary_interior_triangulation (boundary, interior, s);
-#endif /* CHECK_ORIENTED */
-}
-
-static void create_edges (GtsSegment * s, GtsSurface * surface)
-{
-  if (GTS_OBJECT (s)->reserved) {
-    GList * i = GTS_OBJECT (s)->reserved;
-    GtsVertex * v1 = i->data;
-
-    GTS_OBJECT (s)->reserved = g_list_prepend (i, 
-		      gts_edge_new (surface->edge_class, s->v1, v1));
-    while (i) {
-      GList * next = i->next;
-      GtsVertex * v2 = next ? next->data : s->v2;
-
-      GTS_OBJECT (i->data)->reserved = NULL;
-      i->data = gts_edge_new (surface->edge_class, v1, v2);
-      v1 = v2;
-      i = next;
-    }
-  }
-}
-
-static void add_boundary (GtsSegment * s, GtsSegment * next, 
-			  GSList ** boundary)
-{
-  if (GTS_OBJECT (s)->reserved == NULL)
-    *boundary = g_slist_prepend (*boundary, s);
-  else {
-    if (s->v2 == next->v2 || s->v2 == next->v1) {
-      GList * i = g_list_last (GTS_OBJECT (s)->reserved);
-
-      while (i) {
-	*boundary = g_slist_prepend (*boundary, i->data);
-	i = i->prev;
-      }
-    }
-    else {
-      GList * i = GTS_OBJECT (s)->reserved;
-
-      while (i) {
-	*boundary = g_slist_prepend (*boundary, i->data);
-	i = i->next;
-      }
-    }
-  }
-}
-
-static void triangulate_face (GtsTriangle * t, GtsSurface * surface)
-{
-  GSList * interior = GTS_OBJECT (t)->reserved;
-  GSList * boundary = NULL;
-  GtsSurface * s = gts_surface_new (gts_surface_class (),
-				    surface->face_class,
-				    surface->edge_class,
-				    surface->vertex_class);
-  gdouble x, y, z;
-  GtsPoint * p = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
-  GtsPoint * o;
-
-  GTS_OBJECT (t)->reserved = NULL;  
-  gts_triangle_normal (t, &x, &y, &z);
-  g_assert (x != 0. || y != 0. || z != 0.);
-  o = gts_point_new (gts_point_class (), p->x + x, p->y + y, p->z + z);
-  add_boundary (GTS_SEGMENT (t->e3), GTS_SEGMENT (t->e1), &boundary);
-  add_boundary (GTS_SEGMENT (t->e2), GTS_SEGMENT (t->e3), &boundary);
-  add_boundary (GTS_SEGMENT (t->e1), GTS_SEGMENT (t->e2), &boundary);
-#ifdef DEBUG
-  {
-    static guint nt = 0;
-    char name[80];
-    FILE * fp;
-
-    fprintf (stderr, "%u: triangulating %p\n", nt, t);
-if (nt == 28)
-  fprintf (stderr, "tintin!!!!\n");
-    sprintf (name, "/tmp/oc.%u", nt++);
-    fp = fopen (name, "wt");
-    //    write_graph (boundary, interior, s, fp);
-    write_segments (boundary, interior, fp);
-    fclose (fp);
-  }
-#endif /* DEBUG */
-  triangulate_boundary_interior (boundary, interior, s, o);
-  g_slist_free (interior);
-  g_slist_free (boundary);
-  if (GTS_OBJECT (t)->klass->attributes)
-    gts_surface_foreach_face (s, (GtsFunc) gts_object_attributes, t);
-  gts_surface_merge (surface, s);
-  gts_object_destroy (GTS_OBJECT (s));
-  gts_object_destroy (GTS_OBJECT (o));
-}
-
-static void free_edge_list (GtsObject * o)
-{
-  g_list_free (o->reserved);
-  o->reserved = NULL;
-}
-
-/**
- * gts_surface_inter_new:
- * @klass: a #GtsSurfaceInterClass.
- * @s1: a #GtsSurface.
- * @s2: a #GtsSurface.
- * @faces_tree1: a bounding box tree (see gts_bb_tree_new()) for
- * the faces of @s1.
- * @faces_tree2: a bounding box tree for the faces of @s2.
- * @is_open1: whether @s1 is an "open" surface.
- * @is_open2: whether @s2 is an "open" surface.
- *
- * When triangulating the cut faces, the new faces inherit the
- * attributes of these original faces through their attributes()
- * method.
- *
- * Returns: a new #GtsSurfaceInter describing the intersection of @s1
- * and @s2.  
- */
-GtsSurfaceInter * gts_surface_inter_new (GtsSurfaceInterClass * klass,
-					 GtsSurface * s1,
-					 GtsSurface * s2,
-					 GNode * faces_tree1,
-					 GNode * faces_tree2,
-					 gboolean is_open1,
-					 gboolean is_open2)
-{
-  GtsSurfaceInter * si;
-  GtsSurface * s;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (s1 != NULL, NULL);
-  g_return_val_if_fail (s2 != NULL, NULL);
-  g_return_val_if_fail (faces_tree1 != NULL, NULL);
-  g_return_val_if_fail (faces_tree2 != NULL, NULL);
-
-  si = surface_inter_new (klass, s1, s2, faces_tree1, faces_tree2);
-
-  gts_surface_foreach_edge (si->s1, (GtsFunc) create_edges, si->s1);
-  gts_surface_foreach_edge (si->s2, (GtsFunc) create_edges, si->s2);
-
-#ifdef DEBUG
-  fprintf (stderr, "====== triangulating s1 ======\n");
-#endif /* DEBUG */
-  s = gts_surface_new (gts_surface_class (),
-		       s1->face_class,
-		       s1->edge_class,
-		       s1->vertex_class);
-  gts_surface_foreach_face (si->s1, (GtsFunc) triangulate_face, s);
-  gts_surface_foreach_edge (si->s1, (GtsFunc) free_edge_list, NULL);
-  gts_object_destroy (GTS_OBJECT (si->s1));
-  si->s1 = s;
-  GTS_OBJECT (si->s1)->reserved = s1;
-  
-#ifdef DEBUG
-  fprintf (stderr, "====== triangulating s2 ======\n");
-#endif /* DEBUG */
-  s = gts_surface_new (gts_surface_class (),
-		       s2->face_class,
-		       s2->edge_class,
-		       s2->vertex_class);
-  gts_surface_foreach_face (si->s2, (GtsFunc) triangulate_face, s);
-  gts_surface_foreach_edge (si->s2, (GtsFunc) free_edge_list, NULL);
-  gts_object_destroy (GTS_OBJECT (si->s2));
-  si->s2 = s;
-  GTS_OBJECT (si->s2)->reserved = s2;
-
-  return si;
-}
-
-static void check_surface_edge (GtsEdge * e, gpointer * data)
-{
-  gboolean * ok = data[0];
-  GtsSurface * s = data[1];
-  GtsSurface * bs = GTS_OBJECT (s)->reserved;
-  guint nf = gts_edge_face_number (e, s);
-
-  if (nf < 1 || nf > 2) {
-    *ok = FALSE;
-    g_return_if_fail (nf >= 1 && nf <= 2);
-  }
-  if (nf == 1 && gts_edge_face_number (e, bs) == 0) {
-    *ok = FALSE;
-    g_return_if_fail (gts_edge_face_number (e, bs) > 0);
-  }
-}
-
-static void mark_edge (GtsObject * o, gpointer data)
-{
-  o->reserved = data;
-}
-
-static gint triangle_orientation (GtsTriangle * t, GtsEdge * e)
-{
-  GtsSegment * s = GTS_SEGMENT (t->e1 == e ? t->e2 
-				: 
-				t->e2 == e ? t->e3 
-				: 
-				t->e1);
-  GtsVertex * v2 = GTS_SEGMENT (e)->v2;
-
-  if (s->v1 == v2 || s->v2 == v2)
-    return 1;
-  return -1;
-}
-
-static gboolean check_orientation (GtsEdge * e, GtsSurface * s)
-{
-  GtsTriangle * t1 = NULL, * t2 = NULL;
-  GSList * i = e->triangles;
-  gint o1 = 0, o2 = 0;
-
-  while (i) {
-    if (GTS_IS_FACE (i->data) && 
-	gts_face_has_parent_surface (i->data, s)) {
-      if (t1 == NULL) {
-	t1 = i->data;
-	o1 = triangle_orientation (t1, e);
-      }
-      else if (t2 == NULL) {
-	t2 = i->data;
-	o2 = triangle_orientation (t2, e);
-	g_return_val_if_fail (o1*o2 < 0, FALSE);
-      }
-      else
-	g_assert_not_reached ();
-    }
-    i = i->next;
-  }
-  g_return_val_if_fail (t1 && t2, FALSE);
-  return TRUE;
-}
-
-static void check_edge (GtsSegment * s, gpointer * data)
-{
-  gboolean * ok = data[0];
-  GtsSurfaceInter * si = data[1];
-  gboolean * closed = data[2];
-  GSList * j;
-  guint nn = 0;
-  
-  j = s->v1->segments;
-  while (j && *ok) {
-    GtsSegment * s1 = j->data;
-    
-    if (s1 != s && GTS_OBJECT (s1)->reserved == si) {
-      if (s1->v2 != s->v1)
-	*ok = FALSE;
-      nn++;
-    }
-    j = j->next;
-  }
-  j = s->v2->segments;
-  while (j && *ok) {
-    GtsSegment * s1 = j->data;
-    
-    if (s1 != s && GTS_OBJECT (s1)->reserved == si) {
-      if (s1->v1 != s->v2)
-	*ok = FALSE;
-      nn++;
-    }
-    j = j->next;
-  }
-  if (nn != 2)
-    *closed = FALSE;
-
-  if (!check_orientation (GTS_EDGE (s), si->s1))
-    *ok = FALSE;
-  if (!check_orientation (GTS_EDGE (s), si->s2))
-    *ok = FALSE;
-}
-
-/**
- * gts_surface_inter_check:
- * @si: a #GtsSurfaceInter.
- * @closed: is set to %TRUE if @si->edges is a closed curve, %FALSE
- * otherwise.
- *
- * Returns: %TRUE if the curve described by @si is an orientable
- * manifold, %FALSE otherwise.  
- */
-gboolean gts_surface_inter_check (GtsSurfaceInter * si,
-				  gboolean * closed)
-{
-  gboolean ok = TRUE;
-  gpointer data[3];
-
-  g_return_val_if_fail (si != NULL, FALSE);
-  g_return_val_if_fail (closed != NULL, FALSE);
-
-  *closed = si->edges ? TRUE : FALSE;
-
-  /* mark edges as used by si */
-  g_slist_foreach (si->edges, (GFunc) mark_edge, si);
-
-  data[0] = &ok;
-  data[1] = si;
-  data[2] = closed;
-  g_slist_foreach (si->edges, (GFunc) check_edge, data);
-  g_slist_foreach (si->edges, (GFunc) gts_object_reset_reserved, NULL);
-
-  /* check connectivity of the faces of @si */
-  if (*closed) {
-    gpointer data[2];
-
-    data[0] = &ok;
-    data[1] = si->s1;
-    gts_surface_foreach_edge (si->s1, (GtsFunc) check_surface_edge, data);
-    data[1] = si->s2;
-    gts_surface_foreach_edge (si->s2, (GtsFunc) check_surface_edge, data);
-  }
-
-  return ok;
-}
-
-/* Given @e and @f returns a #GtsFace compatible with @f and belonging to
-   @s1 or @s2 */
-static GtsFace * next_compatible_face (GtsEdge * e, 
-				       GtsFace * f, 
-				       GtsSurface * s1,
-				       GtsSurface * s2)
-{
-  GSList * i = e->triangles;
-  GtsFace * f2 = NULL, * f3 = NULL;
-
-  while (i) {
-    GtsFace * f1 = i->data;
-
-    if (f1 != f && GTS_IS_FACE (f1)) {
-      if (gts_face_has_parent_surface (f1, s1))
-	return f1;
-      if (gts_face_has_parent_surface (f1, s2)) {
-	if (f2 == NULL) f2 = f1;
-	else if (f3 == NULL) f3 = f1;
-	else g_assert_not_reached (); /* s2 is a non-manifold surface */
-      }
-    }
-    i = i->next;
-  }
-  if (f3 == NULL) {
-    if (gts_edge_is_boundary (e, s2))
-      return NULL;
-    return f2; 
-  }
-  g_assert (gts_face_has_parent_surface (f, s1));
-  if (gts_triangles_are_compatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f2), e))
-    return f2;
-  return f3;
-}
-
-static void walk_faces (GtsEdge * e, GtsFace * f, 
-			GtsSurface * s1,
-			GtsSurface * s2,
-			GtsSurface * s)
-{
-  GtsFifo * faces = gts_fifo_new ();
-  GtsFifo * edges = gts_fifo_new ();
-
-  gts_fifo_push (faces, f);
-  gts_fifo_push (edges, e);
-  while ((f = gts_fifo_pop (faces)) && (e = gts_fifo_pop (edges))) {
-    if (!GTS_OBJECT (f)->reserved) {
-      GtsTriangle * t = GTS_TRIANGLE (f);
-      GtsFace * f1;
-
-      gts_surface_add_face (s, f);
-      GTS_OBJECT (f)->reserved = s;
-      if (t->e1 != e && !GTS_OBJECT (t->e1)->reserved &&
-	  (f1 = next_compatible_face (t->e1, f, s1, s2))) {
-	gts_fifo_push (faces, f1);
-	gts_fifo_push (edges, t->e1);
-      }	
-      if (t->e2 != e && !GTS_OBJECT (t->e2)->reserved &&
-	  (f1 = next_compatible_face (t->e2, f, s1, s2))) {
-	gts_fifo_push (faces, f1);
-	gts_fifo_push (edges, t->e2);
-      }	
-      if (t->e3 != e && !GTS_OBJECT (t->e3)->reserved &&
-	  (f1 = next_compatible_face (t->e3, f, s1, s2))) {
-	gts_fifo_push (faces, f1);
-	gts_fifo_push (edges, t->e3);
-      }	
-    }
-  }
-  gts_fifo_destroy (faces);
-  gts_fifo_destroy (edges);
-}
-
-/**
- * gts_surface_inter_boolean:
- * @si: a #GtsSurfaceInter.
- * @surface: a #GtsSurface.
- * @op: a #GtsBooleanOperation.
- *
- * Adds to @surface the part of the surface described by @si and @op.
- */
-void gts_surface_inter_boolean (GtsSurfaceInter * si,
-				GtsSurface * surface,
-				GtsBooleanOperation op)
-{
-  GtsSurface * s = NULL;
-  gint orient = 1;
-  GSList * i;
-
-  g_return_if_fail (si != NULL);
-  g_return_if_fail (surface != NULL);
-
-  switch (op) {
-  case GTS_1_OUT_2: s = si->s1; orient = 1; break;
-  case GTS_1_IN_2: s = si->s1; orient = -1; break;
-  case GTS_2_OUT_1: s = si->s2; orient = -1; break;
-  case GTS_2_IN_1: s = si->s2; orient = 1; break;
-  default: g_assert_not_reached ();
-  }
-
-  /* mark edges as belonging to intersection */
-  g_slist_foreach (si->edges, (GFunc) mark_edge, si);
-
-  i = si->edges;
-  while (i) {
-    GtsEdge * e = i->data;
-    GSList * j = e->triangles;
-    
-    while (j) {
-      if (gts_face_has_parent_surface (j->data, s) &&
-	  orient*triangle_orientation (j->data, e) > 0) {
-#ifdef DEBUG_BOOLEAN
-	GtsFace * boundary = gts_edge_is_boundary (e, surface);
-
-	g_assert (!boundary || boundary == j->data);
-#endif /* DEBUG_BOOLEAN */
-	walk_faces (e, j->data, s, GTS_OBJECT (s)->reserved, surface);
-	break;
-      }
-      j = j->next;
-    }
-    i = i->next;
-  }
-  g_slist_foreach (si->edges, (GFunc) gts_object_reset_reserved, NULL);
-  gts_surface_foreach_face (surface, 
-			    (GtsFunc) gts_object_reset_reserved, NULL);
-}
-
-static void self_intersecting (GtsBBox * bb1, GtsBBox * bb2, 
-			       gpointer * d)
-{
-  GtsTriangle * t1 = bb1->bounded;
-  GtsTriangle * t2 = bb2->bounded;
-
-  if (t1 != t2) {
-    GtsSegment * s1 = GTS_SEGMENT (t1->e1);
-    GtsSegment * s2 = GTS_SEGMENT (t1->e2);
-    GtsSegment * s3 = GTS_SEGMENT (t1->e3);
-    GtsSegment * s4 = GTS_SEGMENT (t2->e1);
-    GtsSegment * s5 = GTS_SEGMENT (t2->e2);
-    GtsSegment * s6 = GTS_SEGMENT (t2->e3);
-    GtsPoint * pi;
-
-    if ((!gts_segments_touch (s4, s1) && 
-	 !gts_segments_touch (s4, s2) &&
-	 !gts_segments_touch (s4, s3) &&
-	 (pi = segment_triangle_intersection (s4, t1, gts_point_class ()))
-	 != NULL) ||
-	(!gts_segments_touch (s5, s1) && 
-	 !gts_segments_touch (s5, s2) &&
-	 !gts_segments_touch (s5, s3) &&
-	 (pi = segment_triangle_intersection (s5, t1, gts_point_class ())) 
-	 != NULL) ||
-	(!gts_segments_touch (s6, s1) && 
-	 !gts_segments_touch (s6, s2) &&
-	 !gts_segments_touch (s6, s3) &&
-	 (pi = segment_triangle_intersection (s6, t1, gts_point_class ())) 
-	 != NULL)) {
-      GtsBBTreeTraverseFunc func = d[0];
-      gpointer data = d[1];
-      gboolean * self_inter = d[2];
-
-      gts_object_destroy (GTS_OBJECT (pi));
-      *self_inter = TRUE;
-      (* func) (bb1, bb2, data);
-    }
-  }
-}
-
-/**
- * gts_surface_foreach_intersecting_face:
- * @s: a #GtsSurface.
- * @func: a #GtsBBTreeTraverseFunc.
- * @data: user data to pass to @func.
- *
- * Calls @func for each intersecting pair of faces of @s.
- *
- * Returns: %TRUE if @func was called at least once, %FALSE otherwise.
- */
-gboolean gts_surface_foreach_intersecting_face (GtsSurface * s,
-						GtsBBTreeTraverseFunc func,
-						gpointer data)
-{
-  GNode * tree;
-  gpointer d[3];
-  gboolean self_inter = FALSE;
-
-  g_return_val_if_fail (s != NULL, FALSE);
-  g_return_val_if_fail (func != NULL, FALSE);
-
-  tree = gts_bb_tree_surface (s);
-  d[0] = func;
-  d[1] = data;
-  d[2] = &self_inter;
-  gts_bb_tree_traverse_overlapping (tree, tree, 
-				    (GtsBBTreeTraverseFunc) self_intersecting,
-				    d);
-  gts_bb_tree_destroy (tree, TRUE);
-
-  return self_inter;
-}
-
-static void add_intersecting (GtsBBox * bb1, GtsBBox * bb2, 
-			      GtsSurface * intersected)
-{
-  gts_surface_add_face (intersected, bb1->bounded);
-  gts_surface_add_face (intersected, bb2->bounded);
-}
-
-/**
- * gts_surface_is_self_intersecting:
- * @s: a #GtsSurface.
- *
- * Returns: a new #GtsSurface containing the faces of @s which are
- * self-intersecting or %NULL if no faces of @s are self-intersecting.
- */
-GtsSurface * gts_surface_is_self_intersecting (GtsSurface * s)
-{
-  GtsSurface * intersected;
-
-  g_return_val_if_fail (s != NULL, NULL);
-
-  intersected = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass),
-				 s->face_class,
-				 s->edge_class,
-				 s->vertex_class);
-  if (!gts_surface_foreach_intersecting_face (s,
-		      (GtsBBTreeTraverseFunc) add_intersecting, intersected)) {
-    gts_object_destroy (GTS_OBJECT (intersected));
-    intersected = NULL;
-  }
-  return intersected;
-}
diff --git a/src_3rd/gts/cdt.c b/src_3rd/gts/cdt.c
deleted file mode 100644
index 088eb8e..0000000
--- a/src_3rd/gts/cdt.c
+++ /dev/null
@@ -1,1173 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <config.h>
-
-
-#include <math.h>
-#include "gts.h"
-
-#ifdef USE_SURFACE_BTREE
-
-static gint find_closest (GtsTriangle * t, gpointer value, gpointer * data)
-{
-  guint * ns = data[2];
-  guint * n = data[3];
-
-  if (*n >= *ns)
-    return TRUE;
-  else {
-    gdouble * dmin = data[0];
-    gpointer * closest = data[1];
-    GtsPoint * p = data[4];
-
-    if (gts_triangle_orientation (t) > 0.) {
-      GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
-      gdouble d = (p->x - p1->x)*(p->x - p1->x) + (p->y - p1->y)*(p->y - p1->y);
-      
-      if (d < *dmin) {
-	*dmin = d;
-	*closest = t;
-      }
-      (*n)++;
-    }
-  }
-  return FALSE;
-}
-
-/* select the face closest to @p among n^1/3 randomly picked faces
- *  of @surface */
-static GtsFace * closest_face (GtsSurface * s, GtsPoint * p)
-{
-  guint n = 0, nt, ns;
-  gdouble dmin = G_MAXDOUBLE;
-  GtsFace * closest = NULL;
-  gpointer data[5];
-
-  nt = gts_surface_face_number (s);
-  if (!nt)
-    return NULL;
-  ns = exp (log ((gdouble) nt)/3.);
-
-  data[0] = &dmin;
-  data[1] = &closest;
-  data[2] = &ns;
-  data[3] = &n;
-  data[4] = p;
-  g_tree_traverse (s->faces, (GTraverseFunc) find_closest, G_IN_ORDER, data);
-
-  return closest;
-}
-
-#else /* not USE_SURFACE_BTREE */
-
-typedef struct _SFindClosest SFindClosest; 
-
-struct _SFindClosest {
-  gdouble dmin; 
-  GtsFace *closest;
-  GtsPoint * p;
-  gint stop;
-};
-
-#  if GLIB_CHECK_VERSION(2,4,0)
-/* finally, with g_hash_table_find we are able to stop iteration over the hash
-   table in the middle */
-
-static gboolean find_closest (gpointer key, gpointer value, gpointer user_data)
-{
-  SFindClosest * data = (SFindClosest *) user_data;
-  GtsFace * f = GTS_FACE (value);
-  
-  if (gts_triangle_orientation (GTS_TRIANGLE (f)) > 0.) {
-    GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (GTS_TRIANGLE (f)->e1)->v1);
-    gdouble d = ((data->p->x - p1->x)*(data->p->x - p1->x) + 
-		 (data->p->y - p1->y)*(data->p->y - p1->y));
-
-    if (d < data->dmin) {
-      data->dmin = d;
-      data->closest = f;
-    }
-  }
-  data->stop--;
-  return !(data->stop > 0);
-}
-
-static GtsFace * closest_face (GtsSurface * s, GtsPoint * p)
-{
-  SFindClosest fc;
-
-  fc.dmin = G_MAXDOUBLE;
-  fc.closest = NULL;
-  fc.p = p;
-  fc.stop = (gint) exp (log ((gdouble) g_hash_table_size (s->faces))/3.);
-  g_hash_table_find (s->faces, find_closest, &fc);
-  
-  return fc.closest;
-}
-
-#  else /* VERSION < 2.4.0 */
-
-static void
-find_closest (gpointer key, gpointer value, gpointer user_data)
-{
-  SFindClosest * data = (SFindClosest *) user_data;
-  GtsFace * f = GTS_FACE (value);
-
-  if (gts_triangle_orientation (GTS_TRIANGLE (f)) > 0.) {
-    GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (GTS_TRIANGLE (f)->e1)->v1);
-    gdouble d = ((data->p->x - p1->x)*(data->p->x - p1->x) +
-		 (data->p->y - p1->y)*(data->p->y - p1->y));
-
-    if (d < data->dmin) {
-      data->dmin = d;
-      data->closest = f;
-    }
-  }
-  data->stop--;
-}
-
-/* select the face closest to @p among n^1/3 randomly picked faces
- * of @surface */
-static GtsFace * closest_face (GtsSurface * s, GtsPoint * p)
-{
-  SFindClosest fc;
-
-  if (!g_hash_table_size (s->faces))
-    return NULL;
-
-  fc.dmin = G_MAXDOUBLE;
-  fc.closest = NULL;
-  fc.p = p;
-  fc.stop = (gint) exp (log ((gdouble) g_hash_table_size (s->faces))/3.);
-  g_hash_table_foreach (s->faces, find_closest, &fc);
-  return fc.closest;
-}
-#  endif /* VERSION < 2.4.0 */
-#endif /* not USE_SURFACE_BTREE */
-
-/* returns the face belonging to @surface and neighbor of @f via @e */
-static GtsFace * neighbor (GtsFace * f,
-			   GtsEdge * e,
-			   GtsSurface * surface)
-{
-  GSList * i = e->triangles;
-  GtsTriangle * t = GTS_TRIANGLE (f);
-
-  while (i) {
-    GtsTriangle * t1 = i->data;
-    if (t1 != t &&
-	GTS_IS_FACE (t1) &&
-	gts_face_has_parent_surface (GTS_FACE (t1), surface))
-      return GTS_FACE (t1);
-    i = i->next;
-  }
-  return NULL;
-}
-
-/* given a triangle @t and a segment s (@o -> @p). 
-   @o must be in @t. Returns the
-   edge of @t which is intersected by s or %NULL if @p is also
-   contained in @t (on_summit is set to %FALSE) or if s intersects @t 
-   exactly on one of its summit (on_summit is set to %TRUE). */
-static GtsEdge * triangle_next_edge (GtsTriangle * t,
-				     GtsPoint * o, GtsPoint * p,
-				     gboolean * on_summit)
-{
-  GtsVertex * v1, * v2, * v3;
-  GtsEdge * e1, * e2, * e3;
-  gdouble orient = 0.0;
-  
-  gts_triangle_vertices_edges (t, NULL,
-			       &v1, &v2, &v3, 
-			       &e1, &e2, &e3);
-
-  *on_summit = FALSE;
-  orient = gts_point_orientation (o, GTS_POINT (v1), p);
-  if (orient > 0.0) {
-    orient = gts_point_orientation (o, GTS_POINT (v2), p);
-    if (orient > 0.0) {
-      if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0)
-	return NULL;
-      return e2;
-    }
-    if (orient < 0.0) {
-      if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) >= 0.0)
-	return NULL;
-      return e1;
-    }
-    if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) < 0.0)
-      *on_summit = TRUE;
-    return NULL;
-  }
-
-  if (orient < 0.0) {
-    orient = gts_point_orientation (o, GTS_POINT (v3), p);
-    if (orient > 0.0) {
-      if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) >= 0.0)
-	return NULL;
-      return e3;
-    }
-    if (orient < 0.0) {
-      if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0)
-	return NULL;
-      return e2;
-    }
-    if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) < 0.0)
-      *on_summit = TRUE;
-    return NULL;
-  }
-  
-  if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) < 0.0)
-    return e2;
-  if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) < 0.0)
-    *on_summit = TRUE;
-  return NULL;
-}
-
-static void triangle_barycenter (GtsTriangle * t, GtsPoint * b)
-{
-  GtsPoint * p = GTS_POINT (gts_triangle_vertex (t));
-  b->x = (p->x + 
-	  GTS_POINT (GTS_SEGMENT(t->e1)->v1)->x +
-	  GTS_POINT (GTS_SEGMENT(t->e1)->v2)->x)/3.;
-  b->y = (p->y + 
-	  GTS_POINT (GTS_SEGMENT(t->e1)->v1)->y +
-	  GTS_POINT (GTS_SEGMENT(t->e1)->v2)->y)/3.;
-}
-
-static GtsFace * point_locate (GtsPoint * o,
-			       GtsPoint * p,
-			       GtsFace * f,
-			       GtsSurface * surface)
-{
-  GtsEdge * prev;
-  gboolean on_summit;
-  GtsVertex * v1, * v2, * v3;
-  GtsEdge * e2, * e3;    
-  
-  prev = triangle_next_edge (GTS_TRIANGLE (f), o, p, &on_summit);
-
-  if (!prev) {
-    GtsFace * f1;
-
-    if (!on_summit)
-      return f; /* p is inside f */
-
-    /* s intersects f exactly on a summit: restarts from a neighbor of f */
-    if ((f1 = neighbor (f, GTS_TRIANGLE (f)->e1, surface)) ||
-	(f1 = neighbor (f, GTS_TRIANGLE (f)->e2, surface)) ||
-	(f1 = neighbor (f, GTS_TRIANGLE (f)->e3, surface))) {
-      triangle_barycenter (GTS_TRIANGLE (f1), o);
-      return point_locate (o, p, f1, surface);
-    }
-    return NULL;
-  }
-  
-  f = neighbor (f, prev, surface);
-  if (f)
-    gts_triangle_vertices_edges (GTS_TRIANGLE (f), prev, 
-				 &v1, &v2, &v3, &prev, &e2, &e3);
-  while (f) {
-    gdouble orient = gts_point_orientation (o, GTS_POINT (v3), p);
-
-    if (orient < 0.0) {
-      if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0)
-	return f; /* p is inside f */
-      f = neighbor (f, e2, surface);
-      prev = e2;
-      v1 = v3;      
-    }
-    else if (orient > 0.0) {
-      if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) >= 0.0)
-	return f; /* p is inside f */
-      f = neighbor (f, e3, surface);
-      prev = e3;
-      v2 = v3;
-    }
-    else {
-      GtsFace * f1;
-
-      if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0)
-	return f; /* p is inside f */
-
-      /* s intersects f exactly on v3: restarts from a neighbor of f */
-      if ((f1 = neighbor (f, e2, surface)) ||
-	  (f1 = neighbor (f, e3, surface))) {
-	triangle_barycenter (GTS_TRIANGLE (f1), o);
-	return point_locate (o, p, f1, surface);
-      }
-      return NULL;
-    }
-    /* update e2, e3, v3 for the new triangle */
-    if (f) {
-      if (prev == GTS_TRIANGLE (f)->e1) {
-	e2 = GTS_TRIANGLE (f)->e2; e3 = GTS_TRIANGLE (f)->e3;
-      }
-      else if (prev == GTS_TRIANGLE (f)->e2) {
-	e2 = GTS_TRIANGLE (f)->e3; e3 = GTS_TRIANGLE (f)->e1;
-      }
-      else {
-	e2 = GTS_TRIANGLE (f)->e1; e3 = GTS_TRIANGLE (f)->e2;
-      }
-      if (GTS_SEGMENT (e2)->v1 == v1 || GTS_SEGMENT (e2)->v1 == v2)
-	v3 = GTS_SEGMENT (e2)->v2;
-      else
-	v3 = GTS_SEGMENT (e2)->v1;
-    }
-  }
-  return NULL;
-}
-
-/**
- * gts_point_locate:
- * @p: a #GtsPoint.
- * @surface: a #GtsSurface.
- * @guess: %NULL or a face of @surface close to @p.
- *
- * Locates the face of the planar projection of @surface containing
- * @p. The planar projection of @surface must define a connected set
- * of triangles without holes and bounded by a convex boundary. The
- * algorithm is randomized and performs in O(n^1/3) expected time
- * where n is the number of triangles of @surface.
- *
- * If a good @guess is given the point location can be significantly faster.
- *
- * Returns: a #GtsFace of @surface containing @p or %NULL if @p is not
- * contained within the boundary of @surface.  
- */
-GtsFace * gts_point_locate (GtsPoint * p, 
-			    GtsSurface * surface,
-			    GtsFace * guess)
-{
-  GtsFace * fr;
-  GtsPoint * o;
-
-  g_return_val_if_fail (p != NULL, NULL);
-  g_return_val_if_fail (surface != NULL, NULL);
-  g_return_val_if_fail (guess == NULL || 
-			gts_face_has_parent_surface (guess, surface), NULL);
-
-  if (guess == NULL)
-    guess = closest_face (surface, p);
-  else
-    g_return_val_if_fail (gts_triangle_orientation (GTS_TRIANGLE (guess)) > 0., NULL);
-
-  if (guess == NULL)
-    return NULL;
-
-  o = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ())));
-  triangle_barycenter (GTS_TRIANGLE (guess), o);
-  fr = point_locate (o, p, guess, surface);
-  gts_object_destroy (GTS_OBJECT (o));
-
-  return fr;
-}
-
-
-/**
- * gts_constraint_class:
- *
- * Returns: the #GtsConstraintClass.
- */
-GtsConstraintClass * gts_constraint_class (void)
-{
-  static GtsConstraintClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo constraint_info = {
-      "GtsConstraint",
-      sizeof (GtsConstraint),
-      sizeof (GtsConstraintClass),
-      (GtsObjectClassInitFunc) NULL,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_edge_class ()), 
-				  &constraint_info);
-  }
-
-  return klass;
-}
-
-static void split_list (GtsListFace * f, GtsListFace * f1, GtsListFace * f2, 
-			GtsPoint * p1, GtsPoint * p2,
-			GSList ** last1, GSList ** last2)
-{
-  GSList * i = f->points, * l1 = *last1, * l2 = *last2;
-
-  while (i) {
-    GtsPoint * p = i->data;
-    
-    if (gts_point_orientation (p1, p2, p) >= 0.) {
-      if (l1) l1->next = i; else f1->points = i;
-      l1 = i;
-    }
-    else {
-      if (l2) l2->next = i; else f2->points = i;
-      l2 = i;
-    }
-    i = i->next;
-  }
-  f->points = NULL;
-  *last1 = l1;
-  *last2 = l2;
-}
-
-/* cf. figure misc/swap.fig */
-static void swap_if_in_circle (GtsFace * f1,
-			       GtsVertex * v1, 
-			       GtsVertex * v2, 
-			       GtsVertex * v3,
-			       GtsEdge * e1, 
-			       GtsEdge * e2, 
-			       GtsEdge * e3,
-			       GtsSurface * surface)
-{
-  GtsFace * f2;
-  GtsEdge * e4, *e5;
-  GtsVertex * v4;
-
-  if (GTS_IS_CONSTRAINT (e1)) /* @e1 is a constraint can not swap */
-    return;
-
-  f2 = neighbor (f1, e1, surface);
-  if (f2 == NULL) /* @e1 is a boundary of @surface */
-    return;
-
-  if (GTS_TRIANGLE (f2)->e1 == e1) {
-    e4 = GTS_TRIANGLE (f2)->e2; e5 = GTS_TRIANGLE (f2)->e3;
-  }
-  else if (GTS_TRIANGLE (f2)->e2 == e1) {
-    e4 = GTS_TRIANGLE (f2)->e3; e5 = GTS_TRIANGLE (f2)->e1;
-  }
-  else {
-    e4 = GTS_TRIANGLE (f2)->e1; e5 = GTS_TRIANGLE (f2)->e2;
-  }
-  if (GTS_SEGMENT (e4)->v1 == GTS_SEGMENT (e1)->v1 || 
-      GTS_SEGMENT (e4)->v1 == GTS_SEGMENT (e1)->v2)
-    v4 = GTS_SEGMENT (e4)->v2;
-  else
-    v4 = GTS_SEGMENT (e4)->v1;
-
-  if (gts_point_in_circle (GTS_POINT (v4), GTS_POINT (v1), 
-			   GTS_POINT (v2), GTS_POINT (v3)) > 0.0) {
-    GtsEdge * en;
-    GtsSegment * sn = gts_vertices_are_connected (v3, v4);
-    GtsFace * f3, * f4;
-
-    if (!GTS_IS_EDGE (sn))
-      en = gts_edge_new (surface->edge_class, v3, v4);
-    else
-      en = GTS_EDGE (sn);
-
-    f3 = gts_face_new (surface->face_class, en, e5, e2);
-    gts_object_attributes (GTS_OBJECT (f3), GTS_OBJECT (f1));
-    f4 = gts_face_new (surface->face_class, en, e3, e4);
-    gts_object_attributes (GTS_OBJECT (f4), GTS_OBJECT (f2));
-    
-    if (GTS_IS_LIST_FACE (f3)) {
-      GSList * last3 = NULL, * last4 = NULL;
-
-      if (GTS_IS_LIST_FACE (f1))
-	split_list (GTS_LIST_FACE (f1), GTS_LIST_FACE (f3), GTS_LIST_FACE (f4),
-		    GTS_POINT (v3), GTS_POINT (v4), &last3, &last4);
-      if (GTS_IS_LIST_FACE (f2))
-	split_list (GTS_LIST_FACE (f2), GTS_LIST_FACE (f3), GTS_LIST_FACE (f4),
-		    GTS_POINT (v3), GTS_POINT (v4), &last3, &last4);
-      if (last3) last3->next = NULL;
-      if (last4) last4->next = NULL;
-    }
-
-    gts_surface_remove_face (surface, f1);
-    gts_surface_remove_face (surface, f2);
-    gts_surface_add_face (surface, f3);
-    gts_surface_add_face (surface, f4);
-
-    swap_if_in_circle (f3, v4, v2, v3, e5, e2, en, surface);
-    swap_if_in_circle (f4, v1, v4, v3, e4, en, e3, surface);
-  }
-}
-
-/**
- * gts_delaunay_add_vertex_to_face:
- * @surface: a #GtsSurface.
- * @v: a #GtsVertex.
- * @f: a #GtsFace belonging to @surface.
- *
- * Adds vertex @v to the face @f of the Delaunay triangulation defined
- * by @surface.
- *
- * Returns: %NULL is @v has been successfully added to @surface or was
- * already contained in @surface or a #GtsVertex having the same x and
- * y coordinates as @v.  
- */
-GtsVertex * gts_delaunay_add_vertex_to_face (GtsSurface * surface, 
-					     GtsVertex * v,
-					     GtsFace * f)
-{
-  GtsEdge * e1, * e2, * e3;
-  GtsSegment * s4, * s5, * s6;
-  GtsEdge * e4, * e5, * e6;
-  GtsVertex * v1, * v2, * v3;
-  GtsFace * nf[3];
-
-  g_return_val_if_fail (surface != NULL, v);
-  g_return_val_if_fail (v != NULL, v);
-  g_return_val_if_fail (f != NULL, v);
-
-  gts_triangle_vertices_edges (GTS_TRIANGLE (f), NULL, 
-			       &v1, &v2, &v3, &e1, &e2, &e3);
-  if (v == v1 || v == v2 || v == v3) /* v already in @surface */
-    return NULL;
-  if (GTS_POINT (v)->x == GTS_POINT (v1)->x &&
-      GTS_POINT (v)->y == GTS_POINT (v1)->y)
-    return v1;
-  if (GTS_POINT (v)->x == GTS_POINT (v2)->x &&
-      GTS_POINT (v)->y == GTS_POINT (v2)->y)
-    return v2;
-  if (GTS_POINT (v)->x == GTS_POINT (v3)->x &&
-      GTS_POINT (v)->y == GTS_POINT (v3)->y)
-    return v3;
-
-  s4 = gts_vertices_are_connected (v, v1);
-  if (!GTS_IS_EDGE (s4))
-    e4 = gts_edge_new (surface->edge_class, v, v1);
-  else
-    e4 = GTS_EDGE (s4);
-  s5 = gts_vertices_are_connected (v, v2);
-  if (!GTS_IS_EDGE (s5))
-    e5 = gts_edge_new (surface->edge_class, v, v2);
-  else
-    e5 = GTS_EDGE (s5);
-  s6 = gts_vertices_are_connected (v, v3);
-  if (!GTS_IS_EDGE (s6))
-    e6 = gts_edge_new (surface->edge_class, v, v3);
-  else
-    e6 = GTS_EDGE (s6);
-
-  /* cf. figure misc/swap.fig */
-  nf[0] = gts_face_new (surface->face_class, e4, e1, e5);
-  gts_object_attributes (GTS_OBJECT (nf[0]), GTS_OBJECT (f));
-  nf[1] = gts_face_new (surface->face_class, e5, e2, e6);
-  gts_object_attributes (GTS_OBJECT (nf[1]), GTS_OBJECT (f));
-  nf[2] = gts_face_new (surface->face_class, e6, e3, e4);
-  gts_object_attributes (GTS_OBJECT (nf[2]), GTS_OBJECT (f));
-
-  if (GTS_IS_LIST_FACE (f) && GTS_IS_LIST_FACE (nf[0])) {
-    GSList * i = GTS_LIST_FACE (f)->points, * last[3] = { NULL, NULL, NULL };
-
-    while (i) {
-      GtsPoint * p = i->data;
-      GSList * next = i->next;
-      guint j;
-      
-      if (p != GTS_POINT (v)) {
-	if (gts_point_orientation (GTS_POINT (v), GTS_POINT (v1), p) >= 0.) {
-	  gdouble o = gts_point_orientation (GTS_POINT (v), GTS_POINT (v2), p);
-
-	  if (o != 0.)
-	    j = o > 0. ? 1 : 0;
-	  else
-	    j = gts_point_orientation (GTS_POINT (v), GTS_POINT (v3), p) 
-	      > 0. ? 0 : 1;
-	}
-	else if (gts_point_orientation (GTS_POINT (v), GTS_POINT (v3), p) > 0.)
-	  j = 2;
-	else
-	  j = 1;
-	if (last[j])
-	  last[j]->next = i; 
-	else 
-	  GTS_LIST_FACE (nf[j])->points = i;
-	last[j] = i;
-      }
-      else
-	g_slist_free_1 (i);
-      i = next;
-    }
-    GTS_LIST_FACE (f)->points = NULL;
-    if (last[0]) last[0]->next = NULL;
-    if (last[1]) last[1]->next = NULL;
-    if (last[2]) last[2]->next = NULL;
-  }
-
-  gts_surface_remove_face (surface, f);
-  gts_surface_add_face (surface, nf[0]);
-  gts_surface_add_face (surface, nf[1]);
-  gts_surface_add_face (surface, nf[2]);
-
-  swap_if_in_circle (nf[0], v1, v2, v, e1, e5, e4, surface);
-  swap_if_in_circle (nf[1], v2, v3, v, e2, e6, e5, surface);
-  swap_if_in_circle (nf[2], v3, v1, v, e3, e4, e6, surface);
-
-  return NULL;
-}
-
-/** 
- * gts_delaunay_add_vertex: 
- * @surface: a #GtsSurface.  
- * @v: a #GtsVertex.  
- * @guess: %NULL or a #GtsFace belonging to @surface to be used as an initial
- * guess for point location.
- *
- * Adds vertex @v to the Delaunay triangulation defined by
- * @surface. If @v is not contained in the convex hull bounding
- * @surface, @v is not added to the triangulation.
- *
- * Returns: %NULL is @v has been successfully added to @surface or was
- * already contained in @surface, @v if @v is not contained in the
- * convex hull bounding surface or a #GtsVertex having the same x and
- * y coordinates as @v.  
- */
-GtsVertex * gts_delaunay_add_vertex (GtsSurface * surface, 
-				     GtsVertex * v,
-				     GtsFace * guess)
-{
-  GtsFace * f;
-
-  g_return_val_if_fail (surface != NULL, v);
-  g_return_val_if_fail (v != NULL, v);
-
-  if (!(f = gts_point_locate (GTS_POINT (v), surface, guess)))
-    return v;
-  return gts_delaunay_add_vertex_to_face (surface, v, f);
-}
-
-static gboolean polygon_in_circle (GSList * poly,
-				   GtsPoint * p1, 
-				   GtsPoint * p2,
-				   GtsPoint * p3)
-{
-  GtsVertex * v1 = NULL, * v2 = NULL;
-
-  while (poly) {
-    GtsSegment * s = poly->data;
-    GtsVertex * v;
-    v = s->v1;
-    if (v != v1 && v != v2 &&
-	v != GTS_VERTEX (p1) &&
-	v != GTS_VERTEX (p2) &&
-	v != GTS_VERTEX (p3) &&
-	gts_point_in_circle (GTS_POINT (v), p1, p2, p3) > 0.)
-      return TRUE;
-    v = s->v2;
-    if (v != v1 && v != v2 &&
-	v != GTS_VERTEX (p1) &&
-	v != GTS_VERTEX (p2) &&
-	v != GTS_VERTEX (p3) &&
-	gts_point_in_circle (GTS_POINT (v), p1, p2, p3) > 0.)
-      return TRUE;
-    v1 = s->v1;
-    v2 = s->v2;
-    poly = poly->next;
-  }
-  return FALSE;
-}
-
-static void triangulate_polygon (GSList * poly, 
-				 GtsSurface * surface,
-				 GtsFace * ref)
-{
-  GSList * i, * poly1, * poly2;
-  GtsVertex * v1, * v2, * v3 = NULL;
-  gboolean found = FALSE;
-  GtsSegment * s, * s1, * s2;
-  GtsEdge * e1, * e2;
-  GtsFace * f;
-
-  if (poly == NULL || poly->next == NULL) {
-    g_slist_free (poly);
-    return;
-  }
-
-  s = poly->data;
-  s1 = poly->next->data;
-  if (s->v1 == s1->v1 || s->v1 == s1->v2) {
-    v1 = s->v2;
-    v2 = s->v1;
-  }
-  else {
-    g_assert (s->v2 == s1->v1 || s->v2 == s1->v2);
-    v1 = s->v1;
-    v2 = s->v2;
-  }
-
-  i = poly->next;
-  v3 = v2;
-  while (i && !found) {
-    s1 = i->data;
-    if (s1->v1 == v3)
-      v3 = s1->v2;
-    else {
-      g_assert (s1->v2 == v3);
-      v3 = s1->v1;
-    }
-    if (v3 != v1 &&
-	gts_point_orientation (GTS_POINT (v1), 
-			       GTS_POINT (v2), 
-			       GTS_POINT (v3)) >= 0. &&
-	!polygon_in_circle (poly, 
-			    GTS_POINT (v1), 
-			    GTS_POINT (v2), 
-			    GTS_POINT (v3)))
-      found = TRUE;
-    else 
-      i = i->next;
-  }
-
-  if (!found) {
-    g_slist_free (poly);
-    return;
-  }
-
-  s1 = gts_vertices_are_connected (v2, v3);
-  if (!GTS_IS_EDGE (s1))
-    e1 = gts_edge_new (surface->edge_class, v2, v3);
-  else
-    e1 = GTS_EDGE (s1);
-  s2 = gts_vertices_are_connected (v3, v1);
-  if (!GTS_IS_EDGE (s2))
-    e2 = gts_edge_new (surface->edge_class, v3, v1);
-  else
-    e2 = GTS_EDGE (s2);
-  f = gts_face_new (surface->face_class, GTS_EDGE (s), e1, e2);
-  gts_object_attributes (GTS_OBJECT (f), GTS_OBJECT (ref));
-  gts_surface_add_face (surface, f);
-
-  poly1 = poly->next;
-  g_slist_free_1 (poly);
-  if (i->next && e2 != i->next->data)
-    poly2 = g_slist_prepend (i->next, e2);
-  else
-    poly2 = i->next;
-  if (e1 != i->data)
-    i->next = g_slist_prepend (NULL, e1);
-  else
-    i->next = NULL;
-
- triangulate_polygon (poly1, surface, ref);
- triangulate_polygon (poly2, surface, ref);
-}
-
-/**
- * gts_delaunay_remove_vertex:
- * @surface: a #GtsSurface.
- * @v: a #GtsVertex.
- *
- * Removes @v from the Delaunay triangulation defined by @surface and
- * restores the Delaunay property. Vertex @v must not be used by any
- * constrained edge otherwise the triangulation is not guaranteed to
- * be Delaunay.  
- */
-void gts_delaunay_remove_vertex (GtsSurface * surface, GtsVertex * v)
-{
-  GSList * triangles, * i;
-  GtsFace * ref = NULL;
-
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (v != NULL);
-
-  i = triangles = gts_vertex_triangles (v, NULL);
-  while (i && !ref) {
-    if (GTS_IS_FACE (i->data) &&
-	gts_face_has_parent_surface (i->data, surface))
-      ref = i->data;
-    i = i->next;
-  }
-  if (!ref) {
-    g_slist_free (triangles);
-    g_return_if_fail (ref);
-  }
-  triangulate_polygon (gts_vertex_fan_oriented (v, surface), surface, ref);
-  i = triangles;
-  while (i) {
-    if (GTS_IS_FACE (i->data) &&
-	gts_face_has_parent_surface (i->data, surface))
-      gts_surface_remove_face (surface, i->data);
-    i = i->next;
-  }
-  g_slist_free (triangles);
-}
-
-#define NEXT_CUT(edge, edge1, list) { next = neighbor (f, edge, surface);\
-                                      remove_triangles (e, surface);\
-                                      if (!constraint && !e->triangles)\
-				        gts_object_destroy (GTS_OBJECT (e));\
-                                      g_assert (next);\
-				      *list = g_slist_prepend (*list, edge1);\
-                                      return g_slist_concat (constraint,\
-                                        remove_intersected_edge (s, edge,\
-					       next, surface, left, right));\
-                                    }
-
-static void remove_triangles (GtsEdge * e, GtsSurface * s)
-{
-  GSList * i = e->triangles;
-
-  while (i) {
-    GSList * next = i->next;
-
-    if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s))
-      gts_surface_remove_face (s, i->data);
-    i = next;
-  }
-}
-
-static GSList * 
-remove_intersected_edge (GtsSegment * s,
-			 GtsEdge * e,
-			 GtsFace * f,
-			 GtsSurface * surface,
-			 GSList ** left, GSList ** right)
-{
-  GtsVertex * v1, * v2, * v3;
-  GtsEdge * e1, * e2;
-  gdouble o1, o2;
-  GtsFace * next;
-  GSList * constraint = NULL;
-
-  if (GTS_IS_CONSTRAINT (e))
-    constraint = g_slist_prepend (NULL, e);
-
-  gts_triangle_vertices_edges (GTS_TRIANGLE (f), e, 
-			       &v1, &v2, &v3, &e, &e1, &e2);
-  
-  o1 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), 
-			      GTS_POINT (s->v2));
-  o2 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), 
-			      GTS_POINT (s->v2));
-
-  if (o1 == 0. && o2 == 0.) {
-/*    if(o2 != 0.) {
-      fprintf(stderr, "o1 = %f o2 = %f\n", o1, o2);
-      fprintf(stderr, "v1 = %f, %f\n", GTS_POINT(v1)->x, GTS_POINT(v1)->y);
-      fprintf(stderr, "v2 = %f, %f\n", GTS_POINT(v2)->x, GTS_POINT(v2)->y);
-      fprintf(stderr, "v3 = %f, %f\n", GTS_POINT(v3)->x, GTS_POINT(v3)->y);
-      fprintf(stderr, "s->v2 = %f, %f\n", GTS_POINT(s->v2)->x, GTS_POINT(s->v2)->y);
-
-      g_assert (o2 == 0.);
-    }*/
- //   if(o2 == 0.) {
-      remove_triangles (e, surface);
-      if (!constraint && !e->triangles)
-        gts_object_destroy (GTS_OBJECT (e));
-      *left = g_slist_prepend (*left, e2);
-      *right = g_slist_prepend (*right, e1);
-//    }
-  }
-  else if (o1 > 0.) {
-    g_assert (o2 <= 0.);
-    NEXT_CUT (e2, e1, right)
-  }
-  else if (o2 >= 0.)
-    NEXT_CUT (e1, e2, left)
-  else {
-    gdouble o3 = gts_point_orientation (GTS_POINT (s->v1), GTS_POINT (s->v2),
-					GTS_POINT (v3));
-    if (o3 > 0.)
-      NEXT_CUT (e1, e2, left)
-    else
-      NEXT_CUT (e2, e1, right)
-  }
-  return constraint;
-}
-
-static GSList * 
-remove_intersected_vertex (GtsSegment * s,
-			   GtsVertex * v,
-			   GtsSurface * surface,
-			   GSList ** left,
-			   GSList ** right,
-			   GtsFace ** ref)
-{
-  GSList * triangles = gts_vertex_triangles (v, NULL);
-  GSList * i;
-
-  i = triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    if (GTS_IS_FACE (t) && 
-	gts_face_has_parent_surface (GTS_FACE (t), surface)) {
-      GtsVertex * v1, * v2, * v3;
-      gdouble o1, o2;
-
-      gts_triangle_vertices (t, &v1, &v2, &v3);
-      if (v == v2) {
-	v2 = v3;
-	v3 = v1;
-      }
-      else if (v == v3) {
-	v3 = v2;
-	v2 = v1;	
-      }
-      else
-	g_assert (v == v1);
-
-      if ((o1 = gts_point_orientation (GTS_POINT (v), GTS_POINT (v2),
-				       GTS_POINT (s->v2))) >= 0. &&
-	  (o2 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v),
-				       GTS_POINT (s->v2))) >= 0.) {
-	gdouble o3 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3),
-					    GTS_POINT (s->v2));
-	GtsEdge * e = gts_triangle_edge_opposite (t, v);
-	GtsEdge * e1, * e2;
-	GtsFace * next = neighbor (GTS_FACE (t), e, surface);
-
-	*ref = GTS_FACE (t);
-	gts_triangle_vertices_edges (t, e, &v2, &v3, &v, &e, &e2, &e1);
-
-	g_slist_free (triangles);
-
-	if (o3 >= 0.) /* @s->v2 is inside (or on the edge) of t */
-	  return NULL;
-
-	gts_allow_floating_faces = TRUE;
-	gts_surface_remove_face (surface, GTS_FACE (t));
-	gts_allow_floating_faces = FALSE;
-
-	*left = g_slist_prepend (*left, e2);
-	*right = g_slist_prepend (*right, e1);
-
-	g_assert (next);
-	return remove_intersected_edge (s, e, next, surface, left, right);
-      }
-    }
-    i = i->next;
-  }
-
-  g_assert_not_reached ();
-  return NULL;
-}
-
-/**
- * gts_delaunay_add_constraint:
- * @surface: a #GtsSurface.
- * @c: a #GtsConstraint.
- *
- * Add constraint @c to the constrained Delaunay triangulation defined by
- * @surface.
- *
- * Returns: a list of #GtsConstraint conflicting (i.e. intersecting) with @c 
- * which were removed from @surface (%NULL if there was none).
- */
-GSList * gts_delaunay_add_constraint (GtsSurface * surface,
-				      GtsConstraint * c)
-{
-  GSList * constraints;
-  GtsVertex * v1; //, * v2;
-  GSList * left = NULL, * right = NULL;
-  GtsFace * ref = NULL;
-
-  g_return_val_if_fail (surface != NULL, NULL);
-  g_return_val_if_fail (c != NULL, NULL);
-  g_return_val_if_fail (GTS_IS_CONSTRAINT (c), NULL);
-  
-  v1 = GTS_SEGMENT (c)->v1;
-  //v2 = GTS_SEGMENT (c)->v2;
-  
-  gts_allow_floating_edges = TRUE;
-  constraints = remove_intersected_vertex (GTS_SEGMENT (c), v1, surface,
-					   &left, &right, &ref);
-  gts_allow_floating_edges = FALSE;
-#if 1
-  triangulate_polygon (g_slist_prepend (g_slist_reverse (right), c), 
-		       surface, ref);
-  triangulate_polygon (g_slist_prepend (left, c), 
-		       surface, ref);
-#else
-  right = g_slist_prepend (g_slist_reverse (right), c);
-  left = g_slist_prepend (left, c);
-  {
-    FILE * fp0 = fopen ("hole", "wt");
-    FILE * fp1 = fopen ("right", "wt");
-    FILE * fp2 = fopen ("left", "wt");
-    GSList * i = left;
-
-    gts_surface_write (surface, fp0);
-    fclose (fp0);
- 
-    fprintf (fp2, "LIST {\n");
-    while (i) {
-      GtsSegment * s = i->data;
-      fprintf (fp2, 
-	       "# %p: %p->%p\n"
-	       "VECT 1 2 0 2 0 %g %g 0 %g %g 0\n",
-	       s, s->v1, s->v2,
-	       GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y,
-	       GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y);
-      i = i->next;
-    }
-    fprintf (fp2, "}\n");
-    fprintf (fp1, "LIST {\n");
-    i = right;
-    while (i) {
-      GtsSegment * s = i->data;
-      fprintf (fp1, 
-	       "# %p: %p->%p\n"
-	       "VECT 1 2 0 2 0 %g %g 0 %g %g 0\n",
-	       s, s->v1, s->v2,
-	       GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y,
-	       GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y);
-      i = i->next;
-    }
-    fprintf (fp1, "}\n");
-    fclose (fp1);
-    fclose (fp2);
-  }
-  triangulate_polygon (right, surface);
-  triangulate_polygon (left, surface);
-#endif
-  if (ref && !ref->surfaces) {
-    gts_allow_floating_edges = TRUE;
-    gts_object_destroy (GTS_OBJECT (ref));
-    gts_allow_floating_edges = FALSE;
-  }
-  return constraints;
-}
-
-static void delaunay_check (GtsTriangle * t, gpointer * data)
-{
-  GtsSurface * surface = data[0];
-  GtsFace ** face = data[1];
-
-  if (*face == NULL) {
-    GSList * i, * list;
-    GtsVertex * v1, * v2, * v3;
-
-    gts_triangle_vertices (t, &v1, &v2, &v3);
-    list = gts_vertex_neighbors (v1, NULL, surface);
-    list = gts_vertex_neighbors (v2, list, surface);
-    list = gts_vertex_neighbors (v3, list, surface);
-    i = list;
-    while (i && *face == NULL) {
-      GtsVertex * v = i->data;
-      if (v != v1 && v != v2 && v != v3 &&
-	  gts_point_in_circle (GTS_POINT (v), 
-			       GTS_POINT (v1),
-			       GTS_POINT (v2),  
-			       GTS_POINT (v3)) > 0.)
-	*face = GTS_FACE (t);
-      i = i->next;
-    }
-    g_slist_free (list);
-  }
-}
-
-/**
- * gts_delaunay_check:
- * @surface: a #GtsSurface.
- *
- * Returns: %NULL if the planar projection of @surface is a Delaunay 
- * triangulation (unconstrained), a #GtsFace violating the Delaunay
- * property otherwise.
- */
-GtsFace * gts_delaunay_check (GtsSurface * surface)
-{
-  GtsFace * face = NULL;
-  gpointer data[2];
-
-  g_return_val_if_fail (surface != NULL, FALSE);
-
-  data[0] = surface;
-  data[1] = &face;
-  gts_surface_foreach_face (surface, (GtsFunc) delaunay_check, data);
-
-  return face;
-}
-
-/**
- * gts_delaunay_remove_hull:
- * @surface: a #GtsSurface.
- *
- * Removes all the edges of the boundary of @surface which are not
- * constraints.  
- */
-void gts_delaunay_remove_hull (GtsSurface * surface)
-{
-  GSList * boundary;
-
-  g_return_if_fail (surface != NULL);
-
-  boundary = gts_surface_boundary (surface);
-  gts_allow_floating_edges = TRUE;
-  while (boundary) {
-    GSList * i = boundary;
-    GtsEdge * e = i->data;
-
-    boundary = i->next;
-    g_slist_free_1 (i);
-    if (!GTS_IS_CONSTRAINT (e)) {
-      GtsTriangle * t = GTS_TRIANGLE (gts_edge_is_boundary (e, surface));
-
-      if (t != NULL) {
-	if (t->e1 != e && !GTS_IS_CONSTRAINT (t->e1) &&
-	    !gts_edge_is_boundary (t->e1, surface))
-	  boundary = g_slist_prepend (boundary, t->e1);
-	if (t->e2 != e && !GTS_IS_CONSTRAINT (t->e2) &&
-	    !gts_edge_is_boundary (t->e2, surface))
-	  boundary = g_slist_prepend (boundary, t->e2);
-	if (t->e3 != e && !GTS_IS_CONSTRAINT (t->e3) &&
-	    !gts_edge_is_boundary (t->e3, surface))
-	  boundary = g_slist_prepend (boundary, t->e3);
-	gts_surface_remove_face (surface, GTS_FACE (t));
-      }
-      if (!e->triangles)
-	gts_object_destroy (GTS_OBJECT (e));
-    }
-  }
-  gts_allow_floating_edges = FALSE;
-}
-
-/* GtsListFace: Object */
-
-static void gts_list_face_destroy (GtsObject * object)
-{
-  g_slist_free (GTS_LIST_FACE (object)->points);
-
-  (* GTS_OBJECT_CLASS (gts_list_face_class ())->parent_class->destroy) 
-    (object);
-}
-
-static void gts_list_face_class_init (GtsFaceClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->destroy = gts_list_face_destroy;
-}
-
-GtsFaceClass * gts_list_face_class (void)
-{
-  static GtsFaceClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo gts_list_face_info = {
-      "GtsListFace",
-      sizeof (GtsListFace),
-      sizeof (GtsFaceClass),
-      (GtsObjectClassInitFunc) gts_list_face_class_init,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_face_class ()),
-				  &gts_list_face_info);
-  }
-
-  return klass;
-}
diff --git a/src_3rd/gts/container.c b/src_3rd/gts/container.c
deleted file mode 100644
index e1dc0fa..0000000
--- a/src_3rd/gts/container.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-/* GtsContainee */
-
-static void containee_class_init (GtsContaineeClass * klass)
-{
-  klass->remove_container = NULL;
-  klass->add_container = NULL;
-  klass->foreach = NULL;
-  klass->is_contained = NULL;
-  klass->replace = NULL;
-}
-
-GtsContaineeClass * gts_containee_class (void)
-{
-  static GtsContaineeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo containee_info = {
-      "GtsContainee",
-      sizeof (GtsContainee),
-      sizeof (GtsContaineeClass),
-      (GtsObjectClassInitFunc) containee_class_init,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (),
-				  &containee_info);
-  }
-
-  return klass;
-}
-
-GtsContainee * gts_containee_new (GtsContaineeClass * klass)
-{
-  GtsContainee * object;
-
-  object = GTS_CONTAINEE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-
-  return object;
-}
-
-gboolean gts_containee_is_contained (GtsContainee * item,
-				     GtsContainer * c)
-{
-  g_return_val_if_fail (item != NULL, FALSE);
-  g_return_val_if_fail (c != NULL, FALSE);
-
-  if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->is_contained)
-    return
-      (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->is_contained) 
-      (item, c);
-  return FALSE;
-}
-
-void gts_containee_replace (GtsContainee * item,
-			    GtsContainee * with)
-{
-  if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->replace)
-    (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->replace) (item, with);
-  if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) {
-    (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) 
-      (item, (GtsFunc) gts_container_add, with);
-    (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) 
-      (item, (GtsFunc) gts_container_remove, item);
-  }
-}
-
-/* GtsSListContainee */
-
-static void slist_containee_destroy (GtsObject * object)
-{
-  GtsSListContainee * item = GTS_SLIST_CONTAINEE (object);
-  GSList * i;
-
-  i = item->containers;
-  while (i) {
-    GSList * next = i->next;
-
-    gts_container_remove (i->data, GTS_CONTAINEE (item));
-    i = next;
-  }
-  g_assert (item->containers == NULL);
-
-  (* GTS_OBJECT_CLASS (gts_slist_containee_class ())->parent_class->destroy) 
-    (object);
-}
-
-static void slist_containee_remove_container (GtsContainee * i, 
-					      GtsContainer * c)
-{
-  GtsSListContainee * item = GTS_SLIST_CONTAINEE (i);
-  item->containers = g_slist_remove (item->containers, c);
-}
-
-static void slist_containee_add_container (GtsContainee * i, 
-					   GtsContainer * c)
-{
-  GtsSListContainee * item = GTS_SLIST_CONTAINEE (i);
-  if (!g_slist_find (item->containers, c))
-    item->containers = g_slist_prepend (item->containers, c);
-}
-
-static void slist_containee_foreach (GtsContainee * c,
-				     GtsFunc func, 
-				     gpointer data)
-{
-  GSList * i = GTS_SLIST_CONTAINEE (c)->containers;
-
-  while (i) {
-    GSList * next = i->next;
-    
-    (* func) (i->data, data);
-    i = next;
-  }
-}
-
-static gboolean slist_containee_is_contained (GtsContainee * i,
-					      GtsContainer * c)
-{
-  return g_slist_find (GTS_SLIST_CONTAINEE (i)->containers, c) ? TRUE : FALSE;
-}
-
-static void slist_containee_class_init (GtsSListContaineeClass * klass)
-{
-  GTS_CONTAINEE_CLASS (klass)->remove_container = 
-    slist_containee_remove_container;
-  GTS_CONTAINEE_CLASS (klass)->add_container = 
-    slist_containee_add_container;
-  GTS_CONTAINEE_CLASS (klass)->foreach = 
-    slist_containee_foreach;
-  GTS_CONTAINEE_CLASS (klass)->is_contained = 
-    slist_containee_is_contained;
-
-  GTS_OBJECT_CLASS (klass)->destroy = slist_containee_destroy;
-}
-
-static void slist_containee_init (GtsSListContainee * object)
-{
-  object->containers = NULL;
-}
-
-GtsSListContaineeClass * gts_slist_containee_class (void)
-{
-  static GtsSListContaineeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo slist_containee_info = {
-      "GtsSListContainee",
-      sizeof (GtsSListContainee),
-      sizeof (GtsSListContaineeClass),
-      (GtsObjectClassInitFunc) slist_containee_class_init,
-      (GtsObjectInitFunc) slist_containee_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_containee_class ()),
-				  &slist_containee_info);
-  }
-
-  return klass;
-}
-
-/* GtsContainer */
-
-static void remove_container (GtsContainee * item, GtsContainer * c)
-{
-  if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container)
-    (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) 
-      (item, c);
-}
-
-static void container_destroy (GtsObject * object)
-{
-  GtsContainer * c = GTS_CONTAINER (object);
-
-  gts_container_foreach (c, (GtsFunc) remove_container, c);
-
-  (* GTS_OBJECT_CLASS (gts_container_class ())->parent_class->destroy) 
-    (object);
-}
-
-static void container_add (GtsContainer * c, GtsContainee * item)
-{
-  if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->add_container)
-    (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->add_container)
-      (item, c);
-}
-
-static void container_remove (GtsContainer * c, GtsContainee * item)
-{
-  if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container)
-    (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container)
-      (item, c);
-}
-
-static void container_clone_add (GtsContainee * item, GtsContainer * clone)
-{
-  gts_container_add (clone, item);
-}
-
-static void container_clone (GtsObject * clone, GtsObject * object)
-{
-  gts_object_init (clone, object->klass);
-  gts_container_foreach (GTS_CONTAINER (object), 
-			 (GtsFunc) container_clone_add, clone);
-}
-
-static void container_class_init (GtsContainerClass * klass)
-{
-  klass->add = container_add;
-  klass->remove = container_remove;
-  klass->foreach = NULL;
-  klass->size = NULL;
-
-  GTS_OBJECT_CLASS (klass)->destroy = container_destroy;
-  GTS_OBJECT_CLASS (klass)->clone = container_clone;
-}
-
-GtsContainerClass * gts_container_class (void)
-{
-  static GtsContainerClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo container_info = {
-      "GtsContainer",
-      sizeof (GtsContainer),
-      sizeof (GtsContainerClass),
-      (GtsObjectClassInitFunc) container_class_init,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = 
-      gts_object_class_new (GTS_OBJECT_CLASS (gts_slist_containee_class ()), 
-			    &container_info);
-  }
-
-  return klass;
-}
-
-GtsContainer * gts_container_new (GtsContainerClass * klass)
-{
-  GtsContainer * object;
-
-  object = GTS_CONTAINER (gts_object_new (GTS_OBJECT_CLASS (klass)));
-
-  return object;
-}
-
-void gts_container_add (GtsContainer * c,
-			GtsContainee * item)
-{
-  g_return_if_fail (c != NULL);
-  g_return_if_fail (item != NULL);
-
-  g_assert (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->add);
-  (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->add) (c, item);
-}
-
-void gts_container_remove (GtsContainer * c,
-			   GtsContainee * item)
-{
-  g_return_if_fail (c != NULL);
-  g_return_if_fail (item != NULL);
-
-  g_assert (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->remove);
-  (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->remove) (c, item);
-}
-
-void gts_container_foreach (GtsContainer * c,
-			    GtsFunc func,
-			    gpointer data)
-{
-  g_return_if_fail (c != NULL);
-  g_return_if_fail (func != NULL);
-
-  if (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->foreach)
-    (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->foreach) (c, func, data);
-}
-
-guint gts_container_size (GtsContainer * c)
-{
-  g_return_val_if_fail (c != NULL, 0);
-
-  if (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->size)
-    return (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->size) (c);
-  return 0;
-}
-
-/* GtsHashContainer */
-
-static void hash_container_destroy (GtsObject * object)
-{
-  GHashTable * items = GTS_HASH_CONTAINER (object)->items;
-
-  (* GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class->destroy) 
-    (object);
-
-  g_hash_table_destroy (items);
-}
-
-static void hash_container_add (GtsContainer * c, GtsContainee * item)
-{
-  g_return_if_fail (GTS_HASH_CONTAINER (c)->frozen == FALSE);
-
-  g_hash_table_insert (GTS_HASH_CONTAINER (c)->items, item, NULL);
-
-  (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class)->add) (c, item);
-}
-
-static void hash_container_remove (GtsContainer * c, GtsContainee * item)
-{
-  g_return_if_fail (GTS_HASH_CONTAINER (c)->frozen == FALSE);
-
-  g_hash_table_remove (GTS_HASH_CONTAINER (c)->items, item);
-
-  (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class)->remove) (c, item);
-}
-
-static void hash_foreach (GtsContainee * item, 
-			  gpointer item_data, 
-			  gpointer * info)
-{
-  (* ((GtsFunc) info[0])) (item, info[1]);
-}
-
-static void hash_container_foreach (GtsContainer * c, 
-				    GtsFunc func, 
-				    gpointer data)
-{
-  gpointer info[2];
-  
-  info[0] = func;
-  info[1] = data;
-  /* prevent removing or adding items */
-  GTS_HASH_CONTAINER (c)->frozen = TRUE;
-  g_hash_table_foreach (GTS_HASH_CONTAINER (c)->items, 
-			(GHFunc) hash_foreach, info);
-  GTS_HASH_CONTAINER (c)->frozen = FALSE;
-}
-
-static guint hash_container_size (GtsContainer * c)
-{
-  return g_hash_table_size (GTS_HASH_CONTAINER (c)->items);
-}
-
-static void hash_container_class_init (GtsHashContainerClass * klass)
-{
-  GTS_CONTAINER_CLASS (klass)->add = hash_container_add;
-  GTS_CONTAINER_CLASS (klass)->remove = hash_container_remove;
-  GTS_CONTAINER_CLASS (klass)->foreach = hash_container_foreach;
-  GTS_CONTAINER_CLASS (klass)->size = hash_container_size;
-
-  GTS_OBJECT_CLASS (klass)->destroy = hash_container_destroy;
-}
-
-static void hash_container_init (GtsHashContainer * object)
-{
-  object->items = g_hash_table_new (NULL, NULL);
-  object->frozen = FALSE;
-}
-
-GtsHashContainerClass * gts_hash_container_class (void)
-{
-  static GtsHashContainerClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo hash_container_info = {
-      "GtsHashContainer",
-      sizeof (GtsHashContainer),
-      sizeof (GtsHashContainerClass),
-      (GtsObjectClassInitFunc) hash_container_class_init,
-      (GtsObjectInitFunc) hash_container_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_container_class ()),
-				  &hash_container_info);
-  }
-
-  return klass;
-}
-
-/* GtsSListContainer */
-
-static void slist_container_destroy (GtsObject * object)
-{
-  GSList * items = GTS_SLIST_CONTAINER (object)->items;
-
-  (* GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class->destroy) 
-    (object);
-
-  g_slist_free (items);
-}
-
-static void slist_container_add (GtsContainer * c, GtsContainee * item)
-{
-  g_return_if_fail (GTS_SLIST_CONTAINER (c)->frozen == FALSE);
-
-  if (!g_slist_find (GTS_SLIST_CONTAINER (c)->items, item))
-    GTS_SLIST_CONTAINER (c)->items = 
-      g_slist_prepend (GTS_SLIST_CONTAINER (c)->items, item);
-
-  (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class)->add) (c, item);
-}
-
-static void slist_container_remove (GtsContainer * c, GtsContainee * item)
-{
-  g_return_if_fail (GTS_SLIST_CONTAINER (c)->frozen == FALSE);
-
-  GTS_SLIST_CONTAINER (c)->items = 
-      g_slist_remove (GTS_SLIST_CONTAINER (c)->items, item);
-
-  (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class)->remove) (c, item);
-}
-
-static void slist_container_foreach (GtsContainer * c, 
-				     GtsFunc func, 
-				     gpointer data)
-{
-  GSList * i;
-
-  i = GTS_SLIST_CONTAINER (c)->items;
-  while (i) {
-    GSList * next = i->next;
-
-    (* func) (i->data, data);
-    i = next;
-  }
-}
-
-static guint slist_container_size (GtsContainer * c)
-{
-  return g_slist_length (GTS_SLIST_CONTAINER (c)->items);
-}
-
-static void slist_container_class_init (GtsSListContainerClass * klass)
-{
-  GTS_CONTAINER_CLASS (klass)->add = slist_container_add;
-  GTS_CONTAINER_CLASS (klass)->remove = slist_container_remove;
-  GTS_CONTAINER_CLASS (klass)->foreach = slist_container_foreach;
-  GTS_CONTAINER_CLASS (klass)->size = slist_container_size;
-
-  GTS_OBJECT_CLASS (klass)->destroy = slist_container_destroy;
-}
-
-static void slist_container_init (GtsSListContainer * object)
-{
-  object->items = NULL;
-  object->frozen = FALSE;
-}
-
-GtsSListContainerClass * gts_slist_container_class (void)
-{
-  static GtsSListContainerClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo slist_container_info = {
-      "GtsSListContainer",
-      sizeof (GtsSListContainer),
-      sizeof (GtsSListContainerClass),
-      (GtsObjectClassInitFunc) slist_container_class_init,
-      (GtsObjectInitFunc) slist_container_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_container_class ()),
-				  &slist_container_info);
-  }
-
-  return klass;
-}
diff --git a/src_3rd/gts/curvature.c b/src_3rd/gts/curvature.c
deleted file mode 100644
index 70f6af2..0000000
--- a/src_3rd/gts/curvature.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999-2002 Ray Jones, St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include "gts.h"
-
-static gboolean angle_obtuse (GtsVertex * v, GtsFace * f)
-{
-  GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v);
-  GtsVector vec1, vec2;
-
-  gts_vector_init (vec1, GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v1));
-  gts_vector_init (vec2, GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v2));
-
-  return (gts_vector_scalar (vec1, vec2) < 0.0);
-}
-
-static gboolean triangle_obtuse (GtsVertex * v, GtsFace * f)
-{
-  GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v);
-
-  return (angle_obtuse (v, f) ||
-          angle_obtuse (GTS_SEGMENT (e)->v1, f) ||
-          angle_obtuse (GTS_SEGMENT (e)->v2, f));
-} 
-
-static gdouble cotan (GtsVertex * vo, GtsVertex * v1, GtsVertex * v2)
-{
-  /* cf. Appendix B of [Meyer et al 2002] */
-  GtsVector u, v;
-  gdouble udotv, denom;
-
-  gts_vector_init (u, GTS_POINT (vo), GTS_POINT (v1));
-  gts_vector_init (v, GTS_POINT (vo), GTS_POINT (v2));
-
-  udotv = gts_vector_scalar (u, v);
-  denom = sqrt (gts_vector_scalar (u,u)*gts_vector_scalar (v,v) -
-		udotv*udotv);
-
-
-  /* denom can be zero if u==v.  Returning 0 is acceptable, based on
-   * the callers of this function below. */
-  if (denom == 0.0) return (0.0);
-
-  return (udotv/denom);
-}
-
-static gdouble angle_from_cotan (GtsVertex * vo, 
-				 GtsVertex * v1, GtsVertex * v2)
-{
-  /* cf. Appendix B and the caption of Table 1 from [Meyer et al 2002] */
-  GtsVector u, v;
-  gdouble udotv, denom;
-
-  gts_vector_init (u, GTS_POINT (vo), GTS_POINT (v1));
-  gts_vector_init (v, GTS_POINT (vo), GTS_POINT (v2));
-
-  udotv = gts_vector_scalar (u, v);
-  denom = sqrt (gts_vector_scalar (u,u)*gts_vector_scalar (v,v) 
-		- udotv*udotv);
-
-  /* Note: I assume this is what they mean by using atan2 (). -Ray Jones */
-
-  /* tan = denom/udotv = y/x (see man page for atan2) */
-  return (fabs (atan2 (denom, udotv)));
-}
-
-static gdouble region_area (GtsVertex * v, GtsFace * f)
-{
-  /* cf. Section 3.3 of [Meyer et al 2002] */
-  
-  if (gts_triangle_area (GTS_TRIANGLE (f)) == 0.0) return (0.0);
-
-  if (triangle_obtuse (v, f)) {
-    if (angle_obtuse (v, f))
-      return (gts_triangle_area (GTS_TRIANGLE (f))/2.0);
-    else
-      return (gts_triangle_area (GTS_TRIANGLE (f))/4.0);
-  } else {
-    GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v);
-
-    return ((cotan (GTS_SEGMENT (e)->v1, v, GTS_SEGMENT (e)->v2)* 
-             gts_point_distance2 (GTS_POINT (v), 
-				  GTS_POINT (GTS_SEGMENT (e)->v2)) +
-             cotan (GTS_SEGMENT (e)->v2, v, GTS_SEGMENT (e)->v1)* 
-             gts_point_distance2 (GTS_POINT (v), 
-                                  GTS_POINT (GTS_SEGMENT (e)->v1)))
-            /8.0);
-  }
-}
-
-/** 
- * gts_vertex_mean_curvature_normal:
- * @v: a #GtsVertex.  
- * @s: a #GtsSurface.
- * @Kh: the Mean Curvature Normal at @v.
- *
- * Computes the Discrete Mean Curvature Normal approximation at @v.
- * The mean curvature at @v is half the magnitude of the vector @Kh.
- *
- * Note: the normal computed is not unit length, and may point either
- * into or out of the surface, depending on the curvature at @v.  It
- * is the responsibility of the caller of the function to use the mean
- * curvature normal appropriately.
- *
- * This approximation is from the paper:
- * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
- * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
- * VisMath '02, Berlin (Germany) 
- * http://www-grail.usc.edu/pubs.html
- *
- * Returns: %TRUE if the operator could be evaluated, %FALSE if the
- * evaluation failed for some reason (@v is boundary or is the
- * endpoint of a non-manifold edge.)
- */
-gboolean gts_vertex_mean_curvature_normal (GtsVertex * v, GtsSurface * s, 
-                                           GtsVector Kh)
-{
-  GSList * faces, * edges, * i;
-  gdouble area = 0.0;
-
-  g_return_val_if_fail (v != NULL, FALSE);
-  g_return_val_if_fail (s != NULL, FALSE);
-
-  /* this operator is not defined for boundary edges */
-  if (gts_vertex_is_boundary (v, s)) return (FALSE);
-    
-  faces = gts_vertex_faces (v, s, NULL);
-  g_return_val_if_fail (faces != NULL, FALSE);
-
-  edges = gts_vertex_fan_oriented (v, s);
-  if (edges == NULL) {
-    g_slist_free (faces);
-    return (FALSE);
-  }
-
-  i = faces;
-  while (i) {
-    GtsFace * f = i->data;
-
-    area += region_area (v, f);
-    i = i->next;
-  } 
-  g_slist_free (faces);
-
-  Kh[0] = Kh[1] = Kh[2] = 0.0;
-
-  i = edges;
-  while (i) {
-    GtsEdge * e = i->data;
-    GtsVertex * v1 = GTS_SEGMENT (e)->v1;
-    GtsVertex * v2 = GTS_SEGMENT (e)->v2;
-    gdouble temp;
-
-    temp = cotan (v1, v, v2);
-    Kh[0] += temp*(GTS_POINT (v2)->x - GTS_POINT (v)->x);
-    Kh[1] += temp*(GTS_POINT (v2)->y - GTS_POINT (v)->y);
-    Kh[2] += temp*(GTS_POINT (v2)->z - GTS_POINT (v)->z);
-
-    temp = cotan (v2, v, v1);
-    Kh[0] += temp*(GTS_POINT (v1)->x - GTS_POINT (v)->x);
-    Kh[1] += temp*(GTS_POINT (v1)->y - GTS_POINT (v)->y);
-    Kh[2] += temp*(GTS_POINT (v1)->z - GTS_POINT (v)->z);
-
-    i = i->next;
-  }
-  g_slist_free (edges);
-
-  if (area > 0.0) {
-    Kh[0] /= 2*area;
-    Kh[1] /= 2*area;
-    Kh[2] /= 2*area;
-  } else {
-    return (FALSE);
-  }
- 
-  return TRUE;
-}
-
-/** 
- * gts_vertex_gaussian_curvature:
- * @v: a #GtsVertex.  
- * @s: a #GtsSurface.
- * @Kg: the Discrete Gaussian Curvature approximation at @v.
- *
- * Computes the Discrete Gaussian Curvature approximation at @v.
- *
- * This approximation is from the paper:
- * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
- * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
- * VisMath '02, Berlin (Germany) 
- * http://www-grail.usc.edu/pubs.html
- *
- * Returns: %TRUE if the operator could be evaluated, %FALSE if the
- * evaluation failed for some reason (@v is boundary or is the
- * endpoint of a non-manifold edge.)
- */
-gboolean gts_vertex_gaussian_curvature (GtsVertex * v, GtsSurface * s, 
-                                        gdouble * Kg)
-{
-  GSList * faces, * edges, * i;
-  gdouble area = 0.0;
-  gdouble angle_sum = 0.0;
-
-  g_return_val_if_fail (v != NULL, FALSE);
-  g_return_val_if_fail (s != NULL, FALSE);
-  g_return_val_if_fail (Kg != NULL, FALSE);
-
-  /* this operator is not defined for boundary edges */
-  if (gts_vertex_is_boundary (v, s)) return (FALSE);
-    
-  faces = gts_vertex_faces (v, s, NULL);
-  g_return_val_if_fail (faces != NULL, FALSE);
-
-  edges = gts_vertex_fan_oriented (v, s);
-  if (edges == NULL) {
-    g_slist_free (faces);
-    return (FALSE);
-  }
-
-  i = faces;
-  while (i) {
-    GtsFace * f = i->data;
-
-    area += region_area (v, f);
-    i = i->next;
-  } 
-  g_slist_free (faces);
-
-  i = edges;
-  while (i) {
-    GtsEdge * e = i->data;
-    GtsVertex * v1 = GTS_SEGMENT (e)->v1;
-    GtsVertex * v2 = GTS_SEGMENT (e)->v2;
-
-    angle_sum += angle_from_cotan (v, v1, v2);
-    i = i->next;
-  }
-  g_slist_free (edges);
-
-  *Kg = (2.0*M_PI - angle_sum)/area;
- 
-  return TRUE;
-}
-
-/** 
- * gts_vertex_principal_curvatures:
- * @Kh: mean curvature.
- * @Kg: Gaussian curvature.
- * @K1: first principal curvature.
- * @K2: second principal curvature.
- *
- * Computes the principal curvatures at a point given the mean and
- * Gaussian curvatures at that point.  
- *
- * The mean curvature can be computed as one-half the magnitude of the
- * vector computed by gts_vertex_mean_curvature_normal().
- *
- * The Gaussian curvature can be computed with
- * gts_vertex_gaussian_curvature().
- */
-void gts_vertex_principal_curvatures (gdouble Kh, gdouble Kg, 
-				      gdouble * K1, gdouble * K2)
-{
-  gdouble temp = Kh*Kh - Kg;
-
-  g_return_if_fail (K1 != NULL);
-  g_return_if_fail (K2 != NULL);
-
-  if (temp < 0.0) temp = 0.0;
-  temp = sqrt (temp);
-  *K1 = Kh + temp;
-  *K2 = Kh - temp;
-}
-
-/* from Maple */
-static void linsolve (gdouble m11, gdouble m12, gdouble b1,
-		      gdouble m21, gdouble m22, gdouble b2,
-		      gdouble * x1, gdouble * x2)
-{
-  gdouble temp;
-
-  temp = 1.0 / (m21*m12 - m11*m22);
-  *x1 = (m12*b2 - m22*b1)*temp;
-  *x2 = (m11*b2 - m21*b1)*temp;
-}
-                
-/* from Maple - largest eigenvector of [a b; b c] */
-static void eigenvector (gdouble a, gdouble b, gdouble c,
-			 GtsVector e)
-{
-  if (b == 0.0) {
-    e[0] = 0.0;
-  } else {
-    e[0] = -(c - a - sqrt (c*c - 2*a*c + a*a + 4*b*b))/(2*b);
-  }
-  e[1] = 1.0;
-  e[2] = 0.0;
-}
-
-/** 
- * gts_vertex_principal_directions:
- * @v: a #GtsVertex.  
- * @s: a #GtsSurface.
- * @Kh: mean curvature normal (a #GtsVector).
- * @Kg: Gaussian curvature (a gdouble).
- * @e1: first principal curvature direction (direction of largest curvature).
- * @e2: second principal curvature direction.
- *
- * Computes the principal curvature directions at a point given @Kh
- * and @Kg, the mean curvature normal and Gaussian curvatures at that
- * point, computed with gts_vertex_mean_curvature_normal() and
- * gts_vertex_gaussian_curvature(), respectively. 
- *
- * Note that this computation is very approximate and tends to be
- * unstable.  Smoothing of the surface or the principal directions may
- * be necessary to achieve reasonable results.  
- */
-void gts_vertex_principal_directions (GtsVertex * v, GtsSurface * s,
-                                      GtsVector Kh, gdouble Kg,
-				      GtsVector e1, GtsVector e2)
-{
-  GtsVector N;
-  gdouble normKh;
-  GSList * i, * j;
-  GtsVector basis1, basis2, d, eig;
-  gdouble ve2, vdotN;
-  gdouble aterm_da, bterm_da, cterm_da, const_da;
-  gdouble aterm_db, bterm_db, cterm_db, const_db;
-  gdouble a, b, c;
-  gdouble K1, K2;
-  gdouble *weights, *kappas, *d1s, *d2s;
-  gint edge_count;
-  gdouble err_e1, err_e2;
-  int e;
-
-  /* compute unit normal */
-  normKh = sqrt (gts_vector_scalar (Kh, Kh));
-
-  if (normKh > 0.0) {
-    N[0] = Kh[0] / normKh;
-    N[1] = Kh[1] / normKh;
-    N[2] = Kh[2] / normKh;
-  } else {
-    /* This vertex is a point of zero mean curvature (flat or saddle
-     * point).  Compute a normal by averaging the adjacent triangles
-     */
-    N[0] = N[1] = N[2] = 0.0;
-    i = gts_vertex_faces (v, s, NULL);
-    while (i) {
-      gdouble x, y, z;
-      gts_triangle_normal (GTS_TRIANGLE ((GtsFace *) i->data),
-                           &x, &y, &z);
-      N[0] += x;
-      N[1] += y;
-      N[2] += z;
-
-      i = i->next;
-    }
-    g_return_if_fail (gts_vector_norm (N) > 0.0);
-    gts_vector_normalize (N);
-  }
-    
-
-  /* construct a basis from N: */
-  /* set basis1 to any component not the largest of N */
-  basis1[0] =  basis1[1] =  basis1[2] = 0.0;
-  if (fabs (N[0]) > fabs (N[1]))
-    basis1[1] = 1.0;
-  else
-    basis1[0] = 1.0;
-    
-  /* make basis2 orthogonal to N */
-  gts_vector_cross (basis2, N, basis1);
-  gts_vector_normalize (basis2);
-
-  /* make basis1 orthogonal to N and basis2 */
-  gts_vector_cross (basis1, N, basis2);
-  gts_vector_normalize (basis1);
-  
-  aterm_da = bterm_da = cterm_da = const_da = 0.0;
-  aterm_db = bterm_db = cterm_db = const_db = 0.0;
-
-  weights = g_malloc (sizeof (gdouble)*g_slist_length (v->segments));
-  kappas = g_malloc (sizeof (gdouble)*g_slist_length (v->segments));
-  d1s = g_malloc (sizeof (gdouble)*g_slist_length (v->segments));
-  d2s = g_malloc (sizeof (gdouble)*g_slist_length (v->segments));
-  edge_count = 0;
-
-  i = v->segments;
-  while (i) {
-    GtsEdge * e;
-    GtsFace * f1, * f2;
-    gdouble weight, kappa, d1, d2;
-    GtsVector vec_edge;
-
-    if (! GTS_IS_EDGE (i->data)) {
-      i = i->next;
-      continue;
-    }
-
-    e = i->data;
-
-    /* since this vertex passed the tests in
-     * gts_vertex_mean_curvature_normal(), this should be true. */
-    g_assert (gts_edge_face_number (e, s) == 2);
-
-    /* identify the two triangles bordering e in s */
-    f1 = f2 = NULL;
-    j = e->triangles;
-    while (j) {
-      if ((! GTS_IS_FACE (j->data)) || 
-          (! gts_face_has_parent_surface (GTS_FACE (j->data), s))) {
-        j = j->next;
-        continue;
-      }
-      if (f1 == NULL)
-        f1 = GTS_FACE (j->data);
-      else {
-        f2 = GTS_FACE (j->data);
-        break;
-      }
-      j = j->next;
-    }
-    g_assert (f2 != NULL);
-
-    /* We are solving for the values of the curvature tensor 
-     *     B = [ a b ; b c ].  
-     * The computations here are from section 5 of [Meyer et al 2002].  
-     *
-     * The first step is to calculate the linear equations governing
-     * the values of (a,b,c).  These can be computed by setting the
-     * derivatives of the error E to zero (section 5.3).
-     * 
-     * Since a + c = norm(Kh), we only compute the linear equations
-     * for dE/da and dE/db.  (NB: [Meyer et al 2002] has the
-     * equation a + b = norm(Kh), but I'm almost positive this is
-     * incorrect.)
-     *
-     * Note that the w_ij (defined in section 5.2) are all scaled by
-     * (1/8*A_mixed).  We drop this uniform scale factor because the
-     * solution of the linear equations doesn't rely on it.
-     *
-     * The terms of the linear equations are xterm_dy with x in
-     * {a,b,c} and y in {a,b}.  There are also const_dy terms that are
-     * the constant factors in the equations.  
-     */
-
-    /* find the vector from v along edge e */
-    gts_vector_init (vec_edge, GTS_POINT (v), 
-                     GTS_POINT ((GTS_SEGMENT (e)->v1 == v) ? 
-                                GTS_SEGMENT (e)->v2 : GTS_SEGMENT (e)->v1));
-    ve2 = gts_vector_scalar (vec_edge, vec_edge);
-    vdotN = gts_vector_scalar (vec_edge, N);
-
-    /* section 5.2 - There is a typo in the computation of kappa.  The
-     * edges should be x_j-x_i.
-     */
-    kappa = 2.0 * vdotN / ve2;
-
-    /* section 5.2 */
-
-    /* I don't like performing a minimization where some of the
-     * weights can be negative (as can be the case if f1 or f2 are
-     * obtuse).  To ensure all-positive weights, we check for
-     * obtuseness and use values similar to those in region_area(). */
-    weight = 0.0;
-    if (! triangle_obtuse(v, f1)) {
-      weight += ve2 * 
-        cotan (gts_triangle_vertex_opposite (GTS_TRIANGLE (f1), e), 
-               GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2) / 8.0;
-    } else {
-      if (angle_obtuse (v, f1)) {
-        weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f1)) / 4.0;
-      } else {
-        weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f1)) / 8.0;
-      }
-    }
-
-    if (! triangle_obtuse(v, f2)) {
-      weight += ve2 * 
-        cotan (gts_triangle_vertex_opposite (GTS_TRIANGLE (f2), e), 
-               GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2) / 8.0;
-    } else {
-      if (angle_obtuse (v, f2)) {
-        weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f2)) / 4.0;
-      } else {
-        weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f2)) / 8.0;
-      }
-    }
-
-    /* projection of edge perpendicular to N (section 5.3) */
-    d[0] = vec_edge[0] - vdotN * N[0];
-    d[1] = vec_edge[1] - vdotN * N[1];
-    d[2] = vec_edge[2] - vdotN * N[2];
-    gts_vector_normalize (d);
-    
-    /* not explicit in the paper, but necessary.  Move d to 2D basis. */
-    d1 = gts_vector_scalar (d, basis1);
-    d2 = gts_vector_scalar (d, basis2);
-
-    /* store off the curvature, direction of edge, and weights for later use */
-    weights[edge_count] = weight;
-    kappas[edge_count] = kappa;
-    d1s[edge_count] = d1;
-    d2s[edge_count] = d2;
-    edge_count++;
-
-    /* Finally, update the linear equations */
-    aterm_da += weight * d1 * d1 * d1 * d1;
-    bterm_da += weight * d1 * d1 * 2 * d1 * d2;
-    cterm_da += weight * d1 * d1 * d2 * d2;
-    const_da += weight * d1 * d1 * (- kappa);
-
-    aterm_db += weight * d1 * d2 * d1 * d1;
-    bterm_db += weight * d1 * d2 * 2 * d1 * d2;
-    cterm_db += weight * d1 * d2 * d2 * d2;
-    const_db += weight * d1 * d2 * (- kappa);
-
-    i = i->next;
-  }
-
-  /* now use the identity (Section 5.3) a + c = |Kh| = 2 * kappa_h */
-  aterm_da -= cterm_da;
-  const_da += cterm_da * normKh;
-
-  aterm_db -= cterm_db;
-  const_db += cterm_db * normKh;
-  
-  /* check for solvability of the linear system */
-  if (((aterm_da * bterm_db - aterm_db * bterm_da) != 0.0) &&
-      ((const_da != 0.0) || (const_db != 0.0))) {
-    linsolve (aterm_da, bterm_da, -const_da,
-              aterm_db, bterm_db, -const_db,
-              &a, &b);
-
-    c = normKh - a;
-
-    eigenvector (a, b, c, eig);
-  } else {
-    /* region of v is planar */
-    eig[0] = 1.0;
-    eig[1] = 0.0;
-  }
-
-  /* Although the eigenvectors of B are good estimates of the
-   * principal directions, it seems that which one is attached to
-   * which curvature direction is a bit arbitrary.  This may be a bug
-   * in my implementation, or just a side-effect of the inaccuracy of
-   * B due to the discrete nature of the sampling.
-   *
-   * To overcome this behavior, we'll evaluate which assignment best
-   * matches the given eigenvectors by comparing the curvature
-   * estimates computed above and the curvatures calculated from the
-   * discrete differential operators.  */
-
-  gts_vertex_principal_curvatures (0.5 * normKh, Kg, &K1, &K2);
-  
-  err_e1 = err_e2 = 0.0;
-  /* loop through the values previously saved */
-  for (e = 0; e < edge_count; e++) {
-    gdouble weight, kappa, d1, d2;
-    gdouble temp1, temp2;
-    gdouble delta;
-
-    weight = weights[e];
-    kappa = kappas[e];
-    d1 = d1s[e];
-    d2 = d2s[e];
-
-    temp1 = fabs (eig[0] * d1 + eig[1] * d2);
-    temp1 = temp1 * temp1;
-    temp2 = fabs (eig[1] * d1 - eig[0] * d2);
-    temp2 = temp2 * temp2;
-
-    /* err_e1 is for K1 associated with e1 */
-    delta = K1 * temp1 + K2 * temp2 - kappa;
-    err_e1 += weight * delta * delta;
-
-    /* err_e2 is for K1 associated with e2 */
-    delta = K2 * temp1 + K1 * temp2 - kappa;
-    err_e2 += weight * delta * delta;
-  }
-  g_free (weights);
-  g_free (kappas);
-  g_free (d1s);
-  g_free (d2s);
-
-  /* rotate eig by a right angle if that would decrease the error */
-  if (err_e2 < err_e1) {
-    gdouble temp = eig[0];
-
-    eig[0] = eig[1];
-    eig[1] = -temp;
-  }
-
-  e1[0] = eig[0] * basis1[0] + eig[1] * basis2[0];
-  e1[1] = eig[0] * basis1[1] + eig[1] * basis2[1];
-  e1[2] = eig[0] * basis1[2] + eig[1] * basis2[2];
-  gts_vector_normalize (e1);
-
-  /* make N,e1,e2 a right handed coordinate sytem */
-  gts_vector_cross (e2, N, e1);
-  gts_vector_normalize (e2);
-}
diff --git a/src_3rd/gts/edge.c b/src_3rd/gts/edge.c
deleted file mode 100644
index 708c06c..0000000
--- a/src_3rd/gts/edge.c
+++ /dev/null
@@ -1,582 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-gboolean gts_allow_floating_edges = FALSE;
-
-static void edge_destroy (GtsObject * object)
-{
-  GtsEdge * edge = GTS_EDGE (object);
-  GSList * i;
-
-  i = edge->triangles;
-  while (i) {
-    GSList * next = i->next;
-    gts_object_destroy (i->data);
-    i = next;
-  }
-  g_assert (edge->triangles == NULL);
-
-  (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->destroy) (object);
-}
-
-static void edge_clone (GtsObject * clone, GtsObject * object)
-{
-  (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->clone) (clone,
-								 object);
-  GTS_SEGMENT (clone)->v1 = GTS_SEGMENT (clone)->v2 = NULL;
-  GTS_EDGE (clone)->triangles = NULL;
-}
-
-static void edge_class_init (GtsObjectClass * klass)
-{
-  klass->clone = edge_clone;
-  klass->destroy = edge_destroy;
-}
-
-static void edge_init (GtsEdge * edge)
-{
-  edge->triangles = NULL;
-}
-
-/**
- * gts_edge_class:
- *
- * Returns: the #GtsEdgeClass.
- */
-GtsEdgeClass * gts_edge_class (void)
-{
-  static GtsEdgeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo edge_info = {
-      "GtsEdge",
-      sizeof (GtsEdge),
-      sizeof (GtsEdgeClass),
-      (GtsObjectClassInitFunc) edge_class_init,
-      (GtsObjectInitFunc) edge_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_segment_class ()), 
-				  &edge_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_edge_new:
- * @klass: a #GtsEdgeClass.
- * @v1: a #GtsVertex.
- * @v2: a #GtsVertex.
- *
- * Returns: a new #GtsEdge linking @v1 and @v2.
- */
-GtsEdge * gts_edge_new (GtsEdgeClass * klass,
-			GtsVertex * v1, GtsVertex * v2)
-{
-  return GTS_EDGE (gts_segment_new (GTS_SEGMENT_CLASS (klass), v1, v2));
-}
-
-void gts_edge_remove(GtsEdge *edge) 
-{
-  edge->segment.v1->segments = g_slist_remove(edge->segment.v1->segments, &edge->segment);
-  edge->segment.v2->segments = g_slist_remove(edge->segment.v2->segments, &edge->segment);
-  edge_destroy(GTS_OBJECT (edge));
-}
-
-/**
- * gts_edge_replace:
- * @e: a #GtsEdge.
- * @with: a #GtsEdge.
- *
- * Replaces @e with @with. For each triangle which uses @e as an
- * edge, @e is replaced with @with. The @with->triangles list is
- * updated appropriately and the @e->triangles list is freed and set
- * to %NULL.
- */
-void gts_edge_replace (GtsEdge * e, GtsEdge * with)
-{
-  GSList * i;
-
-  g_return_if_fail (e != NULL && with != NULL && e != with);
-
-  i = e->triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    if (t->e1 == e) t->e1 = with;
-    if (t->e2 == e) t->e2 = with;
-    if (t->e3 == e) t->e3 = with;
-    if (!g_slist_find (with->triangles, t))
-      with->triangles = g_slist_prepend (with->triangles, t);
-    i = i->next;
-  }
-  g_slist_free (e->triangles);
-  e->triangles = NULL;
-}
-
-/**
- * gts_edge_has_parent_surface:
- * @e: a #GtsEdge.
- * @surface: a #GtsSurface.
- * 
- * Returns: a #GtsFace of @surface having @e as an edge, %NULL otherwise.
- */
-GtsFace * gts_edge_has_parent_surface (GtsEdge * e, GtsSurface * surface)
-{
-  GSList * i;
-
-  g_return_val_if_fail (e != NULL, NULL);
-
-  i = e->triangles;
-  while (i) {
-    if (GTS_IS_FACE (i->data) && 
-	gts_face_has_parent_surface (i->data, surface))
-      return i->data;
-    i = i->next;
-  }
-  return NULL;
-}
-
-/**
- * gts_edge_has_any_parent_surface:
- * @e: a #GtsEdge.
- * 
- * Returns: %NULL if @e is not an edge of any triangle or if all the
- * faces having @e has an edge do not belong to any surface,
- * a #GtsFace belonging to a surface and having @e as an edge.
- */
-GtsFace * gts_edge_has_any_parent_surface (GtsEdge * e)
-{
-  GSList * i;
-
-  g_return_val_if_fail (e != NULL, NULL);
-
-  i = e->triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    if (GTS_IS_FACE (t) && GTS_FACE (t)->surfaces != NULL)
-      return GTS_FACE (t);
-    i = i->next;
-  }
-  return NULL;
-}
-
-/**
- * gts_edge_is_boundary:
- * @e: a #GtsEdge.
- * @surface: a #GtsSurface or %NULL.
- * 
- * Returns: the unique #GtsFace (which belongs to @surface) and which
- * has @e as an edge (i.e. @e is a boundary edge (of @surface)) or %NULL 
- * if there is more than one or no faces (belonging to @surface) and
- * with @e as an edge.
- */
-GtsFace * gts_edge_is_boundary (GtsEdge * e, GtsSurface * surface)
-{
-  GSList * i;
-  GtsFace * f = NULL;
-  
-  g_return_val_if_fail (e != NULL, NULL);
-  
-  i = e->triangles;
-  while (i) {
-    if (GTS_IS_FACE (i->data)) {
-      if (!surface || gts_face_has_parent_surface (i->data, surface)) {
-	if (f != NULL)
-	  return NULL;
-	f = i->data;
-      }
-    }
-    i = i->next;    
-  }
-  return f;
-}
-
-/**
- * gts_edges_from_vertices:
- * @vertices: a list of #GtsVertex.
- * @parent: a #GtsSurface.
- * 
- * Returns: a list of unique #GtsEdge which have one of their vertices in 
- * @vertices and are used by a face of @parent. 
- */
-GSList * gts_edges_from_vertices (GSList * vertices, GtsSurface * parent)
-{
-  GHashTable * hash;
-  GSList * edges = NULL, * i;
-
-  g_return_val_if_fail (parent != NULL, NULL);
-  
-  hash = g_hash_table_new (NULL, NULL);
-  i = vertices;
-  while (i) {
-    GSList * j = GTS_VERTEX (i->data)->segments;
-    while (j) {
-      GtsSegment * s = j->data;
-      if (GTS_IS_EDGE (s) &&
-	  gts_edge_has_parent_surface (GTS_EDGE (s), parent) && 
-	  g_hash_table_lookup (hash, s) == NULL) {
-	edges = g_slist_prepend (edges, s);
-	g_hash_table_insert (hash, s, i);
-      }
-      j = j->next;
-    }
-    i = i->next;
-  }
-  g_hash_table_destroy (hash);
-  return edges;
-}
-
-/**
- * gts_edge_face_number:
- * @e: a #GtsEdge.
- * @s: a #GtsSurface.
- *
- * Returns: the number of faces using @e and belonging to @s.
- */
-guint gts_edge_face_number (GtsEdge * e, GtsSurface * s)
-{
-  GSList * i;
-  guint nt = 0;
-
-  g_return_val_if_fail (e != NULL, 0);
-  g_return_val_if_fail (s != NULL, 0);
-
-  i = e->triangles;
-  while (i) {
-    if (GTS_IS_FACE (i->data) && 
-	gts_face_has_parent_surface (GTS_FACE (i->data), s))
-      nt++;
-    i = i->next;
-  }
-  return nt;
-}
-
-/**
- * gts_edge_is_duplicate:
- * @e: a #GtsEdge.
- *
- * Returns: the first #GtsEdge different from @e which shares the
- * same endpoints or %NULL if there is none.
- */
-GtsEdge * gts_edge_is_duplicate (GtsEdge * e)
-{
-  GSList * i;
-  GtsVertex * v2;
-
-  g_return_val_if_fail (e != NULL, NULL);
-
-  v2 = GTS_SEGMENT (e)->v2;
-  i = GTS_SEGMENT (e)->v1->segments;
-  if (GTS_SEGMENT (e)->v1 == v2) /* e is degenerate: special treatment */
-    while (i) {
-      GtsSegment * s = i->data;
-      if (s != GTS_SEGMENT (e) &&
-	  GTS_IS_EDGE (s) && 
-	  s->v1 == v2 && s->v2 == v2)
-	return GTS_EDGE (s);
-      i = i->next;
-    }
-  else /* e is not degenerate */
-    while (i) {
-      GtsSegment * s = i->data;
-      if (s != GTS_SEGMENT (e) &&
-	  GTS_IS_EDGE (s) && 
-	  (s->v1 == v2 || s->v2 == v2))
-	return GTS_EDGE (s);
-      i = i->next;
-    }
-  return NULL;
-}
-
-/**
- * gts_edges_merge:
- * @edges: a list of #GtsEdge.
- *
- * For each edge in @edges check if it is duplicated (as
- * returned by gts_edge_is_duplicate()). If it is replace it by its
- * duplicate, destroy it and remove it from the list.
- *
- * Returns: the updated @edges list.
- */
-GList * gts_edges_merge (GList * edges)
-{
-  GList * i = edges;
-
-  /* we want to control edge destruction */
-  gts_allow_floating_edges = TRUE;
-  while (i) {
-    GtsEdge * e = i->data;
-    GtsEdge * de = gts_edge_is_duplicate (e);
-    if (de) {
-      GList * next = i->next;
-      edges = g_list_remove_link (edges, i);
-      g_list_free_1 (i);
-      i = next;
-      gts_edge_replace (e, de);
-      gts_object_destroy (GTS_OBJECT (e));
-    }
-    else
-      i = i->next;
-  }
-  gts_allow_floating_edges = FALSE;;
-
-  return edges;
-}
-
-static void triangle_vertices_edges (GtsTriangle * t, 
-				     GtsEdge * e,
-				     GtsVertex ** v,
-				     GtsEdge ** ee1,
-				     GtsEdge ** ee2)
-{
-  GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3;
-  GtsVertex * v1 = GTS_SEGMENT (e)->v1;
-
-  if (e1 == e)        e1 = e3;
-  else if (e2 == e)   e2 = e3;
-  else                g_assert (e3 == e);
-
-  if (GTS_SEGMENT (e2)->v1 == v1 || GTS_SEGMENT (e2)->v2 == v1) {
-    e3 = e1; e1 = e2; e2 = e3;
-  }
-  if (GTS_SEGMENT (e1)->v1 == v1)
-    *v = GTS_SEGMENT (e1)->v2;
-  else
-    *v = GTS_SEGMENT (e1)->v1;
-  *ee1 = e1;
-  *ee2 = e2;
-}
-
-/**
- * gts_edge_belongs_to_tetrahedron:
- * @e: a #GtsEdge.
- *
- * Returns: %TRUE if @e is used by faces forming a tetrahedron, %FALSE
- * otherwise.
- */
-gboolean gts_edge_belongs_to_tetrahedron (GtsEdge * e)
-{
-  GSList * i;
-
-  g_return_val_if_fail (e != NULL, FALSE);
-
-  i = e->triangles;
-  while (i) {
-    GtsEdge * e1, * e2;
-    GtsVertex * vt1;
-    GSList * j = i->next;
-    triangle_vertices_edges (i->data, e, &vt1, &e1, &e2);
-    while (j) {      
-      GtsSegment * s5;
-      GtsEdge * e3, * e4;
-      GtsVertex * vt2;
-
-      triangle_vertices_edges (j->data, e, &vt2, &e3, &e4);
-      s5 = gts_vertices_are_connected (vt1, vt2);
-      if (GTS_IS_EDGE (s5) &&
-	  gts_triangle_use_edges (e1, e3, GTS_EDGE (s5)) &&
-	  gts_triangle_use_edges (e2, e4, GTS_EDGE (s5)))
-	return TRUE;
-      j = j->next;
-    }
-    i = i->next;
-  }
-
-  return FALSE;
-}
-
-#define edge_use_vertex(e, v) (GTS_SEGMENT(e)->v1 == v ||\
-			       GTS_SEGMENT(e)->v2 == v)
-
-static GtsEdge * next_edge (GtsTriangle * t,
-			    GtsEdge * e1,
-			    GtsEdge * e)
-{
-  GtsVertex * v1 = GTS_SEGMENT (e)->v1;
-  GtsVertex * v2 = GTS_SEGMENT (e)->v2;
-  
-  if (t->e1 != e1 && t->e1 != e && 
-      (edge_use_vertex (t->e1, v1) || edge_use_vertex (t->e1, v2)))
-    return t->e1;
-  else if (t->e2 != e1 && t->e2 != e && 
-	   (edge_use_vertex (t->e2, v1) || edge_use_vertex (t->e2, v2)))
-    return t->e2;
-  else if (t->e3 != e1 && t->e3 != e && 
-	   (edge_use_vertex (t->e3, v1) || edge_use_vertex (t->e3, v2)))
-    return t->e3;
-  g_assert_not_reached ();
-  return NULL;
-}
-
-static void triangle_next (GtsEdge * e1, GtsEdge * e)
-{
-  GSList * i;
-
-  i = e1->triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    if (GTS_OBJECT (t)->reserved) {
-      GTS_OBJECT (t)->reserved = NULL;
-      triangle_next (next_edge (t, e1, e), e);
-    }
-    i = i->next;
-  }
-}
-
-/** 
- * gts_edge_is_contact: 
- * @e: a #GtsEdge.  
- *
- * Returns: the number of sets of connected triangles sharing @e as a
- * contact edge.  
- */
-guint gts_edge_is_contact (GtsEdge * e)
-{
-  GSList * i, * triangles;
-  guint ncomponent = 0;
-
-  g_return_val_if_fail (e != NULL, 0);
-
-  triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL);
-  i = triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles);
-  while (i) {
-    GTS_OBJECT (i->data)->reserved = i;
-    i = i->next;
-  }
-
-  i = e->triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    if (GTS_OBJECT (t)->reserved) {
-      GtsEdge * e1;
-      GTS_OBJECT (t)->reserved = NULL;
-      e1 = next_edge (t, NULL, e);
-      triangle_next (e1, e);
-      triangle_next (next_edge (t, e1, e), e);
-      ncomponent++;
-    }
-    i = i->next;
-  }
-   
-  g_slist_foreach (triangles, (GFunc) gts_object_reset_reserved, NULL);
-  g_slist_free (triangles);
-
-  return ncomponent;
-}
-
-/**
- * gts_edge_swap:
- * @e: a #GtsEdge.
- * @s: a #GtsSurface.
- *
- * Performs an "edge swap" on the two triangles sharing @e and
- * belonging to @s.
- */
-void gts_edge_swap (GtsEdge * e, GtsSurface * s)
-{
-  GtsTriangle * t1 = NULL, * t2 = NULL, * t;
-  GtsFace * f;
-  GSList * i;
-  GtsVertex * v1, * v2, * v3, * v4, * v5, * v6;
-  GtsEdge * e1, * e2, * e3, * e4;
-  GtsSegment * v3v6;
-
-  g_return_if_fail (e != NULL);
-  g_return_if_fail (s != NULL);
-
-  i = e->triangles;
-  while (i) {
-    if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) {
-      if (!t1)
-	t1 = i->data;
-      else if (!t2)
-	t2 = i->data;
-      else
-	g_return_if_fail (gts_edge_face_number (e, s) == 2);
-    }
-    i = i->next;
-  }
-  g_assert (t1 && t2);
-
-  gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e1, &e2);
-  gts_triangle_vertices_edges (t2, e, &v4, &v5, &v6, &e, &e3, &e4);
-  g_assert (v2 == v4 && v1 == v5);
-
-  v3v6 = gts_vertices_are_connected (v3, v6);
-  if (!GTS_IS_EDGE (v3v6))
-    v3v6 = GTS_SEGMENT (gts_edge_new (s->edge_class, v3, v6));
-  f = gts_face_new (s->face_class, e1, GTS_EDGE (v3v6), e4);
-  if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) &&
-      GTS_IS_FACE (t)) {
-    gts_object_destroy (GTS_OBJECT (f));
-    f = GTS_FACE (t);
-  }
-  gts_surface_add_face (s, f);
-
-  f = gts_face_new (s->face_class, GTS_EDGE (v3v6), e2, e3);
-  if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) &&
-      GTS_IS_FACE (t)) {
-    gts_object_destroy (GTS_OBJECT (f));
-    f = GTS_FACE (t);
-  }
-  gts_surface_add_face (s, f);
-
-  gts_surface_remove_face (s, GTS_FACE (t1));
-  gts_surface_remove_face (s, GTS_FACE (t2));
-}
-
-/**
- * gts_edge_manifold_faces:
- * @e: a #GtsEdge.
- * @s: a #GtsSurface.
- * @f1: pointer for first face.
- * @f2: pointer for second face.
- *
- * If @e is a manifold edge of surface @s, fills @f1 and @f2 with the
- * faces belonging to @s and sharing @e.
- *
- * Returns: %TRUE if @e is a manifold edge, %FALSE otherwise.
- */
-gboolean gts_edge_manifold_faces (GtsEdge * e, GtsSurface * s,
-				  GtsFace ** f1, GtsFace ** f2)
-{
-  GSList * i;
-
-  g_return_val_if_fail (e != NULL, FALSE);
-  g_return_val_if_fail (s != NULL, FALSE);
-  g_return_val_if_fail (f1 != NULL, FALSE);
-  g_return_val_if_fail (f2 != NULL, FALSE);
-
-  *f1 = *f2 = NULL;
-  i = e->triangles;
-  while (i) {
-    if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) {
-      if (!(*f1)) *f1 = i->data;
-      else if (!(*f2)) *f2 = i->data;
-      else return FALSE;
-    }
-    i = i->next;
-  }
-
-  return (*f1 && *f2);
-}
diff --git a/src_3rd/gts/eheap.c b/src_3rd/gts/eheap.c
deleted file mode 100644
index 29f462d..0000000
--- a/src_3rd/gts/eheap.c
+++ /dev/null
@@ -1,461 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include "gts.h"
-
-#define PARENT(i) ((i) >= 2 ? (i)/2 : 0)
-#define LEFT_CHILD(i) (2*(i))
-#define RIGHT_CHILD(i) (2*(i) + 1)
-
-
-/**
- * gts_eheap_new:
- * @key_func: a #GtsKeyFunc or %NULL.
- * @data: user data to be passed to @key_func.
- *
- * Returns: a new #GtsEHeap using @key_func as key.
- */
-GtsEHeap * gts_eheap_new (GtsKeyFunc key_func,
-			  gpointer data)
-{
-  GtsEHeap * heap;
-
-  heap = g_malloc (sizeof(GtsEHeap));
-  heap->elts = g_ptr_array_new ();
-  heap->func = key_func;
-  heap->data = data;
-  heap->frozen = FALSE;
-  heap->randomized = FALSE;
-  return heap;
-}
-
-static void sift_up (GtsEHeap * heap, guint i)
-{
-  GtsEHeapPair * parent, * child;
-  guint p;
-  gpointer * pdata = heap->elts->pdata;
-  gdouble key;
-
-  child = pdata[i - 1];
-  key = child->key;
-  while ((p = PARENT (i))) {
-    parent = pdata[p - 1];
-    if (parent->key > key ||
-	(heap->randomized && parent->key == key && rand () < RAND_MAX/2)) {
-      pdata[p - 1] = child;
-      pdata[i - 1] = parent;
-      child->pos = p;
-      parent->pos = i;
-      i = p;
-    }
-    else
-      i = 0;
-  }
-}
-
-/**
- * gts_eheap_insert:
- * @heap: a #GtsEHeap.
- * @p: a pointer to add to the heap.
- *
- * Inserts a new element @p in the heap.
- *
- * Returns: a #GtsEHeapPair describing the position of the element in the heap.
- * This pointer is necessary for gts_eheap_remove() and 
- * gts_eheap_decrease_key().
- */
-GtsEHeapPair * gts_eheap_insert (GtsEHeap * heap, gpointer p)
-{
-  GtsEHeapPair * pair;
-  GPtrArray * elts;
-
-  g_return_val_if_fail (heap != NULL, NULL);
-  g_return_val_if_fail (heap->func != NULL, NULL);
-
-  elts = heap->elts;
-  pair = g_malloc (sizeof (GtsEHeapPair));
-  g_ptr_array_add (elts, pair);
-  pair->data = p;
-  pair->pos = elts->len;
-  pair->key = (*heap->func) (p, heap->data);
-  if (!heap->frozen)
-    sift_up (heap, elts->len);
-  return pair;
-}
-
-/**
- * gts_eheap_insert_with_key:
- * @heap: a #GtsEHeap.
- * @p: a pointer to add to the heap.
- * @key: the value of the key associated to @p.
- *
- * Inserts a new element @p in the heap.
- *
- * Returns: a #GtsEHeapPair describing the position of the element in the heap.
- * This pointer is necessary for gts_eheap_remove() and 
- * gts_eheap_decrease_key().
- */
-GtsEHeapPair * gts_eheap_insert_with_key (GtsEHeap * heap, 
-					  gpointer p, 
-					  gdouble key)
-{
-  GtsEHeapPair * pair;
-  GPtrArray * elts;
-
-  g_return_val_if_fail (heap != NULL, NULL);
-
-  elts = heap->elts;
-  pair = g_malloc (sizeof (GtsEHeapPair));
-  g_ptr_array_add (elts, pair);
-  pair->data = p;
-  pair->pos = elts->len;
-  pair->key = key;
-  if (!heap->frozen)
-    sift_up (heap, elts->len);
-  return pair;
-}
-
-static void sift_down (GtsEHeap * heap, guint i)
-{
-  GtsEHeapPair * left_child, * right_child, * child, * parent;
-  guint lc, rc, c;
-  gpointer * pdata = heap->elts->pdata;
-  guint len = heap->elts->len;
-  gdouble key;
-
-  lc = LEFT_CHILD (i);
-  rc = RIGHT_CHILD (i);
-  left_child = lc <= len ? pdata[lc - 1] : NULL;
-  right_child = rc <= len ? pdata[rc - 1] : NULL;
-
-  parent = pdata[i - 1];
-  key = parent->key;
-  while (left_child != NULL) {
-    if (right_child == NULL || left_child->key  < right_child->key) {
-      child = left_child;
-      c = lc;
-    }
-    else {
-      child = right_child;
-      c = rc;
-    }
-    if (key > child->key) {
-      pdata[i - 1] = child;
-      child->pos = i;
-      pdata[c - 1] = parent;
-      parent->pos = c;
-      i = c;
-      lc = LEFT_CHILD (i);
-      rc = RIGHT_CHILD (i);
-      left_child = lc <= len ? pdata[lc - 1] : NULL;
-      right_child = rc <= len ? pdata[rc - 1] : NULL;      
-    }
-    else
-      left_child = NULL;
-  }
-}
-
-/**
- * gts_eheap_remove_top:
- * @heap: a #GtsEHeap.
- * @key: a pointer on a gdouble or %NULL.
- *
- * Removes the element at the top of the heap and optionally (if @key is not
- * %NULL) returns the value of its key.
- *
- * Returns: the element at the top of the heap.
- */
-gpointer gts_eheap_remove_top (GtsEHeap * heap, gdouble * key)
-{
-  gpointer root;
-  GPtrArray * elts;
-  guint len;
-  GtsEHeapPair * pair;
-
-  g_return_val_if_fail (heap != NULL, NULL);
-
-  elts = heap->elts; 
-  len = elts->len;
-
-  if (len == 0)
-    return NULL;
-  if (len == 1) {
-    pair = g_ptr_array_remove_index (elts, 0);
-    root = pair->data;
-    if (key) 
-      *key = pair->key;
-    g_free (pair);
-    return root;
-  }
-
-  pair = elts->pdata[0];
-  root = pair->data;
-  if (key) 
-    *key = pair->key;
-  g_free (pair);
-  pair = g_ptr_array_remove_index (elts, len - 1);
-  elts->pdata[0] = pair;
-  pair->pos = 1;
-  sift_down (heap, 1);
-  return root;
-}
-
-/**
- * gts_eheap_top:
- * @heap: a #GtsEHeap.
- * @key: a pointer on a gdouble or %NULL.
- *
- * Returns: the element at the top of the heap and optionally (if @key is not
- * %NULL) its key.
- */
-gpointer gts_eheap_top (GtsEHeap * heap, gdouble * key)
-{
-  GtsEHeapPair * pair;
-  GPtrArray * elts;
-
-  g_return_val_if_fail (heap != NULL, NULL);
-
-  elts = heap->elts;
-
-  if (elts->len == 0)
-    return NULL;
-
-  pair = elts->pdata[0];
-  if (key)
-    *key = pair->key;
-  return pair->data;
-}
-
-/**
- * gts_eheap_destroy:
- * @heap: a #GtsEHeap.
- * 
- * Free all the memory allocated for @heap.
- */
-void gts_eheap_destroy (GtsEHeap * heap)
-{
-  guint i;
-
-  g_return_if_fail (heap != NULL);
-
-  for (i = 0; i < heap->elts->len; i++)
-    g_free (heap->elts->pdata[i]);
-  g_ptr_array_free (heap->elts, TRUE);
-  g_free (heap);
-}
-
-/**
- * gts_eheap_thaw:
- * @heap: a #GtsEHeap.
- *
- * If @heap has been frozen previously using gts_eheap_freeze(), reorder it
- * in O(n) time and unfreeze it.
- */
-void gts_eheap_thaw (GtsEHeap * heap)
-{
-  guint i;
-  
-  g_return_if_fail (heap != NULL);
-
-  if (!heap->frozen)
-    return;
-
-  for (i = heap->elts->len/2; i > 0; i--)
-    sift_down (heap, i);
-
-  heap->frozen = FALSE;
-}
-
-/**
- * gts_eheap_foreach:
- * @heap: a #GtsEHeap.
- * @func: the function to call for each element in the heap.
- * @data: to pass to @func.
- */
-void gts_eheap_foreach (GtsEHeap * heap, 
-			GFunc func,
-			gpointer data)
-{
-  guint i;
-  GPtrArray * elts;
-  
-  g_return_if_fail (heap != NULL);
-  g_return_if_fail (func != NULL);
-
-  elts = heap->elts;
-  for (i = 0; i < elts->len; i++)
-    (*func) (((GtsEHeapPair *) elts->pdata[i])->data, data);
-}
-
-/**
- * gts_eheap_remove:
- * @heap: a #GtsEHeap.
- * @p: a #GtsEHeapPair.
- *
- * Removes element corresponding to @p from @heap in O(log n).
- *
- * Returns: the element just removed from @heap.
- */
-gpointer gts_eheap_remove (GtsEHeap * heap, GtsEHeapPair * p)
-{
-  GtsEHeapPair ** pdata;
-  GtsEHeapPair * parent;
-  guint i, par;
-  gpointer data;
-
-  g_return_val_if_fail (heap != NULL, NULL);
-  g_return_val_if_fail (p != NULL, NULL);
-
-  pdata = (GtsEHeapPair **)heap->elts->pdata;
-  i = p->pos;
-  data = p->data;
-
-  g_return_val_if_fail (i > 0 && i <= heap->elts->len, NULL);
-  g_return_val_if_fail (p == pdata[i - 1], NULL);
-
-  /* move element to the top */
-  while ((par = PARENT (i))) {
-    parent = pdata[par - 1];
-    pdata[par - 1] = p;
-    pdata[i - 1] = parent;
-    p->pos = par;
-    parent->pos = i;
-    i = par;
-  }
-
-  gts_eheap_remove_top (heap, NULL);
-
-  return data;
-}
-
-/**
- * gts_eheap_decrease_key:
- * @heap: a #GtsEHeap.
- * @p: a #GtsEHeapPair.
- * @new_key: the new value of the key for this element. Must be smaller than
- * the current key.
- *
- * Decreases the value of the key of the element at position @p.
- */
-void gts_eheap_decrease_key (GtsEHeap * heap, 
-			     GtsEHeapPair * p,
-			     gdouble new_key)
-{
-  guint i;
-
-  g_return_if_fail (heap != NULL);
-  g_return_if_fail (p != NULL);
-
-  i = p->pos;
-  g_return_if_fail (i > 0 && i <= heap->elts->len);
-  g_return_if_fail (p == heap->elts->pdata[i - 1]);
-
-  g_return_if_fail (new_key <= p->key);
-
-  p->key = new_key;
-  if (!heap->frozen)
-    sift_up (heap, i);
-}
-
-/**
- * gts_eheap_freeze:
- * @heap: a #GtsEHeap.
- *
- * Freezes the heap. Any subsequent operation will not preserve the heap
- * property. Used in conjunction with gts_eheap_insert() and gts_eheap_thaw()
- * to create a heap in O(n) time.
- */
-void gts_eheap_freeze (GtsEHeap * heap)
-{
-  g_return_if_fail (heap != NULL);
-
-  heap->frozen = TRUE;
-}
-
-/**
- * gts_eheap_size:
- * @heap: a #GtsEHeap.
- *
- * Returns: the number of items in @heap.
- */
-guint gts_eheap_size (GtsEHeap * heap)
-{
-  g_return_val_if_fail (heap != NULL, 0);
-
-  return heap->elts->len;
-}
-
-/**
- * gts_eheap_update:
- * @heap: a #GtsEHeap.
- *
- * Updates the key of each element of @heap and reorders it.
- */
-void gts_eheap_update (GtsEHeap * heap)
-{
-  guint i, len;
-  GtsEHeapPair ** pairs;
-  gpointer data;
-  GtsKeyFunc func;
-
-  g_return_if_fail (heap != NULL);
-  g_return_if_fail (heap->func != NULL);
-
-  heap->frozen = TRUE;
-
-  len = heap->elts->len;
-  pairs = (GtsEHeapPair **) heap->elts->pdata;
-  data = heap->data;
-  func = heap->func;
-
-  for (i = 0; i < len; i++) {
-    GtsEHeapPair * pair = pairs[i];
-    pair->key = (*func) (pair->data, data);
-  }
-  
-  gts_eheap_thaw (heap);
-}
-
-/**
- * gts_eheap_key:
- * @heap: a #GtsEHeap.
- * @p: a pointer to be tested;
- *
- * Returns: the value of the key for pointer @p.
- */
-gdouble gts_eheap_key (GtsEHeap * heap, gpointer p)
-{
-  g_return_val_if_fail (heap != NULL, 0.);
-  g_return_val_if_fail (heap->func != NULL, 0.);
-
-  return (* heap->func) (p, heap->data);
-}
-
-/**
- * gts_eheap_randomized:
- * @heap: a #GtsEHeap.
- * @randomized: whether @heap should be randomized.
- */
-void gts_eheap_randomized (GtsEHeap * heap, gboolean randomized)
-{
-  g_return_if_fail (heap != NULL);
-
-  heap->randomized = randomized;
-}
diff --git a/src_3rd/gts/face.c b/src_3rd/gts/face.c
deleted file mode 100644
index f6009f1..0000000
--- a/src_3rd/gts/face.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-gboolean gts_allow_floating_faces = FALSE;
-
-static void face_destroy (GtsObject * object)
-{
-  GtsFace * face = GTS_FACE (object);
-  GSList * i;
-
-  i = face->surfaces;
-  while (i) {
-    GSList * next = i->next;
-    gts_surface_remove_face (i->data, face);
-    i = next;
-  }
-  g_assert (face->surfaces == NULL);
-
-  (* GTS_OBJECT_CLASS (gts_face_class ())->parent_class->destroy) (object);
-}
-
-static void face_clone (GtsObject * clone, GtsObject * object)
-{
-  (* GTS_OBJECT_CLASS (gts_face_class ())->parent_class->clone) (clone, 
-								 object);
-  GTS_FACE (clone)->surfaces = NULL;
-}
-
-static void face_class_init (GtsFaceClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->clone = face_clone;
-  GTS_OBJECT_CLASS (klass)->destroy = face_destroy;
-}
-
-static void face_init (GtsFace * face)
-{
-  face->surfaces = NULL;
-}
-
-/**
- * gts_face_class:
- *
- * Returns: the #GtsFaceClass.
- */
-GtsFaceClass * gts_face_class (void)
-{
-  static GtsFaceClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo face_info = {
-      "GtsFace",
-      sizeof (GtsFace),
-      sizeof (GtsFaceClass),
-      (GtsObjectClassInitFunc) face_class_init,
-      (GtsObjectInitFunc) face_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_triangle_class ()), 
-				  &face_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_face_new:
- * @klass: a #GtsFaceClass.
- * @e1: a #GtsEdge.
- * @e2: a #GtsEdge.
- * @e3: a #GtsEdge.
- *
- * Returns: a new #GtsFace using @e1, @e2 and @e3 as edges.
- */
-GtsFace * gts_face_new (GtsFaceClass * klass,
-			GtsEdge * e1, GtsEdge * e2, GtsEdge * e3)
-{
-  GtsFace * f;
-
-  f = GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  gts_triangle_set (GTS_TRIANGLE (f), e1, e2, e3);
-
-  return f;
-}
-
-/**
- * gts_face_has_parent_surface:
- * @f: a #GtsFace.
- * @s: a #GtsSurface.
- *
- * Returns: %TRUE if @f belongs to @s, %FALSE otherwise.
- */
-gboolean gts_face_has_parent_surface (GtsFace * f, GtsSurface * s)
-{
-  GSList * i;
-
-  g_return_val_if_fail (f != NULL, FALSE);
-
-  i = f->surfaces;
-  while (i) {
-    if (i->data == s)
-      return TRUE;
-    i = i->next;
-  }
-  return FALSE;
-}
-
-/**
- * gts_faces_from_edges:
- * @edges: a list of #GtsEdge.
- * @s: a #GtsSurface or %NULL.
- *
- * Builds a list of unique faces which belong to @s and have
- * one of their edges in @edges.
- * 
- * Returns: the list of faces.
- */
-GSList * gts_faces_from_edges (GSList * edges, GtsSurface * s)
-{
-  GHashTable * hash;
-  GSList * faces = NULL, * i;
-
-  hash = g_hash_table_new (NULL, NULL);
-  i = edges;
-  while (i) {
-    GSList * j = GTS_EDGE (i->data)->triangles;
-    while (j) {
-      GtsTriangle * t = j->data;
-      if (GTS_IS_FACE (t) &&
-	  (!s || gts_face_has_parent_surface (GTS_FACE (t), s)) && 
-	  g_hash_table_lookup (hash, t) == NULL) {
-	faces = g_slist_prepend (faces, t);
-	g_hash_table_insert (hash, t, i);
-      }
-      j = j->next;
-    }
-    i = i->next;
-  }
-  g_hash_table_destroy (hash);
-
-  return faces;
-}
-
-/**
- * gts_face_neighbor_number:
- * @f: a #GtsFace.
- * @s: a #GtsSurface or %NULL.
- *
- * Returns: the number of faces neighbors of @f and belonging to @s.
- */
-guint gts_face_neighbor_number (GtsFace * f, GtsSurface * s)
-{
-  GSList * i;
-  guint nn = 0;
-  GtsEdge * e[4], ** e1 = e;
-  
-  g_return_val_if_fail (f != NULL, 0);
-  
-  e[0] = GTS_TRIANGLE (f)->e1; 
-  e[1] = GTS_TRIANGLE (f)->e2; 
-  e[2] = GTS_TRIANGLE (f)->e3; 
-  e[3] = NULL;
-  while (*e1) {
-    i = (*e1++)->triangles;
-    while (i) {
-      GtsTriangle * t = i->data;
-      if (GTS_FACE (t) != f && 
-	  GTS_IS_FACE (t) && 
-	  (!s || gts_face_has_parent_surface (GTS_FACE (t), s)))
-	nn++;
-      i = i->next;
-    }
-  }
-
-  return nn;
-}
-
-/**
- * gts_face_neighbors:
- * @f: a #GtsFace.
- * @s: a #GtsSurface or %NULL.
- *
- * Returns: a list of unique #GtsFace neighbors of @f and belonging to @s.
- */
-GSList * gts_face_neighbors (GtsFace * f, GtsSurface * s)
-{
-  GSList * i, * list = NULL;
-  GtsEdge * e[4], ** e1 = e;
-  
-  g_return_val_if_fail (f != NULL, NULL);
-
-  e[0] = GTS_TRIANGLE (f)->e1; 
-  e[1] = GTS_TRIANGLE (f)->e2; 
-  e[2] = GTS_TRIANGLE (f)->e3; 
-  e[3] = NULL;
-  while (*e1) {
-    i = (*e1++)->triangles;
-    while (i) {
-      GtsTriangle * t = i->data;
-      if (GTS_FACE (t) != f && 
-	  GTS_IS_FACE (t) && 
-	  (!s || gts_face_has_parent_surface (GTS_FACE (t), s)))
-	list = g_slist_prepend (list, t);
-      i = i->next;
-    }
-  }
-
-  return list;
-}
-
-/**
- * gts_face_foreach_neighbor:
- * @f: a #GtsFace.
- * @s: a #GtsSurface or %NULL.
- * @func: a #GtsFunc.
- * @data: user data to pass to @func.
- *
- * Calls @func for each neighbor of @f belonging to @s (if not %NULL).
- */
-void gts_face_foreach_neighbor (GtsFace * f, 
-				GtsSurface * s, 
-				GtsFunc func,
-				gpointer data)
-{
-  GSList * i;
-  GtsEdge * e[4], ** e1 = e;
-  
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (func != NULL);
-
-  e[0] = GTS_TRIANGLE (f)->e1;
-  e[1] = GTS_TRIANGLE (f)->e2; 
-  e[2] = GTS_TRIANGLE (f)->e3; 
-  e[3] = NULL;
-  while (*e1) {
-    i = (*e1++)->triangles;
-    while (i) {
-      GtsTriangle * t = i->data;
-      if (GTS_FACE (t) != f && 
-	  GTS_IS_FACE (t) && 
-	  (!s || gts_face_has_parent_surface (GTS_FACE (t), s)))
-	(* func) (t, data);
-      i = i->next;
-    }
-  }
-}
-
-static gboolean triangle_is_incompatible (GtsTriangle * t, GtsEdge * e, GtsSurface * s)
-{
-  GSList * i = e->triangles;
-
-  while (i) {
-    if (i->data != t &&
-	GTS_IS_FACE (i->data) &&
-	gts_face_has_parent_surface (i->data, s) &&
-	!gts_triangles_are_compatible (t, i->data, e))
-      return TRUE;
-    i = i->next;
-  }
-  return FALSE;
-}
-
-/**
- * gts_face_is_compatible:
- * @f: a #GtsFace.
- * @s: a #GtsSurface.
- *
- * Returns: %TRUE if @f is compatible with all its neighbors belonging
- * to @s, %FALSE otherwise.
- */
-gboolean gts_face_is_compatible (GtsFace * f, GtsSurface * s)
-{
-  g_return_val_if_fail (f != NULL, FALSE);
-  g_return_val_if_fail (s != NULL, FALSE);
-
-  return !(triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e1, s) ||
-	   triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e2, s) ||
-	   triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e3, s));
-}
diff --git a/src_3rd/gts/fifo.c b/src_3rd/gts/fifo.c
deleted file mode 100644
index 8b3d2b6..0000000
--- a/src_3rd/gts/fifo.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-struct _GtsFifo {
-  GList * head;
-  GList * tail;
-};
-
-/**
- * gts_fifo_new:
- *
- * Returns: a new #GtsFifo.
- */
-GtsFifo * gts_fifo_new ()
-{
-  GtsFifo * fifo = g_malloc (sizeof (GtsFifo));
-
-  fifo->head = fifo->tail = NULL;
-  return fifo;
-}
-
-/**
- * gts_fifo_write:
- * @fifo: a #GtsFifo.
- * @fp: a file pointer.
- *
- * Writes the content of @fifo in @fp.
- */
-void gts_fifo_write (GtsFifo * fifo, FILE * fp)
-{
-  GList * i;
-
-  g_return_if_fail (fifo != NULL);
-  g_return_if_fail (fp != NULL);
-
-  fprintf (fp, "[");
-  i = fifo->head;
-  while (i) {
-    fprintf (fp, "%p ", i->data);
-    i = i->next;
-  }
-  fprintf (fp, "]");
-}
-
-/**
- * gts_fifo_push:
- * @fifo: a #GtsFifo.
- * @data: data to add to @fifo.
- *
- * Push @data into @fifo.
- */
-void gts_fifo_push (GtsFifo * fifo, gpointer data)
-{
-  g_return_if_fail (fifo != NULL);
-
-  fifo->head = g_list_prepend (fifo->head, data);
-  if (fifo->tail == NULL)
-    fifo->tail = fifo->head;
-}
-
-/**
- * gts_fifo_pop:
- * @fifo: a #GtsFifo.
- *
- * Removes the first element from @fifo.
- *
- * Returns: the first element in @fifo or %NULL if @fifo is empty.
- */
-gpointer gts_fifo_pop (GtsFifo * fifo)
-{
-  gpointer data;
-  GList * tail;
-
-  g_return_val_if_fail (fifo != NULL, NULL);
-
-  if (fifo->tail == NULL)
-    return NULL;
-  tail = fifo->tail->prev;
-  data = fifo->tail->data;
-  fifo->head = g_list_remove_link (fifo->head, fifo->tail);
-  g_list_free_1 (fifo->tail);
-  fifo->tail = tail;
-  return data;
-}
-
-/**
- * gts_fifo_top:
- * @fifo: a #GtsFifo.
- *
- * Returns: the first element in @fifo or %NULL if @fifo is empty.
- */
-gpointer gts_fifo_top (GtsFifo * fifo)
-{
-  g_return_val_if_fail (fifo != NULL, NULL);
-
-  if (fifo->tail == NULL)
-    return NULL;
-  return fifo->tail->data;
-}
-
-/**
- * gts_fifo_size:
- * @fifo: a #GtsFifo.
- *
- * Returns: the number of elements in @fifo.
- */
-guint gts_fifo_size (GtsFifo * fifo)
-{
-  g_return_val_if_fail (fifo != NULL, 0);
-
-  return g_list_length (fifo->head);
-}
-
-/**
- * gts_fifo_destroy:
- * @fifo: a #GtsFifo.
- *
- * Frees all the memory allocated for @fifo.
- */
-void gts_fifo_destroy (GtsFifo * fifo)
-{
-  g_return_if_fail (fifo != NULL);
-  g_list_free (fifo->head);
-  g_free (fifo);
-}
-
-/**
- * gts_fifo_is_empty:
- * @fifo: a #GtsFifo.
- * 
- * Returns: %TRUE if @fifo is empty, %FALSE otherwise.
- */
-gboolean gts_fifo_is_empty (GtsFifo * fifo)
-{
-  g_return_val_if_fail (fifo != NULL, TRUE);
-
-  return (fifo->head == NULL);
-}
-
-/**
- * gts_fifo_foreach:
- * @fifo: a #GtsFifo.
- * @func: a #GtsFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func in order for each item in @fifo, passing @data.
- */
-void gts_fifo_foreach (GtsFifo * fifo, GtsFunc func, gpointer data)
-{
-  GList * i;
-
-  g_return_if_fail (fifo != NULL);
-  g_return_if_fail (func != NULL);
-
-  i = fifo->tail;
-  while (i) {
-    (* func) (i->data, data);
-    i = i->prev;
-  }
-}
-
-/**
- * gts_fifo_reverse:
- * @fifo: a #GtsFifo.
- *
- * Reverses the order of elements in @fifo.
- */
-void gts_fifo_reverse (GtsFifo * fifo)
-{
-  g_return_if_fail (fifo != NULL);
-
-  fifo->tail = fifo->head;
-  fifo->head = g_list_reverse (fifo->head);
-}
diff --git a/src_3rd/gts/graph.c b/src_3rd/gts/graph.c
deleted file mode 100644
index 1566c95..0000000
--- a/src_3rd/gts/graph.c
+++ /dev/null
@@ -1,1776 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include "gts.h"
-
-/* GtsGNode */
-
-gboolean gts_allow_floating_gnodes = FALSE;
-
-static void gnode_remove_container (GtsContainee * i, GtsContainer * c)
-{
-  (* GTS_CONTAINEE_CLASS (GTS_OBJECT_CLASS (gts_gnode_class ())->parent_class)->remove_container) (i, c);
-  if (GTS_SLIST_CONTAINEE (i)->containers == NULL && 
-      !gts_allow_floating_gnodes &&
-      !GTS_OBJECT_DESTROYED(GTS_OBJECT (i)))
-    gts_object_destroy (GTS_OBJECT (i));
-}
-
-static void gnode_class_init (GtsGNodeClass * klass)
-{
-  klass->weight = NULL;
-
-  GTS_CONTAINEE_CLASS (klass)->remove_container = gnode_remove_container;
-}
-
-static void gnode_init (GtsGNode * n)
-{
-  n->level = 0;
-}
-
-/**
- * gts_gnode_class:
- * 
- * Returns: the #GtsGNodeClass.
- */
-GtsGNodeClass * gts_gnode_class (void)
-{
-  static GtsGNodeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo gnode_info = {
-      "GtsGNode",
-      sizeof (GtsGNode),
-      sizeof (GtsGNodeClass),
-      (GtsObjectClassInitFunc) gnode_class_init,
-      (GtsObjectInitFunc) gnode_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = 
-      gts_object_class_new (GTS_OBJECT_CLASS (gts_slist_container_class ()),
-			    &gnode_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_gnode_new:
- * @klass: a #GtsGNodeClass.
- *
- * Returns: a new #GtsGNode.
- */
-GtsGNode * gts_gnode_new (GtsGNodeClass * klass)
-{
-  GtsGNode * object;
-
-  object = GTS_GNODE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-
-  return object;
-}
-
-/**
- * gts_gnode_foreach_neighbor:
- * @n: a #GtsGNode.
- * @g: a #GtsGraph or %NULL.
- * @func: a #GtsFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func for each neighbor #GtsGNode of @n (belonging to @g if
- * @g is not %NULL.  
- */
-void gts_gnode_foreach_neighbor (GtsGNode * n, 
-				 GtsGraph * g,
-				 GtsFunc func,
-				 gpointer data)
-{
-  GSList * i;
-
-  g_return_if_fail (n != NULL);
-  g_return_if_fail (func != NULL);
-
-  i = GTS_SLIST_CONTAINER (n)->items;
-  while (i) {
-    GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-    if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1),
-						 GTS_CONTAINER (g)))
-      (* func) (n1, data);
-    i = i->next;
-  }
-}
-
-/**
- * gts_gnode_foreach_edge:
- * @n: a #GtsGNode.
- * @g: a #GtsGraph or %NULL.
- * @func: a #GtsFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func for each #GtsGEdge connecting @n to another #GtsGNode
- * (belonging to @g if @g is not %NULL.  
- */
-void gts_gnode_foreach_edge (GtsGNode * n, 
-			     GtsGraph * g,
-			     GtsFunc func,
-			     gpointer data)
-{
-  GSList * i;
-
-  g_return_if_fail (n != NULL);
-  g_return_if_fail (func != NULL);
-
-  i = GTS_SLIST_CONTAINER (n)->items;
-  while (i) {
-    GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-    if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1),
-						 GTS_CONTAINER (g)))
-      (* func) (i->data, data);
-    i = i->next;
-  }
-}
-
-/**
- * gts_gnode_degree:
- * @n: a #GtsGNode.
- * @g: a #GtsGraph or %NULL.
- *
- * Returns: the number of neighbors of @n (belonging to @g if @g is not %NULL).
- */
-guint gts_gnode_degree (GtsGNode * n,
-			GtsGraph * g)
-{
-  GSList * i;
-  guint nn = 0;
-
-  g_return_val_if_fail (n != NULL, 0);
-
-  i = GTS_SLIST_CONTAINER (n)->items;
-  while (i) {
-    GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-    if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1),
-						 GTS_CONTAINER (g)))
-      nn++;
-    i = i->next;
-  }
-
-  return nn;
-}
-
-/**
- * gts_gnode_move_cost:
- * @n: a #GtsGNode.
- * @src: a #GtsGraph containing @n.
- * @dst: another #GtsGraph.
- *
- * Returns: the cost (increase in the sum of the weights of the edges cut) of
- * moving @n from @src to @dst.
- */
-gfloat gts_gnode_move_cost (GtsGNode * n,
-			    GtsGraph * src,
-			    GtsGraph * dst)
-{
-  GSList * i;
-  gfloat cost = 0.;
-  
-  g_return_val_if_fail (n != NULL, G_MAXFLOAT);
-  g_return_val_if_fail (src != NULL, G_MAXFLOAT);
-  g_return_val_if_fail (dst != NULL, G_MAXFLOAT);
-  g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n),
-						    GTS_CONTAINER (src)),
-			G_MAXFLOAT);
-
-  i = GTS_SLIST_CONTAINER (n)->items;
-  while (i) {
-    GtsGEdge * ge = i->data;
-    GtsGNode * neighbor = GTS_GNODE_NEIGHBOR (n, ge);
-
-    if (gts_containee_is_contained (GTS_CONTAINEE (neighbor), 
-				    GTS_CONTAINER (src)))
-      cost += gts_gedge_weight (ge);
-    else if (gts_containee_is_contained (GTS_CONTAINEE (neighbor), 
-					 GTS_CONTAINER (dst)))
-      cost -= gts_gedge_weight (ge);
-    i = i->next;
-  }
-  
-  return cost;
-}
-
-/**
- * gts_gnode_weight:
- * @n: a #GtsGNode.
- *
- * Returns: the weight of @n as defined by the weight() method of the
- * #GtsGNodeClass.  
- */
-gfloat gts_gnode_weight (GtsGNode * n)
-{
-  g_return_val_if_fail (n != NULL, 0.);
-
-  if (GTS_GNODE_CLASS (GTS_OBJECT (n)->klass)->weight)
-    return (* GTS_GNODE_CLASS (GTS_OBJECT (n)->klass)->weight) (n);
-  return 1.;
-}
-
-/* GtsNGNode */
-
-static void ngnode_init (GtsNGNode * n)
-{
-  n->id = 0;
-}
-
-/**
- * gts_ngnode_class:
- *
- * Returns: the #GtsNGNodeClass.
- */
-GtsNGNodeClass * gts_ngnode_class (void)
-{
-  static GtsNGNodeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo ngnode_info = {
-      "GtsNGNode",
-      sizeof (GtsNGNode),
-      sizeof (GtsNGNodeClass),
-      (GtsObjectClassInitFunc) NULL,
-      (GtsObjectInitFunc) ngnode_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
-				  &ngnode_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_ngnode_new:
- * @klass: a #GtsNGNodeClass.
- *
- * Returns: a new #GtsNGNode with identity @id.
- */
-GtsNGNode * gts_ngnode_new (GtsNGNodeClass * klass,
-			    guint id)
-{
-  GtsNGNode * n;
-
-  n = GTS_NGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass)));
-  n->id = id;
-
-  return n;
-}
-
-/* GtsWGNode */
-
-static gfloat wgnode_weight (GtsGNode * n)
-{
-  return GTS_WGNODE (n)->weight;
-}
-
-static void wgnode_class_init (GtsWGNodeClass * klass)
-{
-  GTS_GNODE_CLASS (klass)->weight = wgnode_weight;
-}
-
-static void wgnode_init (GtsWGNode * n)
-{
-  n->weight = 1.;
-}
-
-/**
- * gts_wgnode_class:
- *
- * Returns: the #GtsWGNodeClass.
- */
-GtsWGNodeClass * gts_wgnode_class (void)
-{
-  static GtsWGNodeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo wgnode_info = {
-      "GtsWGNode",
-      sizeof (GtsWGNode),
-      sizeof (GtsWGNodeClass),
-      (GtsObjectClassInitFunc) wgnode_class_init,
-      (GtsObjectInitFunc) wgnode_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
-				  &wgnode_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_wgnode_new:
- * @klass: a #GtsWGNodeClass.
- * @weight: the weight of the #GtsWGNode to create.
- *
- * Returns: a new #GtsWGNode of weight @weight.
- */
-GtsWGNode * gts_wgnode_new (GtsWGNodeClass * klass,
-			    gfloat weight)
-{
-  GtsWGNode * n;
-
-  n = GTS_WGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass)));
-  n->weight = weight;
-
-  return n;
-}
-
-/* GtsPNode */
-
-static void pnode_write (GtsGNode * n, FILE * fp)
-{
-  if (GTS_IS_NVERTEX (GTS_PNODE (n)->data))
-    fprintf (fp, "label=\"%p:%s\",", 
-	     GTS_PNODE (n)->data,
-	     GTS_NVERTEX (GTS_PNODE (n)->data)->name);
-  else
-    fprintf (fp, "label=\"%p\",", GTS_PNODE (n)->data);
-}
-
-static void pnode_class_init (GtsPNodeClass * klass)
-{
-  GTS_GNODE_CLASS (klass)->write = pnode_write;
-}
-
-static void pnode_init (GtsPNode * pn)
-{
-  pn->data = NULL;
-}
-
-/**
- * gts_pnode_class:
- *
- * Returns: the #GtsPNodeClass.
- */
-GtsPNodeClass * gts_pnode_class (void)
-{
-  static GtsPNodeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo pnode_info = {
-      "GtsPNode",
-      sizeof (GtsPNode),
-      sizeof (GtsPNodeClass),
-      (GtsObjectClassInitFunc) pnode_class_init,
-      (GtsObjectInitFunc) pnode_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
-				  &pnode_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_pnode_new:
- * @klass: a #GtsPNodeClass.
- * @data: user data.
- *
- * Returns: a new #GtsPNode associated with @data.
- */
-GtsPNode * gts_pnode_new (GtsPNodeClass * klass, gpointer data)
-{
-  GtsPNode * pn;
-
-  pn = GTS_PNODE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  pn->data = data;
-
-  return pn;
-}
-
-/* GtsFNode */
-
-static void fnode_write (GtsGNode * n, FILE * fp)
-{
-  fprintf (fp, "label=\"%p\",", GTS_FNODE (n)->f);
-}
-
-static void fnode_class_init (GtsGNodeClass * klass)
-{
-  klass->write = fnode_write;
-}
-
-static void fnode_init (GtsFNode * fn)
-{
-  fn->f = NULL;
-}
-
-/**
- * gts_fnode_class:
- *
- * Returns: the #GtsFNodeClass.
- */
-GtsFNodeClass * gts_fnode_class (void)
-{
-  static GtsFNodeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo fnode_info = {
-      "GtsFNode",
-      sizeof (GtsFNode),
-      sizeof (GtsFNodeClass),
-      (GtsObjectClassInitFunc) fnode_class_init,
-      (GtsObjectInitFunc) fnode_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
-				  &fnode_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_fnode_new:
- * @klass: a #GtsFNodeClass.
- * @f: a #GtsFace.
- *
- * Returns: a new #GtsFNode associated with face @f.
- */
-GtsFNode * gts_fnode_new (GtsFNodeClass * klass, GtsFace * f)
-{
-  GtsFNode * fn;
-
-  g_return_val_if_fail (f != NULL, NULL);
-
-  fn = GTS_FNODE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  fn->f = f;
-
-  return fn;
-}
-
-/* GtsGEdge */
-
-static void gedge_destroy (GtsObject * object)
-{
-  GtsGEdge * ge = GTS_GEDGE (object);
-
-  if (ge->n1)
-    gts_container_remove (GTS_CONTAINER (ge->n1), GTS_CONTAINEE (ge));
-  if (ge->n2)
-    gts_container_remove (GTS_CONTAINER (ge->n2), GTS_CONTAINEE (ge));
-
-  (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class->destroy) (object);
-}
-
-static void gedge_remove_container (GtsContainee * i, GtsContainer * c)
-{
-  GtsGEdge * ge = GTS_GEDGE (i);
-  GtsGNode * n1 = ge->n1;
-  GtsGNode * n2 = ge->n2;
-
-  ge->n1 = ge->n2 = NULL;
-  if (n1 != NULL && n2 != NULL) {
-    if (GTS_CONTAINER (n1) == c) {
-      if (n2 && n2 != n1) gts_container_remove (GTS_CONTAINER (n2), i);
-    }
-    else if (GTS_CONTAINER (n2) == c) {
-      if (n1 && n1 != n2) gts_container_remove (GTS_CONTAINER (n1), i);
-    }
-    else
-      g_assert_not_reached ();
-    (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class->destroy)
-      (GTS_OBJECT (i));
-  }
-}
-
-static gboolean gedge_is_contained (GtsContainee * i, GtsContainer * c)
-{
-  GtsGEdge * ge = GTS_GEDGE (i);
-
-  if (GTS_CONTAINER (ge->n1) == c || GTS_CONTAINER (ge->n2) == c)
-    return TRUE;
-  return FALSE;
-}
-
-static void gedge_class_init (GtsGEdgeClass * klass)
-{
-  klass->link = NULL;
-  klass->weight = NULL;
-
-  GTS_CONTAINEE_CLASS (klass)->remove_container = gedge_remove_container;
-  GTS_CONTAINEE_CLASS (klass)->is_contained = gedge_is_contained;
-
-  GTS_OBJECT_CLASS (klass)->destroy = gedge_destroy;
-}
-
-static void gedge_init (GtsGEdge * object)
-{
-  object->n1 = object->n2 = NULL;
-}
-
-/**
- * gts_gedge_class:
- *
- * Returns: the #GtsGEdgeClass.
- */
-GtsGEdgeClass * gts_gedge_class (void)
-{
-  static GtsGEdgeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo gedge_info = {
-      "GtsGEdge",
-      sizeof (GtsGEdge),
-      sizeof (GtsGEdgeClass),
-      (GtsObjectClassInitFunc) gedge_class_init,
-      (GtsObjectInitFunc) gedge_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_containee_class ()),
-				  &gedge_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_gedge_new:
- * @klass: a #GtsGEdgeClass.
- * @n1: a #GtsGNode.
- * @n2: another #GtsGNode.
- *
- * Returns: a new #GtsGEdge linking @n1 and @n2.
- */
-GtsGEdge * gts_gedge_new (GtsGEdgeClass * klass, GtsGNode * n1, GtsGNode * n2)
-{
-  GtsGEdge * object;
-
-  g_return_val_if_fail (n1 != NULL, NULL);
-  g_return_val_if_fail (n2 != NULL, NULL);
-
-  object = GTS_GEDGE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  object->n1 = n1;
-  gts_container_add (GTS_CONTAINER (n1), GTS_CONTAINEE (object));
-  object->n2 = n2;
-  if (n1 != n2)
-    gts_container_add (GTS_CONTAINER (n2), GTS_CONTAINEE (object));
-
-  if (klass->link)
-    object = (* klass->link) (object, n1, n2);
-
-  return object;
-}
-
-/**
- * gts_gedge_weight:
- * @e: a #GtsGEdge.
- *
- * Returns: the weight of edge @e as defined by the weight() method of
- * #GtsGEdgeClass.  
- */
-gfloat gts_gedge_weight (GtsGEdge * e)
-{
-  g_return_val_if_fail (e != NULL, 0.);
-
-  if (GTS_GEDGE_CLASS (GTS_OBJECT (e)->klass)->weight)
-    return (* GTS_GEDGE_CLASS (GTS_OBJECT (e)->klass)->weight) (e);
-  return 1.;
-}
-
-/* GtsPGEdge */
-
-static void pgedge_write (GtsGEdge * ge, FILE * fp)
-{
-  if (GTS_IS_EDGE (GTS_PGEDGE (ge)->data)) {
-    GtsEdge * e = GTS_PGEDGE (ge)->data;
-    guint n = g_slist_length (e->triangles);
-
-    fprintf (fp, "label=\"%p:%s:%d\",color=%s", e,
-	     GTS_IS_NEDGE (e) ? GTS_NEDGE (e)->name : "",
-	     n,
-	     n == 0 ? "black" : 
-             n == 1 ? "blue" :
-	     n == 2 ? "green" :
-	     n == 3 ? "violet" :
-	     n == 4 ? "red" : 
-	     "pink");
-  }
-  else
-    fprintf (fp, "label=\"%p\",", GTS_PGEDGE (ge)->data);
-}
-
-static void pgedge_class_init (GtsPGEdgeClass * klass)
-{
-  GTS_GEDGE_CLASS (klass)->write = pgedge_write;
-}
-
-static void pgedge_init (GtsPGEdge * e)
-{
-  e->data = NULL;
-}
-
-/**
- * gts_pgedge_class:
- * 
- * Returns: the #GtsPGEdgeClass.
- */
-GtsPGEdgeClass * gts_pgedge_class (void)
-{
-  static GtsPGEdgeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo pgedge_info = {
-      "GtsPGEdge",
-      sizeof (GtsPGEdge),
-      sizeof (GtsPGEdgeClass),
-      (GtsObjectClassInitFunc) pgedge_class_init,
-      (GtsObjectInitFunc) pgedge_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()),
-				  &pgedge_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_pgedge_new:
- * @klass: a #GtsPGEdgeClass.
- * @n1: a #GtsGNode.
- * @n2: another #GtsGNode.
- * @data: user data.
- *
- * Returns: a new #GtsPGEdge associated with @data linking @n1 and @n2.
- */ 
-GtsPGEdge * gts_pgedge_new (GtsPGEdgeClass * klass,
-			    GtsGNode * g1,
-			    GtsGNode * g2,
-			    gpointer data)
-{
-  GtsPGEdge * we;
-
-  we = GTS_PGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass), g1, g2));
-  we->data = data;
-
-  return we;
-}
-
-/* GtsWGEdge */
-
-static gfloat wgedge_weight (GtsGEdge * e)
-{
-  return GTS_WGEDGE (e)->weight;
-}
-
-static void wgedge_class_init (GtsWGEdgeClass * klass)
-{
-  GTS_GEDGE_CLASS (klass)->weight = wgedge_weight;
-}
-
-static void wgedge_init (GtsWGEdge * e)
-{
-  e->weight = 1.;
-}
-
-/**
- * gts_wgedge_class:
- * 
- * Returns: the #GtsWGEdgeClass.
- */
-GtsWGEdgeClass * gts_wgedge_class (void)
-{
-  static GtsWGEdgeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo wgedge_info = {
-      "GtsWGEdge",
-      sizeof (GtsWGEdge),
-      sizeof (GtsWGEdgeClass),
-      (GtsObjectClassInitFunc) wgedge_class_init,
-      (GtsObjectInitFunc) wgedge_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()),
-				  &wgedge_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_wgedge_new:
- * @klass: a #GtsWGEdgeClass.
- * @n1: a #GtsGNode.
- * @n2: another #GtsGNode.
- * @weight: the weight of the new edge.
- *
- * Returns: a new #GtsWGEdge of weight @weight linking @n1 and @n2.
- */ 
-GtsWGEdge * gts_wgedge_new (GtsWGEdgeClass * klass,
-			    GtsGNode * g1,
-			    GtsGNode * g2,
-			    gfloat weight)
-{
-  GtsWGEdge * we;
-
-  we = GTS_WGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass), g1, g2));
-  we->weight = weight;
-
-  return we;
-}
-
-/* GtsGraph */
-
-static void graph_init (GtsGraph * g)
-{
-  g->graph_class = gts_graph_class ();
-  g->node_class  = gts_gnode_class ();
-  g->edge_class  = gts_gedge_class ();
-}
-
-static void graph_write (GtsObject * object, FILE * fp)
-{
-  GtsGraph * graph = GTS_GRAPH (object);
-
-  fprintf (fp, " %s %s %s",
-	   object->klass->info.name,
-	   GTS_OBJECT_CLASS (graph->node_class)->info.name,
-	   GTS_OBJECT_CLASS (graph->edge_class)->info.name);
-}
-
-static void graph_read (GtsObject ** object, GtsFile * f)
-{
-  GtsObjectClass * klass;
-
-  if (f->type != GTS_STRING) {
-    gts_file_error (f, "expecting a string (GtsGNodeClass)");
-    return;
-  }
-  klass = gts_object_class_from_name (f->token->str);
-  if (klass == NULL) {
-    gts_file_error (f, "unknown class `%s'", f->token->str);
-    return;
-  }
-  if (!gts_object_class_is_from_class (klass, gts_gnode_class ())) {
-    gts_file_error (f, "class `%s' is not a GtsGNodeClass", f->token->str);
-    return;
-  }
-  GTS_GRAPH (*object)->node_class = GTS_GNODE_CLASS (klass);
-  gts_file_next_token (f);
-
-  if (f->type != GTS_STRING) {
-    gts_file_error (f, "expecting a string (GtsGEdgeClass)");
-    return;
-  }
-  klass = gts_object_class_from_name (f->token->str);
-  if (klass == NULL) {
-    gts_file_error (f, "unknown class `%s'", f->token->str);
-    return;
-  }
-  if (!gts_object_class_is_from_class (klass, gts_gedge_class ())) {
-    gts_file_error (f, "class `%s' is not a GtsGEdgeClass", f->token->str);
-    return;
-  }
-  GTS_GRAPH (*object)->edge_class = GTS_GEDGE_CLASS (klass);
-  gts_file_next_token (f);
-}
-
-static void graph_class_init (GtsGraphClass * klass)
-{
-  klass->weight = NULL;
-
-  GTS_OBJECT_CLASS (klass)->write = graph_write;
-  GTS_OBJECT_CLASS (klass)->read = graph_read;
-}
-
-/**
- * gts_graph_class:
- *
- * Returns: the #GtsGraphClass.
- */
-GtsGraphClass * gts_graph_class (void)
-{
-  static GtsGraphClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo graph_info = {
-      "GtsGraph",
-      sizeof (GtsGraph),
-      sizeof (GtsGraphClass),
-      (GtsObjectClassInitFunc) graph_class_init,
-      (GtsObjectInitFunc) graph_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_hash_container_class ()),
-				  &graph_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_graph_new:
- * @klass: a #GtsGraphClass.
- * @node_class: a #GtsGNodeClass.
- * @edge_class: a #GtsGEdgeClass.
- *
- * Returns: a new #GtsGraph using @node_class and @edge_class as node types.
- */
-GtsGraph * gts_graph_new (GtsGraphClass * klass,
-			  GtsGNodeClass * node_class,
-			  GtsGEdgeClass * edge_class)
-{
-  GtsGraph * g;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (node_class != NULL, NULL);
-  g_return_val_if_fail (edge_class != NULL, NULL);
-
-  g = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  g->node_class = node_class;
-  g->edge_class = edge_class;
-
-  return g;
-}
-
-static void compute_degree (GtsGNode * n, gpointer * data)
-{
-  GtsGraph * g = data[0];
-  GtsRange * degree = data[1];
-
-  gts_range_add_value (degree, gts_gnode_degree (n, g));
-}
-
-/**
- * gts_graph_print_stats:
- * @g: a #GtsGraph.
- * @fp: a file pointer.
- *
- * Writes to @fp a summary of the properties of @g.
- */
-void gts_graph_print_stats (GtsGraph * g, FILE * fp)
-{
-  GtsRange degree;
-  gpointer data[2];
-
-  g_return_if_fail (g != NULL);
-  g_return_if_fail (fp != NULL);
-
-  fprintf (fp, "# nodes: %d weight: %g\n", 
-	   gts_container_size (GTS_CONTAINER (g)),
-	   gts_graph_weight (g));
-  fprintf (fp, "#   degree: ");
-  gts_range_init (&degree);
-  data[0] = g;
-  data[1] = °ree;
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) compute_degree, data);
-  gts_range_update (&degree);
-  gts_range_print (&degree, fp);
-  fprintf (fp, "\n");
-  fprintf (fp, "#   edges cut: %d edges cut weight: %g\n", 
-	   gts_graph_edges_cut (g),
-	   gts_graph_edges_cut_weight (g));
-}
-
-struct _GtsGraphTraverse {
-  GtsFifo * q;
-  GtsGraph * g;
-};
-
-static void reset_level (GtsGNode * n)
-{
-  n->level = 0;
-}
-
-/**
- * gts_graph_traverse_new:
- * @g: a #GtsGraph.
- * @n: a #GtsGNode belonging to @g.
- * @type: the type of traversal.
- * @reinit: if %TRUE, the traversal is reinitialized.
- *
- * Returns: a new #GtsGraphTraverse initialized for the traversal of
- * @g of type @type, starting from @n.  
- */
-GtsGraphTraverse * gts_graph_traverse_new (GtsGraph * g, 
-					   GtsGNode * n,
-					   GtsTraverseType type,
-					   gboolean reinit)
-{
-  GtsGraphTraverse * t;
-
-  g_return_val_if_fail (g != NULL, NULL);
-  g_return_val_if_fail (n != NULL, NULL);
-  g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n), 
-						    GTS_CONTAINER (g)), 
-			NULL);
-
-  if (reinit)
-    gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) reset_level, NULL);
-
-  t = g_malloc (sizeof (GtsGraphTraverse));
-  t->q = gts_fifo_new ();
-  t->g = g;
-  n->level = 1;
-  gts_fifo_push (t->q, n);
-
-  return t;
-}
-
-static void push_neighbor (GtsGNode * n, gpointer * data)
-{
-  GtsFifo * q = data[0];
-  GtsGNode * u = data[1];
-
-  if (n->level == 0) {
-    n->level = u->level + 1;
-    gts_fifo_push (q, n);
-  }
-}
-
-/**
- * gts_graph_traverse_next:
- * @t: a #GtsGraphTraverse.
- *
- * Returns: the next #GtsGNode of the traversal defined by @t or %NULL
- * if the traversal is complete.
- */
-GtsGNode * gts_graph_traverse_next (GtsGraphTraverse * t) 
-{ 
-  GtsGNode * u;
-
-  g_return_val_if_fail (t != NULL, NULL);
-
-  u = gts_fifo_pop (t->q);
-  if (u) {
-    gpointer data[2];
-
-    data[0] = t->q;
-    data[1] = u;
-    gts_gnode_foreach_neighbor (u, t->g, (GtsFunc) push_neighbor, data);
-  }
-  
-  return u;
-}
-
-/**
- * gts_graph_traverse_what_next:
- * @t: a #GtsGraphTraverse.
- *
- * Returns: the next #GtsGNode of the traversal defined by @t or %NULL
- * if the traversal is complete but without advancing the traversal.
- */
-GtsGNode * gts_graph_traverse_what_next (GtsGraphTraverse * t)
-{
-  g_return_val_if_fail (t != NULL, NULL);
-
-  return gts_fifo_top (t->q);
-}
-
-/**
- * gts_graph_traverse_destroy:
- * @t: a #GtsGraphTraverse.
- *
- * Frees all the memory allocated for @t.
- */
-void gts_graph_traverse_destroy (GtsGraphTraverse * t)
-{
-  g_return_if_fail (t != NULL);
-
-  gts_fifo_destroy (t->q);
-  g_free (t);
-}
-
-static void edge_foreach_node (GtsGNode * n, gpointer * info)
-{
-  GtsFunc func = (GtsFunc) info[0];
-  gpointer data = info[1];
-  GHashTable * hash = info[2];
-  GSList * i = GTS_SLIST_CONTAINER (n)->items;
-
-  while (i) {
-    GtsGEdge * e = i->data;
-    if (!g_hash_table_lookup (hash, e)) {
-      (* func) (e, data);
-      g_hash_table_insert (hash, e, e);
-    }
-    i = i->next;
-  }  
-}
-
-/**
- * gts_graph_foreach_edge:
- * @g: a #GtsGraph.
- * @func: a #GtsFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func for each #GtsEdge of @g.
- */
-void gts_graph_foreach_edge (GtsGraph * g, GtsFunc func, gpointer data)
-{
-  gpointer info[3];
-  GHashTable * hash;
-
-  g_return_if_fail (g != NULL);
-  g_return_if_fail (func != NULL);
-
-  info[0] = func;
-  info[1] = data;
-  info[2] = hash = g_hash_table_new (NULL, NULL);
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) edge_foreach_node, info);
-  g_hash_table_destroy (hash);
-}
-
-/**
- * gts_graph_weight:
- * @g: a #GtsGraph.
- *
- * Returns: the weight of graph @g as defined by the weight() method
- * of #GtsGraphClass. 
- */
-gfloat gts_graph_weight (GtsGraph * g)
-{
-  g_return_val_if_fail (g != NULL, 0.);
-
-  if (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass)->weight)
-    return (* GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass)->weight) (g);
-  return (gfloat) gts_container_size (GTS_CONTAINER (g));
-}
-
-/**
- * gts_graph_distance_sum:
- * @g: a #GtsGraph.
- * @center: a #GtsGNode of @g.
- *
- * Returns: the sum of the distances between all the other #GtsGNode
- * of @g and @center.  
- */
-guint gts_graph_distance_sum (GtsGraph * g, GtsGNode * center)
-{
-  GtsGraphTraverse * t;
-  GtsGNode * n;
-  guint sum = 0;
-
-  g_return_val_if_fail (g != NULL, 0);
-  g_return_val_if_fail (center != NULL, 0);
-
-  t = gts_graph_traverse_new (g, center, GTS_BREADTH_FIRST, TRUE);
-  while ((n = gts_graph_traverse_next (t)))
-    sum += n->level - 1;
-  gts_graph_traverse_destroy (t);
-
-  return sum;
-}
-
-/**
- * gts_graph_farthest:
- * @g: a #GtsGraph.
- * @gnodes: a list of #GtsGNode belonging to @g.
- *
- * Returns: the #GtsGNode belonging to @g and farthest from all the nodes in
- * @gnodes (hmmm, definition of "farthest"?).
- */
-GtsGNode * gts_graph_farthest (GtsGraph * g, GSList * gnodes)
-{
-  GtsGNode * farthest = NULL;
-  GSList * i;
-  gboolean reinit = TRUE, changed = TRUE;
-  guint level = 1;
-
-  g_return_val_if_fail (g != NULL, NULL);
-
-  /* initialize traversals */
-  i = gnodes;
-  while (i) {
-    GTS_OBJECT (i->data)->reserved = 
-      gts_graph_traverse_new (g, i->data, GTS_BREADTH_FIRST, reinit);
-    reinit = FALSE;
-    i = i->next;
-  }
-
-  while (changed) {
-    changed = FALSE;
-    i = gnodes;
-    while (i) {
-      GtsGraphTraverse * t = GTS_OBJECT (i->data)->reserved;
-      GtsGNode * n;
-      while ((n = gts_graph_traverse_what_next (t)) && n->level == level) {
-	changed = TRUE;
-	farthest = n;
-	gts_graph_traverse_next (t);
-      }
-      i = i->next;
-    }
-    level++;
-  }
-
-  /* destroy traversals */
-  i = gnodes;
-  while (i) {
-    gts_graph_traverse_destroy (GTS_OBJECT (i->data)->reserved);
-    GTS_OBJECT (i->data)->reserved = NULL;
-    i = i->next;
-  }
-  return farthest;
-}
-
-static void neighbor_count (GtsGNode * n, gpointer * data)
-{
-  guint * cuts = data[0];
-  GtsGraph * g = data[1];
-  
-  if (!gts_containee_is_contained (GTS_CONTAINEE (n), GTS_CONTAINER (g)))
-    (*cuts)++;
-}
-
-static void count_edge_cuts (GtsGNode * n, gpointer * data)
-{
-  gts_gnode_foreach_neighbor (n, NULL, (GtsFunc) neighbor_count, data);
-}
-
-/**
- * gts_graph_edges_cut:
- * @g: a #GtsGraph.
- *
- * Returns: the number of edges of @g connecting nodes belonging to @g
- * to nodes not belonging to @g.  
- */
-guint gts_graph_edges_cut (GtsGraph * g)
-{
-  guint cuts = 0;
-  gpointer data[2];
-
-  g_return_val_if_fail (g != NULL, 0);
-
-  data[0] = &cuts;
-  data[1] = g;
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) count_edge_cuts, data);
-
-  return cuts;
-}
-
-static void sum_edge_cuts_weight (GtsGNode * n, gpointer * data)
-{
-  gfloat * weight = data[0];
-  GtsGraph * g = data[1];
-  GSList * i = GTS_SLIST_CONTAINER (n)->items;
-
-  while (i) {
-    GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-    if (!gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g)))
-      *weight += gts_gedge_weight (i->data);
-    i = i->next;
-  }
-}
-
-/**
- * gts_graph_edges_cut_weight:
- * @g: a #GtsGraph.
- *
- * Returns: the sum of the weights of the edges of @g connecting nodes
- * belonging to @g to nodes not belonging to @g.
- */
-gfloat gts_graph_edges_cut_weight (GtsGraph * g)
-{
-  gfloat weight = 0.;
-  gpointer data[2];
-
-  g_return_val_if_fail (g != NULL, 0);
-
-  data[0] = &weight;
-  data[1] = g;
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) sum_edge_cuts_weight, 
-			 data);
-
-  return weight;
-}
-
-/**
- * gts_graph_read_jostle:
- * @g: a #GtsGraph.
- * @fp: a #GtsFile.
- *
- * Adds to @g the nodes and edges defined in the file pointed to by
- * @fp. This file must use the Jostle "graph" ASCII format.  
- * The nodes created are of type #GtsNGNode and their identities are the
- * line number at which they appear in @fp.
- *
- * Returns: 0 if the lecture was successful, the line number at which
- * an error occured otherwise (in which case the @error field of @fp
- * is set).  
- */
-guint gts_graph_read_jostle (GtsGraph * g, GtsFile * fp)
-{
-  guint nn, ne, n;
-  GtsGNode ** nodes;
-
-  g_return_val_if_fail (g != NULL, 1);
-  g_return_val_if_fail (fp != NULL, 1);
-
-  if (fp->type != GTS_INT) {
-    gts_file_error (fp, "expecting an integer (number of nodes)");
-    return fp->line;
-  }
-  nn = atoi (fp->token->str);
-  gts_file_next_token (fp);
-
-  if (fp->type != GTS_INT) {
-    gts_file_error (fp, "expecting an integer (number of edges)");
-    return fp->line;
-  }
-  ne = atoi (fp->token->str);
-
-  gts_file_first_token_after (fp, '\n');
-  nodes = g_malloc (sizeof (GtsGNode *)*(nn + 1));
-
-  n = 0;
-  while (n < nn && fp->type != GTS_ERROR) {
-    GtsNGNode * node = gts_ngnode_new (gts_ngnode_class (), fp->line);
-    
-    nodes[n++] = GTS_GNODE (node);
-    gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (node));
-    do {
-      if (fp->type != GTS_INT)
-	gts_file_error (fp, "expecting an integer (node index)");
-      else {
-	guint in = atoi (fp->token->str);
-	
-	if (in == 0 || in > nn)
-	  gts_file_error (fp, "node index `%d' is out of range `[1,%d]'",
-			  in, nn);
-	else if (in == n)
-	  gts_file_error (fp, "node index `%d' references itself", in);
-	else if (in < n) {
-	  gts_gedge_new (g->edge_class, GTS_GNODE (node), nodes[in - 1]);
-	  ne--;
-	  gts_file_next_token (fp);
-	}
-      }
-    } while (fp->type != GTS_ERROR && fp->type != '\n');
-  }
-  g_free (nodes);
-
-  if (fp->type != GTS_ERROR) {
-    if (n != nn)
-      gts_file_error (fp, "only `%d' nodes read out of `%d'",
-		      n, nn);
-    else if (ne > 0)
-      gts_file_error (fp, "`%d' unallocated edges remaining",
-		      ne);
-  }
-
-  if (fp->type == GTS_ERROR)
-    return fp->line;
-  return 0;
-}
-
-static void count_edges (GtsGEdge * e, guint * nedge)
-{
-  (*nedge)++;
-}
-
-static void write_node (GtsObject * node, gpointer * data)
-{
-  FILE * fp = data[0];
-  guint * nnode = data[1];
-
-  node->reserved = GUINT_TO_POINTER ((*nnode)++);
-  if (node->klass->write)
-    (* node->klass->write) (node, fp);
-  fputc ('\n', fp);
-}
-
-static void write_edge (GtsGEdge * edge, FILE * fp)
-{
-  fprintf (fp, "%u %u", 
-	   GPOINTER_TO_UINT (GTS_OBJECT (edge->n1)->reserved),
-	   GPOINTER_TO_UINT (GTS_OBJECT (edge->n2)->reserved));
-  if (GTS_OBJECT (edge)->klass->write)
-    (* GTS_OBJECT (edge)->klass->write) (GTS_OBJECT (edge), fp);
-  fputc ('\n', fp);
-}
-
-/**
- * gts_graph_write:
- * @g: a #GtsGraph.
- * @fp: a file pointer.
- *
- * Writes in the file @fp an ASCII representation of @g. The file
- * format is as follows. 
- *
- * All the lines beginning with #GTS_COMMENTS are ignored. The first line
- * contains two unsigned integers separated by spaces. The first
- * integer is the number of nodes, nn, the second is the number of
- * edges, ne.
- *
- * Follows nn lines containing node description.
- * Follows ne lines containing the two indices (starting
- * from one) of the nodes of each edge.
- *
- * The format described above is the least common denominator to all
- * GTS files.  Consistent with an object-oriented approach, the GTS
- * file format is extensible. Each of the lines of the file can be
- * extended with user-specific attributes accessible through the
- * read() and write() virtual methods of each of the objects written
- * (graph, nodes or edges). When read with different object classes,
- * these extra attributes are just ignored.  
- */
-void gts_graph_write (GtsGraph * g, FILE * fp)
-{
-  guint nnode = 1, nedge = 0;
-  gpointer data[2];
-
-  g_return_if_fail (g != NULL);
-  g_return_if_fail (fp != NULL);
-
-  gts_graph_foreach_edge (g, (GtsFunc) count_edges, &nedge);
-  fprintf (fp, "%u %u", gts_container_size (GTS_CONTAINER (g)), nedge);
-  if (GTS_OBJECT (g)->klass->write)
-    (* GTS_OBJECT (g)->klass->write) (GTS_OBJECT (g), fp);
-  fputc ('\n', fp);
-  data[0] = fp;
-  data[1] = &nnode;
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) write_node, data);
-  gts_graph_foreach_edge (g, (GtsFunc) write_edge, fp);
-  gts_container_foreach (GTS_CONTAINER (g), 
-			 (GtsFunc) gts_object_reset_reserved, NULL);
-}
-
-/**
- * gts_graph_read:
- * @fp: a #GtsFile.
- *
- * Reads a graph from a file.
- *
- * Returns: the new #GtsGraph or %NULL if an error occured (in which
- * case the @error field of @fp is set).
- */
-GtsGraph * gts_graph_read (GtsFile * fp)
-{
-  GtsGraph * g;
-  GtsGNode ** nodes;
-  guint nn, ne, n;
-
-  g_return_val_if_fail (fp != NULL, NULL);
-
-  if (fp->type != GTS_INT) {
-    gts_file_error (fp, "expecting an integer (number of nodes)");
-    return NULL;
-  }
-  nn = atoi (fp->token->str);
-  gts_file_next_token (fp);
-
-  if (fp->type != GTS_INT) {
-    gts_file_error (fp, "expecting an integer (number of edges)");
-    return NULL;
-  }
-  ne = atoi (fp->token->str);
-
-  gts_file_next_token (fp);
-  if (fp->type != '\n') {
-    GtsObjectClass * klass;
-
-    gts_graph_class ();
-    gts_gnode_class ();
-    gts_gedge_class ();
-
-    if (fp->type != GTS_STRING) {
-      gts_file_error (fp, "expecting a string (GtsGraphClass)");
-      return NULL;
-    }
-    klass = gts_object_class_from_name (fp->token->str);
-    if (klass == NULL) {
-      gts_file_error (fp, "unknown class `%s'", fp->token->str);
-      return NULL;
-    }
-    if (!gts_object_class_is_from_class (klass, gts_graph_class ())) {
-      gts_file_error (fp, "class `%s' is not a GtsGraphClass", fp->token->str);
-      return NULL;
-    }
-    g = GTS_GRAPH (gts_object_new (klass));
-    g->graph_class = GTS_GRAPH_CLASS (klass);
-    gts_file_next_token (fp);
-    (* klass->read) ((GtsObject **) &g, fp);
-    if (fp->type == GTS_ERROR) {
-      gts_object_destroy (GTS_OBJECT (g));
-      return NULL;
-    }
-  }
-  else
-    g = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (gts_graph_class ())));
-  gts_file_first_token_after (fp, '\n');
-  if (nn <= 0)
-    return g;
-
-  nodes = g_malloc ((nn + 1)*sizeof (GtsGNode *));
-
-  n = 0;
-  while (n < nn && fp->type != GTS_ERROR) {
-    GtsObject * new_node = 
-      gts_object_new (GTS_OBJECT_CLASS (g->node_class));
-
-    gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (new_node));
-    if (GTS_OBJECT_CLASS (g->node_class)->read)
-      (*GTS_OBJECT_CLASS (g->node_class)->read) (&new_node, fp);
-    gts_file_first_token_after (fp, '\n');
-    nodes[n++] = GTS_GNODE (new_node);
-  }
-  if (fp->type == GTS_ERROR)
-    nn = n;
-
-  n = 0;
-  while (n < ne && fp->type != GTS_ERROR) {
-    guint n1, n2;
-
-    if (fp->type != GTS_INT)
-      gts_file_error (fp, "expecting an integer (first node index)");
-    else {
-      n1 = atoi (fp->token->str);
-      if (n1 == 0 || n1 > nn)
-	gts_file_error (fp, "node index `%d' is out of range `[1,%d]'",
-			n1, nn);
-      else {
-	gts_file_next_token (fp);
-	if (fp->type != GTS_INT)
-	  gts_file_error (fp, "expecting an integer (second node index)");
-	else {
-	  n2 = atoi (fp->token->str);
-	  if (n2 == 0 || n2 > nn)
-	    gts_file_error (fp, "node index `%d' is out of range `[1,%d]'",
-			    n2, nn);
-	  else {
-	    GtsGEdge * new_edge =
-	      gts_gedge_new (g->edge_class, nodes[n1 - 1], nodes [n2 - 1]);
-
-	    gts_file_next_token (fp);
-	    if (fp->type != '\n')
-	      if (GTS_OBJECT_CLASS (g->edge_class)->read)
-		(*GTS_OBJECT_CLASS (g->edge_class)->read)
-		  ((GtsObject **) &new_edge, fp);
-	    gts_file_first_token_after (fp, '\n');
-	    n++;
-	  }
-	}
-      }
-    }
-  }
-
-  if (fp->type == GTS_ERROR) {
-    gts_allow_floating_gnodes = TRUE;
-    while (nn)
-      gts_object_destroy (GTS_OBJECT (nodes[nn-- - 1]));
-    gts_allow_floating_gnodes = FALSE;
-  }
-  g_free (nodes);
-
-  if (fp->type == GTS_ERROR) {
-    gts_object_destroy (GTS_OBJECT (g));
-    return NULL;
-  }
-  return g;
-}
-
-static void write_dot_node (GtsGNode * node, gpointer * data)
-{
-  FILE * fp = data[0];
-  guint * nnode = data[1];
-
-  fprintf (fp, "  n%u", *nnode);
-  if (GTS_GNODE_CLASS (GTS_OBJECT (node)->klass)->write) {
-    fputs (" [", fp);
-    (* GTS_GNODE_CLASS (GTS_OBJECT (node)->klass)->write) (node, fp);
-    fputc (']', fp);
-  }
-  fputs (";\n", fp);
-  GTS_OBJECT (node)->reserved = GUINT_TO_POINTER ((*nnode)++);  
-}
-
-static void write_dot_edge (GtsGEdge * edge, FILE * fp)
-{
-  fprintf (fp, "  n%u -> n%u", 
-	   GPOINTER_TO_UINT (GTS_OBJECT (edge->n1)->reserved),
-	   GPOINTER_TO_UINT (GTS_OBJECT (edge->n2)->reserved));
-  if (GTS_GEDGE_CLASS (GTS_OBJECT (edge)->klass)->write) {
-    fputs (" [", fp);
-    (* GTS_GEDGE_CLASS (GTS_OBJECT (edge)->klass)->write) (edge, fp);
-    fputc (']', fp);
-  }
-  fputs (";\n", fp);
-}
-
-/**
- * gts_graph_write_dot:
- * @g: a #GtsGraph.
- * @fp: a file pointer.
- *
- * Writes in the file @fp an ASCII representation of @g in the dot format of
- * AT&T Bell Labs.
- */
-void gts_graph_write_dot (GtsGraph * g, FILE * fp)
-{
-  guint nnode = 1;
-  gpointer data[2];
-
-  g_return_if_fail (g != NULL);
-  g_return_if_fail (fp != NULL);
-
-  fprintf (fp, "digraph \"%p\" {\n", g);
-  data[0] = fp;
-  data[1] = &nnode;
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) write_dot_node, data);
-  gts_graph_foreach_edge (g, (GtsFunc) write_dot_edge, fp);
-  fputs ("}\n", fp);
-
-  gts_container_foreach (GTS_CONTAINER (g), 
-			 (GtsFunc) gts_object_reset_reserved, NULL);
-}
-
-/* GtsWGraph */
-
-static gfloat wgraph_weight (GtsGraph * g)
-{
-  return GTS_WGRAPH (g)->weight;
-}
-
-static void wgraph_add (GtsContainer * g, GtsContainee * n)
-{
-  GtsWGraph * wg = GTS_WGRAPH (g);
-  gfloat w = gts_gnode_weight (GTS_GNODE (n));
-
-  wg->weight += w;
-  
-  (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class)->add) (g, n);
-}
-
-static void wgraph_remove (GtsContainer * g, GtsContainee * n)
-{
-  GTS_WGRAPH (g)->weight -= gts_gnode_weight (GTS_GNODE (n));
-  
-  (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class)->remove) (g, n);
-}
-
-static void wgraph_class_init (GtsWGraphClass * klass)
-{
-  GTS_GRAPH_CLASS (klass)->weight = wgraph_weight;
-
-  GTS_CONTAINER_CLASS (klass)->add = wgraph_add;
-  GTS_CONTAINER_CLASS (klass)->remove = wgraph_remove;
-}
-
-static void wgraph_init (GtsWGraph * g)
-{
-  g->weight = 0.;
-}
-
-/**
- * gts_wgraph_class:
- *
- * Returns: the #GtsWGraphClass.
- */
-GtsWGraphClass * gts_wgraph_class (void)
-{
-  static GtsWGraphClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo wgraph_info = {
-      "GtsWGraph",
-      sizeof (GtsWGraph),
-      sizeof (GtsWGraphClass),
-      (GtsObjectClassInitFunc) wgraph_class_init,
-      (GtsObjectInitFunc) wgraph_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_graph_class ()),
-				  &wgraph_info);
-  }
-
-  return klass;
-}
-
-static void weight_max (GtsGNode * n, gfloat * wmax)
-{
-  gfloat w = gts_gnode_weight (n);
-
-  if (w > *wmax)
-    *wmax = w;
-}
-
-/**
- * gts_wgraph_weight_max:
- * @wg: a #GtsWGraph.
- *
- * Returns: the maximum weight of any vertices belonging to @g.
- */
-gfloat gts_wgraph_weight_max (GtsWGraph * wg)
-{
-  gfloat wmax = - G_MAXFLOAT;
-
-  g_return_val_if_fail (wg != NULL, 0.);
-
-  gts_container_foreach (GTS_CONTAINER (wg), (GtsFunc) weight_max, &wmax);
-
-  return wmax;
-}
-
-/* Surface graph */
-
-static void create_node (GtsFace * f, GtsGraph * graph)
-{
-  GtsFNode * fn = gts_fnode_new (gts_fnode_class (), f);
-
-  gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (fn));
-  GTS_OBJECT (f)->reserved = fn;
-}
-
-static void create_edge (GtsEdge * e, GtsSurface * s)
-{
-  GSList * i = e->triangles;
-  
-  while (i) {
-    GtsFace * f = i->data;
-    if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) {
-      GSList * j = i->next;
-      while (j) {
-	GtsFace * f1 = j->data;
-	if (GTS_IS_FACE (f1) && gts_face_has_parent_surface (f1, s))
-	  gts_pgedge_new (gts_pgedge_class (), 
-			  GTS_OBJECT (f)->reserved,
-			  GTS_OBJECT (f1)->reserved,
-			  e);
-	j = j->next;
-      }
-    }
-    i = i->next;
-  }
-}
-
-/**
- * gts_surface_graph_new:
- * @klass: a #GtsGraphClass.
- * @s: a #GtsSurface.
- *
- * Returns: a new #GtsGraph representing the connectivity of the faces
- * of @s. This graph uses #GtsFGNode as nodes which allows to store
- * the dependencies between nodes and faces of @s.  
- */
-GtsGraph * gts_surface_graph_new (GtsGraphClass * klass,
-				  GtsSurface * s)
-{
-  GtsGraph * graph;
-  
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (s != NULL, NULL);
-
-  graph = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  gts_surface_foreach_face (s, (GtsFunc) create_node, graph);
-  gts_surface_foreach_edge (s, (GtsFunc) create_edge, s);
-  gts_surface_foreach_face (s, (GtsFunc) gts_object_reset_reserved, NULL);
-
-  return graph;
-}
-
-static void create_segment_edge (GtsSegment * s, GtsGraph * graph)
-{
-  GtsGNode * n1 = GTS_OBJECT (s->v1)->reserved, * n2;
-
-  if (n1 == NULL) {
-    n1 = GTS_GNODE (gts_pnode_new (gts_pnode_class (), s->v1));
-    gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (n1));
-    GTS_OBJECT (s->v1)->reserved = n1;
-  }
-
-  n2 = GTS_OBJECT (s->v2)->reserved;
-  if (n2 == NULL) {
-    n2 = GTS_GNODE (gts_pnode_new (gts_pnode_class (), s->v2));
-    gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (n2));
-    GTS_OBJECT (s->v2)->reserved = n2;
-  }
-  
-  gts_pgedge_new (gts_pgedge_class (), n1, n2, s);
-}
-
-static void reset_reserved (GtsSegment * s)
-{
-  GTS_OBJECT (s->v1)->reserved = GTS_OBJECT (s->v2)->reserved = NULL;
-}
-
-/**
- * gts_segments_graph_new:
- * @klass: a #GtsGraphClass.
- * @segments: a list of #GtsSegment.
- *
- * Returns: a new #GtsGraph representing the connectivity of the segments
- * in @segments.
- */
-GtsGraph * gts_segments_graph_new (GtsGraphClass * klass,
-				   GSList * segments)
-{
-  GtsGraph * graph;
-  
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  graph = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  g_slist_foreach (segments, (GFunc) create_segment_edge, graph);
-  g_slist_foreach (segments, (GFunc) reset_reserved, NULL);
-
-  return graph;
-}
-
-static void add_to_surface (GtsGNode * n, GtsSurface * s)
-{
-  if (GTS_IS_FNODE (n))
-    gts_surface_add_face (s, GTS_FNODE (n)->f);
-}
-
-/**
- * gts_surface_graph_surface:
- * @surface_graph: a #GtsGraph using #GtsFGNode as nodes.
- * @s: a #GtsSurface.
- *
- * Returns: a new #GtsSurface using the same classes as @s and
- * composed of the faces defined by @surface_graph.
- */
-GtsSurface * gts_surface_graph_surface (GtsGraph * surface_graph,
-					GtsSurface * s)
-{
-  GtsSurface * s1;
-
-  g_return_val_if_fail (surface_graph != NULL, NULL);
-  g_return_val_if_fail (s != NULL, NULL);
-  
-  s1 = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass),
-			s->face_class,
-			s->edge_class,
-			s->vertex_class);
-  gts_container_foreach (GTS_CONTAINER (surface_graph), 
-			 (GtsFunc) add_to_surface, s1);
-  return s1;
-}
-
diff --git a/src_3rd/gts/gts-private.h b/src_3rd/gts/gts-private.h
deleted file mode 100644
index 59246d1..0000000
--- a/src_3rd/gts/gts-private.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GTS_PRIVATE_H__
-#define __GTS_PRIVATE_H__
-
-/* Debugging flags */
-  
-/* #define DEBUG_FUNCTIONS */
-
-#ifdef DEBUG_FUNCTIONS
-/* #define DEBUG_LEAKS */
-#define DEBUG_IDENTITY
-guint id (gpointer p);
-void id_insert (gpointer p);
-void id_remove (gpointer p);
-void gts_write_triangle (GtsTriangle * t, GtsPoint * o, FILE * fptr);
-void gts_write_segment (GtsSegment * s, GtsPoint * o, FILE * fptr);
-#endif /* DEBUG_FUNCTIONS */
-
-#endif /* __GTS_PRIVATE_H__ */
diff --git a/src_3rd/gts/gts.h b/src_3rd/gts/gts.h
deleted file mode 100644
index 9397230..0000000
--- a/src_3rd/gts/gts.h
+++ /dev/null
@@ -1,2577 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GTS_H__
-#define __GTS_H__
-
-#include <stdio.h>
-#include <glib.h>
-
-#define GTS_MAJOR_VERSION 0
-#define GTS_MINOR_VERSION 7
-#define GTS_MICRO_VERSION 6
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/* Added based on glib.h by M J Loehr 01/01/01 */
-/* GTS version.
- * we prefix variable declarations so they can
- * properly get exported in windows dlls.
- */
-#ifdef NATIVE_WIN32
-#  ifdef GTS_COMPILATION
-#    define GTS_C_VAR __declspec(dllexport)
-#  else /* not GTS_COMPILATION */
-#    define GTS_C_VAR extern __declspec(dllimport)
-#  endif /* not GTS_COMPILATION */
-#else /* not NATIVE_WIN32 */
-#  define GTS_C_VAR extern
-#endif /* not NATIVE_WIN32 */
-
-GTS_C_VAR const guint gts_major_version;
-GTS_C_VAR const guint gts_minor_version;
-GTS_C_VAR const guint gts_micro_version;
-GTS_C_VAR const guint gts_interface_age;
-GTS_C_VAR const guint gts_binary_age;
-
-#define GTS_CHECK_VERSION(major,minor,micro)    \
-    (gts_major_version > (major) || \
-    (gts_major_version == (major) && gts_minor_version > (minor)) || \
-    (gts_major_version == (major) && gts_minor_version == (minor) && \
-     gts_micro_version >= (micro)))
-
-#define GTS_COMMENTS  "#!"
-#define GTS_MAINTAINER "popinet at users.sourceforge.net"
-
-
-
-
-void gts_predicates_init();
-
-
-/* Class declarations for base types */
-
-typedef struct _GtsObjectClassInfo     GtsObjectClassInfo;
-typedef struct _GtsObject        GtsObject;
-typedef struct _GtsObjectClass   GtsObjectClass;
-typedef struct _GtsPoint         GtsPoint;
-typedef struct _GtsPointClass    GtsPointClass;
-typedef struct _GtsVertex        GtsVertex;
-typedef struct _GtsVertexClass   GtsVertexClass;
-typedef struct _GtsSegment       GtsSegment;
-typedef struct _GtsSegmentClass  GtsSegmentClass;
-typedef struct _GtsEdge          GtsEdge;
-typedef struct _GtsEdgeClass     GtsEdgeClass;
-typedef struct _GtsTriangle      GtsTriangle;
-typedef struct _GtsTriangleClass GtsTriangleClass;
-typedef struct _GtsFace          GtsFace;
-typedef struct _GtsFaceClass     GtsFaceClass;
-typedef struct _GtsBBox          GtsBBox;
-typedef struct _GtsBBoxClass     GtsBBoxClass;
-typedef struct _GtsSurface       GtsSurface;
-typedef struct _GtsSurfaceClass  GtsSurfaceClass;
-
-typedef void         (*GtsObjectClassInitFunc) (GtsObjectClass * objclass);
-typedef void         (*GtsObjectInitFunc)      (GtsObject * obj);
-typedef void         (*GtsArgSetFunc)          (GtsObject * obj);
-typedef void         (*GtsArgGetFunc)          (GtsObject * obj);
-
-typedef gdouble                  GtsVector[3];
-typedef gdouble                  GtsVector4[4];
-typedef GtsVector4               GtsMatrix;
-/**
- * GtsKeyFunc:
- * @item: A pointer to an item to be stored in the heap.
- * @data: User data passed to gts_eheap_new().
- *
- * Returns: the value of the key for the given item.
- */
-typedef gdouble                  (*GtsKeyFunc)    (gpointer item,
-						   gpointer data);
-typedef enum 
-{ 
-  GTS_OUT = -1,
-  GTS_ON = 0,
-  GTS_IN = 1
-} GtsIntersect;
-
-typedef struct _GtsColor         GtsColor;
-
-struct _GtsColor {
-  gfloat r, g, b;
-};
-
-typedef gint   (*GtsFunc)              (gpointer item,
-					gpointer data);
-
-/* misc.c */
-
-typedef struct _GtsFile GtsFile;
-
-typedef enum {
-  GTS_NONE   = 1 << 8,
-  GTS_INT    = 1 << 9,
-  GTS_UINT   = 1 << 10,
-  GTS_FLOAT  = 1 << 11,
-  GTS_DOUBLE = 1 << 12,
-  GTS_STRING = 1 << 13,
-  GTS_FILE   = 1 << 14,
-  GTS_ERROR  = 1 << 15
-} GtsTokenType;
-
-struct _GtsFile {
-  FILE * fp;
-  gchar * s, * s1;
-  guint line, pos;
-  GString * token;
-  GtsTokenType type;
-  gchar * error;
-
-  guint curline, curpos;
-  guint scope, scope_max;
-  gint next_token;
-  gchar * delimiters;
-  gchar * comments;
-  gchar * tokens;
-};
-
-typedef struct _GtsFileVariable GtsFileVariable;
-
-struct _GtsFileVariable {
-  GtsTokenType type;
-  gchar name[30];
-  gboolean unique;
-  gpointer data;
-  gboolean set;
-  guint line, pos;
-};
-
-
-GtsFile *      gts_file_new               (FILE * fp);
-GtsFile *      gts_file_new_from_string   (const gchar * s);
-void           gts_file_verror            (GtsFile * f,
-					   const gchar * format,
-					   va_list args);
-void           gts_file_error             (GtsFile * f,
-					   const gchar * format,
-					   ...);
-gint           gts_file_getc              (GtsFile * f);
-guint          gts_file_read              (GtsFile * f, 
-					   gpointer ptr, 
-					   guint size, 
-					   guint nmemb);
-gint           gts_file_getc_scope        (GtsFile * f);
-void           gts_file_next_token        (GtsFile * f);
-void           gts_file_first_token_after (GtsFile * f, 
-					   GtsTokenType type);
-void           gts_file_assign_start      (GtsFile * f, 
-					   GtsFileVariable * vars);
-GtsFileVariable * gts_file_assign_next    (GtsFile * f, 
-					   GtsFileVariable * vars);
-void           gts_file_assign_variables  (GtsFile * f, 
-					   GtsFileVariable * vars);
-void           gts_file_variable_error    (GtsFile * f, 
-					   GtsFileVariable * vars,
-					   const gchar * name,
-					   const gchar * format,
-					   ...);
-void           gts_file_destroy           (GtsFile * f);
-
-/* Objects: object.c */
-
-#ifdef GTS_CHECK_CASTS
-#  define GTS_OBJECT_CAST(obj, type, klass) ((type *) gts_object_check_cast (obj, klass))
-#  define GTS_OBJECT_CLASS_CAST(objklass, type, klass) ((type *) gts_object_class_check_cast (objklass, klass))
-#else  /* not GTS_CHECK_CASTS */
-#  define GTS_OBJECT_CAST(obj, type, klass)             ((type *) (obj))
-#  define GTS_OBJECT_CLASS_CAST(objklass, type, klass)  ((type *) (objklass))
-#endif /* not GTS_CHECK_CASTS */
-
-#define GTS_CLASS_NAME_LENGTH 40
-#define GTS_OBJECT(obj)          GTS_OBJECT_CAST (obj,\
-						  GtsObject,\
-						  gts_object_class ())
-#define GTS_OBJECT_CLASS(klass)  GTS_OBJECT_CLASS_CAST (klass,\
-							GtsObjectClass,\
-							gts_object_class())
-#define GTS_IS_OBJECT(obj) (gts_object_is_from_class (obj,\
-						      gts_object_class ()))
-
-typedef enum
-{
-  GTS_DESTROYED         = 1 << 0,
-  GTS_USER_FLAG         = 1 /* user flags start from here */
-} GtsObjectFlags;
-
-#define GTS_OBJECT_FLAGS(obj)             (GTS_OBJECT (obj)->flags)
-#define GTS_OBJECT_DESTROYED(obj)         ((GTS_OBJECT_FLAGS (obj) & GTS_DESTROYED) != 0)
-#define GTS_OBJECT_SET_FLAGS(obj,flag)	  G_STMT_START{ (GTS_OBJECT_FLAGS (obj) |= (flag)); }G_STMT_END
-#define GTS_OBJECT_UNSET_FLAGS(obj,flag)  G_STMT_START{ (GTS_OBJECT_FLAGS (obj) &= ~(flag)); }G_STMT_END
-
-struct _GtsObjectClassInfo {
-  gchar name[GTS_CLASS_NAME_LENGTH];
-  guint object_size;
-  guint class_size;
-  GtsObjectClassInitFunc class_init_func;
-  GtsObjectInitFunc object_init_func;
-  GtsArgSetFunc arg_set_func;
-  GtsArgGetFunc arg_get_func;
-};
-
-struct _GtsObject {
-  GtsObjectClass * klass;
-
-  gpointer reserved;
-  guint32 flags;
-};
-
-struct _GtsObjectClass {
-  GtsObjectClassInfo info;
-  GtsObjectClass * parent_class;
-
-  void        (* clone)      (GtsObject *, GtsObject *);
-  void        (* destroy)    (GtsObject *);
-  void        (* read)       (GtsObject **, GtsFile *);
-  void        (* write)      (GtsObject *, FILE *);
-  GtsColor    (* color)      (GtsObject *);
-  void        (* attributes) (GtsObject *, GtsObject *);
-};
-
-gpointer         gts_object_class_new      (GtsObjectClass * parent_class,
-					    GtsObjectClassInfo * info);
-GtsObjectClass * gts_object_class          (void);
-gpointer         gts_object_check_cast     (gpointer object, 
-					    gpointer klass);
-gpointer         gts_object_class_check_cast (gpointer klass, 
-					      gpointer from);
-
-static inline
-gpointer gts_object_is_from_class (gpointer object,
-				   gpointer klass)
-{
-  GtsObjectClass * c;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  if (object == NULL)
-    return NULL;
-
-  c = ((GtsObject *) object)->klass;
-
-  g_return_val_if_fail (c != NULL, NULL);
-
-  while (c) {
-    if (c == klass)
-      return object;
-    c = c->parent_class;
-  }
-
-  return NULL;
-}
-
-static inline
-gpointer gts_object_class_is_from_class (gpointer klass,
-					 gpointer from)
-{
-  GtsObjectClass * c;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (from != NULL, NULL);
-
-  c = (GtsObjectClass *) klass;
-  while (c) {
-    if (c == from)
-      return klass;
-    c = c->parent_class;
-  }
-
-  return NULL;
-}
-
-GtsObjectClass * gts_object_class_from_name     (const gchar * name);
-
-GtsObject *      gts_object_new                 (GtsObjectClass * klass);
-GtsObject *      gts_object_clone               (GtsObject * object);
-void             gts_object_attributes          (GtsObject * object, 
-						 GtsObject * from);
-void             gts_object_init                (GtsObject * object, 
-						 GtsObjectClass * klass);
-void             gts_object_reset_reserved      (GtsObject * object);
-void             gts_object_destroy             (GtsObject * object);
-void             gts_finalize                   (void);
-
-/* Ranges: surface.c */
-typedef struct _GtsRange               GtsRange;
-
-struct _GtsRange {
-  gdouble min, max, sum, sum2, mean, stddev;
-  guint n;
-};
-
-void gts_range_init         (GtsRange * r);
-void gts_range_reset        (GtsRange * r);
-void gts_range_add_value    (GtsRange * r, 
-			     gdouble val);
-void gts_range_update       (GtsRange * r);
-void gts_range_print        (GtsRange * r, 
-			     FILE * fptr);
-
-/* Points: point.c */
-
-#define GTS_IS_POINT(obj) (gts_object_is_from_class (obj,\
-						     gts_point_class ()))
-#define GTS_POINT(obj)              GTS_OBJECT_CAST (obj,\
-						     GtsPoint,\
-						     gts_point_class ())
-#define GTS_POINT_CLASS(klass)      GTS_OBJECT_CLASS_CAST (klass,\
-							   GtsPointClass,\
-							   gts_point_class ())
-
-struct _GtsPoint {
-  GtsObject object;
-
-  gdouble x, y, z; /* must be contiguous (cast to robust functions) */
-};
-
-struct _GtsPointClass {
-  GtsObjectClass parent_class;
-  gboolean binary;
-};
-
-GtsPointClass * gts_point_class                      (void);
-GtsPoint *    gts_point_new                          (GtsPointClass * klass,
-						      gdouble x, 
-						      gdouble y, 
-						      gdouble z);
-void          gts_point_set                          (GtsPoint * p, 
-						      gdouble x, 
-						      gdouble y, 
-						      gdouble z);
-#define       gts_point_is_in_rectangle(p, p1, p2)   ((p)->x >= (p1)->x &&\
-						      (p)->x <= (p2)->x &&\
-						      (p)->y >= (p1)->y &&\
-						      (p)->y <= (p2)->y &&\
-						      (p)->z >= (p1)->z &&\
-						      (p)->z <= (p2)->z)
-GtsPoint *    gts_segment_triangle_intersection      (GtsSegment * s,
-						      GtsTriangle * t,
-						      gboolean boundary,
-						      GtsPointClass * klass);
-void          gts_point_transform                    (GtsPoint * p, 
-						      GtsMatrix * m);
-gdouble       gts_point_distance                     (GtsPoint * p1,
-						      GtsPoint * p2);
-gdouble       gts_point_distance2                    (GtsPoint * p1,
-						      GtsPoint * p2);
-gdouble       gts_point_orientation_3d               (GtsPoint * p1,
-						      GtsPoint * p2,
-						      GtsPoint * p3,
-						      GtsPoint * p4);
-gint          gts_point_orientation_3d_sos           (GtsPoint * p1,
-						      GtsPoint * p2,
-						      GtsPoint * p3,
-						      GtsPoint * p4);
-GtsIntersect  gts_point_is_in_triangle               (GtsPoint * p,
-						      GtsTriangle * t);
-gdouble       gts_point_in_circle                    (GtsPoint * p, 
-						      GtsPoint * p1,
-						      GtsPoint * p2,
-						      GtsPoint * p3);
-gdouble       gts_point_in_sphere                    (GtsPoint * p, 
-						      GtsPoint * p1,
-						      GtsPoint * p2,
-						      GtsPoint * p3,
-						      GtsPoint * p4);
-gdouble       gts_point_in_triangle_circle           (GtsPoint * p, 
-						      GtsTriangle * t);
-gdouble       gts_point_orientation                  (GtsPoint * p1,
-						      GtsPoint * p2,
-						      GtsPoint * p3);
-gint          gts_point_orientation_sos              (GtsPoint * p1,
-						      GtsPoint * p2,
-						      GtsPoint * p3);
-gdouble       gts_point_segment_distance2            (GtsPoint * p, 
-						      GtsSegment * s);
-gdouble       gts_point_segment_distance             (GtsPoint * p, 
-						      GtsSegment * s);
-void          gts_point_segment_closest              (GtsPoint * p, 
-						      GtsSegment * s,
-						      GtsPoint * closest);
-gdouble       gts_point_triangle_distance2           (GtsPoint * p, 
-						      GtsTriangle * t);
-gdouble       gts_point_triangle_distance            (GtsPoint * p, 
-						      GtsTriangle * t);
-void          gts_point_triangle_closest             (GtsPoint * p,
-						      GtsTriangle * t,
-						      GtsPoint * closest);
-gboolean      gts_point_is_inside_surface            (GtsPoint * p, 
-						      GNode * tree,
-						      gboolean is_open);
-
-/* Vertices: vertex.c */
-
-#define GTS_IS_VERTEX(obj)   (gts_object_is_from_class (obj,\
-							gts_vertex_class ()))
-#define GTS_VERTEX(obj)             GTS_OBJECT_CAST (obj,\
-						     GtsVertex,\
-						     gts_vertex_class ())
-#define GTS_VERTEX_CLASS(klass)     GTS_OBJECT_CLASS_CAST (klass,\
-							   GtsVertexClass,\
-							   gts_vertex_class ())
-struct _GtsVertex {
-  GtsPoint p;
-  
-  GSList * segments;
-};
-
-struct _GtsVertexClass {
-  GtsPointClass parent_class;
-
-  void        (* intersection_attributes) (GtsVertex *, 
-					   GtsObject *, 
-					   GtsObject *);
-};
-
-GTS_C_VAR 
-gboolean      gts_allow_floating_vertices;
-
-GtsVertexClass * gts_vertex_class          (void);
-GtsVertex *   gts_vertex_new               (GtsVertexClass * klass,
-					    gdouble x,
-					    gdouble y,
-					    gdouble z);
-void          gts_vertex_replace           (GtsVertex * v, 
-					    GtsVertex * with);
-gboolean      gts_vertex_is_unattached     (GtsVertex * v);
-GtsSegment *  gts_vertices_are_connected   (GtsVertex * v1,
-					    GtsVertex * v2);
-GSList *      gts_vertex_triangles         (GtsVertex * v,
-					    GSList * list);
-GSList *      gts_vertex_faces             (GtsVertex * v,
-					    GtsSurface * surface,
-					    GSList * list);
-GSList *      gts_vertex_neighbors         (GtsVertex * v, 
-					    GSList * list,
-					    GtsSurface * surface);
-GSList *      gts_vertices_from_segments   (GSList * segments);
-gboolean      gts_vertex_is_boundary       (GtsVertex * v, 
-					    GtsSurface * surface);
-GList *       gts_vertices_merge           (GList * vertices, 
-					    gdouble epsilon,
-					    gboolean (* check) (GtsVertex *, GtsVertex *));
-GSList *      gts_vertex_fan_oriented      (GtsVertex * v, 
-					    GtsSurface * surface);
-guint         gts_vertex_is_contact        (GtsVertex * v, gboolean sever);
-
-/* GtsVertexNormal: Header */
-
-typedef struct _GtsVertexNormal         GtsVertexNormal;
-
-struct _GtsVertexNormal {
-  /*< private >*/
-  GtsVertex parent;
-
-  /*< public >*/
-  GtsVector n;
-};
-
-#define GTS_VERTEX_NORMAL(obj)            GTS_OBJECT_CAST (obj,\
-					         GtsVertexNormal,\
-					         gts_vertex_normal_class ())
-#define GTS_IS_VERTEX_NORMAL(obj)         (gts_object_is_from_class (obj,\
-						 gts_vertex_normal_class ()))
-
-GtsVertexClass * gts_vertex_normal_class  (void);
-
-/* GtsColorVertex: Header */
-
-typedef struct _GtsColorVertex         GtsColorVertex;
-
-struct _GtsColorVertex {
-  /*< private >*/
-  GtsVertex parent;
-
-  /*< public >*/
-  GtsColor c;
-};
-
-#define GTS_COLOR_VERTEX(obj)            GTS_OBJECT_CAST (obj,\
-					         GtsColorVertex,\
-					         gts_color_vertex_class ())
-#define GTS_IS_COLOR_VERTEX(obj)         (gts_object_is_from_class (obj,\
-						 gts_color_vertex_class ()))
-
-GtsVertexClass * gts_color_vertex_class  (void);
-
-/* Segments: segment.c */
-
-#define GTS_IS_SEGMENT(obj) (gts_object_is_from_class (obj,\
-						       gts_segment_class ()))
-#define GTS_SEGMENT(obj)          GTS_OBJECT_CAST (obj,\
-						   GtsSegment,\
-						   gts_segment_class ())
-#define GTS_SEGMENT_CLASS(klass)  GTS_OBJECT_CLASS_CAST (klass,\
-							 GtsSegmentClass,\
-							 gts_segment_class ())
-
-struct _GtsSegment {
-  GtsObject object;
-
-  GtsVertex * v1;
-  GtsVertex * v2;
-};
-
-struct _GtsSegmentClass {
-  GtsObjectClass parent_class;
-};
-
-GtsSegmentClass * gts_segment_class                  (void);
-GtsSegment *  gts_segment_new                        (GtsSegmentClass * klass,
-						      GtsVertex * v1, 
-						      GtsVertex * v2);
-#define       gts_segment_connect(s, e1, e2)         (((s)->v1 == e1 &&\
-                                                       (s)->v2 == e2) || \
-                                                      ((s)->v1 == e2 &&\
-                                                       (s)->v2 == e1))
-#define       gts_segments_are_identical(s1, s2)     (((s1)->v1 == (s2)->v1 &&\
-						       (s1)->v2 == (s2)->v2)\
-						      ||\
-						      ((s1)->v1 == (s2)->v2 &&\
-						       (s1)->v2 == (s2)->v1))
-#define       gts_segments_touch(s1, s2)             ((s1)->v1 == (s2)->v1 ||\
-						      (s1)->v1 == (s2)->v2 ||\
-						      (s1)->v2 == (s2)->v1 ||\
-						      (s1)->v2 == (s2)->v2)
-GtsIntersect  gts_segments_are_intersecting          (GtsSegment * s1,
-						      GtsSegment * s2);
-GtsSegment *  gts_segment_is_duplicate               (GtsSegment * s);
-GtsVertex *   gts_segment_midvertex                  (GtsSegment * s,
-						      GtsVertexClass * klass);
-GSList *      gts_segments_from_vertices             (GSList * vertices);
-gboolean      gts_segment_is_ok                      (GtsSegment * s);
-
-/* Edges: edge.c */
-
-#define GTS_IS_EDGE(obj)  (gts_object_is_from_class (obj,\
-						     gts_edge_class ()))
-#define GTS_EDGE(obj)            GTS_OBJECT_CAST (obj,\
-						  GtsEdge,\
-						  gts_edge_class ())
-#define GTS_EDGE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-							GtsEdgeClass,\
-							gts_edge_class ())
-
-struct _GtsEdge {
-  GtsSegment segment;
-
-  GSList * triangles;
-};
-
-struct _GtsEdgeClass {
-  GtsSegmentClass parent_class;
-};
-
-GTS_C_VAR 
-gboolean      gts_allow_floating_edges;
-
-GtsEdgeClass * gts_edge_class                     (void);
-GtsEdge *     gts_edge_new                        (GtsEdgeClass * klass,
-						   GtsVertex * v1,
-						   GtsVertex * v2);
-/**
- * gts_edge_is_unattached:
- * @s: a #GtsEdge.
- *
- * Evaluates to %TRUE if no triangles uses @s as an edge, %FALSE otherwise.
- */
-#define       gts_edge_is_unattached(s) ((s)->triangles == NULL ? TRUE : FALSE)
-GtsFace *     gts_edge_has_parent_surface         (GtsEdge * e, 
-						   GtsSurface * surface);
-GtsFace *     gts_edge_has_any_parent_surface     (GtsEdge * e);
-GtsFace *     gts_edge_is_boundary                (GtsEdge * e, 
-						   GtsSurface * surface);
-void          gts_edge_replace                    (GtsEdge * e,
-						   GtsEdge * with);
-GSList *      gts_edges_from_vertices             (GSList * vertices,
-						   GtsSurface * parent);
-guint         gts_edge_face_number                (GtsEdge * e,
-						   GtsSurface * s);
-gboolean      gts_edge_collapse_is_valid          (GtsEdge * e);
-gboolean      gts_edge_collapse_creates_fold      (GtsEdge * e, 
-						   GtsVertex * v,
-						   gdouble max);
-GtsEdge *     gts_edge_is_duplicate               (GtsEdge * e);
-GList *       gts_edges_merge                     (GList * edges);
-gboolean      gts_edge_belongs_to_tetrahedron     (GtsEdge * e);
-guint         gts_edge_is_contact                 (GtsEdge * e);
-void          gts_edge_swap                       (GtsEdge * e, 
-						   GtsSurface * s);
-gboolean      gts_edge_manifold_faces             (GtsEdge * e, 
-						   GtsSurface * s,
-						   GtsFace ** f1, 
-						   GtsFace ** f2);
-
-/* Triangles: triangle.c */
-
-#define GTS_IS_TRIANGLE(obj) (gts_object_is_from_class (obj,\
-							gts_triangle_class ()))
-#define GTS_TRIANGLE(obj)         GTS_OBJECT_CAST (obj,\
-						   GtsTriangle,\
-						   gts_triangle_class ())
-#define GTS_TRIANGLE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\
-							 GtsTriangleClass,\
-							 gts_triangle_class ())
-
-struct _GtsTriangle {
-  GtsObject object;
-
-  GtsEdge * e1;
-  GtsEdge * e2;
-  GtsEdge * e3;
-};
-
-struct _GtsTriangleClass {
-  GtsObjectClass parent_class;
-};
-
-GtsTriangleClass * gts_triangle_class        (void);
-void        gts_triangle_set                 (GtsTriangle * triangle, 
-					      GtsEdge * e1, 
-					      GtsEdge * e2,
-					      GtsEdge * e3);
-GtsTriangle * gts_triangle_new               (GtsTriangleClass * klass, 
-					      GtsEdge * e1, 
-					      GtsEdge * e2,
-					      GtsEdge * e3);
-#define     gts_triangle_vertex(t) (GTS_SEGMENT (GTS_TRIANGLE (t)->e1)->v1 ==\
-                                    GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1 || \
-                                    GTS_SEGMENT (GTS_TRIANGLE (t)->e1)->v2 ==\
-                                    GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1 ? \
-                                    GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v2 :\
-                                    GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1)
-GtsVertex *   gts_triangle_vertex_opposite  (GtsTriangle * t, 
-					     GtsEdge * e);
-GtsEdge *     gts_triangle_edge_opposite    (GtsTriangle * t, 
-					     GtsVertex * v);
-gdouble       gts_triangles_angle           (GtsTriangle * t1,
-					     GtsTriangle * t2);
-gboolean      gts_triangles_are_compatible  (GtsTriangle * t1, 
-					     GtsTriangle * t2,
-					     GtsEdge * e);
-gdouble       gts_triangle_area             (GtsTriangle * t);
-gdouble       gts_triangle_perimeter        (GtsTriangle * t);
-gdouble       gts_triangle_quality          (GtsTriangle * t);
-void          gts_triangle_normal           (GtsTriangle * t, 
-					     gdouble * x, 
-					     gdouble * y, 
-					     gdouble * z);
-gdouble       gts_triangle_orientation      (GtsTriangle * t);
-void          gts_triangle_revert           (GtsTriangle * t);
-GSList *      gts_triangles_from_edges      (GSList * edges);
-void          gts_triangle_vertices_edges   (GtsTriangle * t, 
-					     GtsEdge * e,
-					     GtsVertex ** v1, 
-					     GtsVertex ** v2, 
-					     GtsVertex ** v3,
-					     GtsEdge ** e1,
-					     GtsEdge ** e2,
-					     GtsEdge ** e3);
-GtsTriangle * gts_triangle_enclosing        (GtsTriangleClass * klass,
-					     GSList * points, 
-					     gdouble scale);
-guint         gts_triangle_neighbor_number  (GtsTriangle * t);
-GSList *      gts_triangle_neighbors        (GtsTriangle * t);
-GtsEdge *     gts_triangles_common_edge     (GtsTriangle * t1,
-					     GtsTriangle * t2);
-GtsTriangle * gts_triangle_is_duplicate     (GtsTriangle * t);
-GtsTriangle * gts_triangle_use_edges        (GtsEdge * e1,
-					     GtsEdge * e2,
-					     GtsEdge * e3);
-gboolean      gts_triangle_is_ok            (GtsTriangle * t);
-void          gts_triangle_vertices         (GtsTriangle * t,
-					     GtsVertex ** v1,
-					     GtsVertex ** v2,
-					     GtsVertex ** v3);
-GtsPoint *    gts_triangle_circumcircle_center (GtsTriangle * t,
-						GtsPointClass * point_class);
-gboolean      gts_triangles_are_folded      (GSList * triangles,
-					     GtsVertex * A, GtsVertex * B,
-					     gdouble max);
-GtsObject *   gts_triangle_is_stabbed       (GtsTriangle * t,
-					     GtsPoint * p,
-					     gdouble * orientation);
-void          gts_triangle_interpolate_height (GtsTriangle * t, 
-					       GtsPoint * p);
-
-/* Faces: face.c */
-
-#define GTS_IS_FACE(obj) (gts_object_is_from_class (obj,\
-						    gts_face_class ()))
-#define GTS_FACE(obj)          GTS_OBJECT_CAST (obj,\
-						GtsFace,\
-						gts_face_class ())
-#define GTS_FACE_CLASS(klass)  GTS_OBJECT_CLASS_CAST (klass,\
-						      GtsFaceClass,\
-						      gts_face_class ())
-
-struct _GtsFace {
-  GtsTriangle triangle;
-
-  GSList * surfaces;
-};
-
-struct _GtsFaceClass {
-  GtsTriangleClass parent_class;
-};
-
-GTS_C_VAR 
-gboolean      gts_allow_floating_faces;
-
-GtsFaceClass * gts_face_class                       (void);
-GtsFace *     gts_face_new                          (GtsFaceClass * klass,
-						     GtsEdge * e1,
-						     GtsEdge * e2,
-						     GtsEdge * e3);
-gboolean      gts_face_has_parent_surface           (GtsFace * f,
-						     GtsSurface * s);
-GSList *      gts_faces_from_edges                  (GSList * edges, 
-						     GtsSurface * s);
-guint         gts_face_neighbor_number              (GtsFace * f, 
-						     GtsSurface * s);
-GSList *      gts_face_neighbors                    (GtsFace * f, 
-						     GtsSurface * s);
-void          gts_face_foreach_neighbor             (GtsFace * f, 
-						     GtsSurface * s, 
-						     GtsFunc func,
-						     gpointer data);
-gboolean      gts_face_is_compatible                (GtsFace * f, 
-						     GtsSurface * s);
-
-/* Matrices: matrix.c */
-
-#define       gts_vector_cross(C,A,B) ((C)[0] = (A)[1]*(B)[2] - (A)[2]*(B)[1],\
-			               (C)[1] = (A)[2]*(B)[0] - (A)[0]*(B)[2],\
-			               (C)[2] = (A)[0]*(B)[1] - (A)[1]*(B)[0])
-
-#define       gts_vector_init(v, p1, p2)   ((v)[0] = (p2)->x - (p1)->x,\
-					    (v)[1] = (p2)->y - (p1)->y,\
-					    (v)[2] = (p2)->z - (p1)->z)
-#define       gts_vector_scalar(v1, v2)    ((v1)[0]*(v2)[0] +\
-					    (v1)[1]*(v2)[1] +\
-					    (v1)[2]*(v2)[2])
-#define       gts_vector_norm(v)   (sqrt ((v)[0]*(v)[0] +\
-                                          (v)[1]*(v)[1] +\
-                                          (v)[2]*(v)[2]))
-#define       gts_vector_normalize(v) {\
-  gdouble __gts_n = gts_vector_norm (v);\
-  if (__gts_n > 0.) {\
-    (v)[0] /= __gts_n;\
-    (v)[1] /= __gts_n;\
-    (v)[2] /= __gts_n;\
-  }\
-}
-GtsMatrix * gts_matrix_new (gdouble a00, gdouble a01, gdouble a02, gdouble a03,
-			    gdouble a10, gdouble a11, gdouble a12, gdouble a13,
-			    gdouble a20, gdouble a21, gdouble a22, gdouble a23,
-			    gdouble a30, gdouble a31, gdouble a32, gdouble a33);
-void gts_matrix_assign (GtsMatrix * m,
-			gdouble a00, gdouble a01, gdouble a02, gdouble a03,
-			gdouble a10, gdouble a11, gdouble a12, gdouble a13,
-			gdouble a20, gdouble a21, gdouble a22, gdouble a23,
-			gdouble a30, gdouble a31, gdouble a32, gdouble a33);
-GtsMatrix *   gts_matrix_projection                  (GtsTriangle * t);
-GtsMatrix *   gts_matrix_transpose                   (GtsMatrix * m);
-gdouble       gts_matrix_determinant                 (GtsMatrix * m);
-GtsMatrix *   gts_matrix_inverse                     (GtsMatrix * m);
-GtsMatrix *   gts_matrix3_inverse                    (GtsMatrix * m);
-void          gts_matrix_print                       (GtsMatrix * m, 
-						      FILE * fptr);
-guint         gts_matrix_compatible_row              (GtsMatrix * A,
-						      GtsVector b,
-						      guint n,
-						      GtsVector A1,
-						      gdouble b1);
-guint         gts_matrix_quadratic_optimization      (GtsMatrix * A,
-						      GtsVector b,
-						      guint n,
-						      GtsMatrix * H,
-						      GtsVector c);
-GtsMatrix *   gts_matrix_product                     (GtsMatrix * m1, 
-						      GtsMatrix * m2);
-GtsMatrix *   gts_matrix_zero                        (GtsMatrix * m);
-GtsMatrix *   gts_matrix_identity                    (GtsMatrix * m);
-GtsMatrix *   gts_matrix_scale                       (GtsMatrix * m, 
-						      GtsVector s);
-GtsMatrix *   gts_matrix_translate                   (GtsMatrix * m, 
-						      GtsVector t);
-GtsMatrix *   gts_matrix_rotate                      (GtsMatrix * m,
-						      GtsVector r,
-						      gdouble angle);
-void          gts_matrix_destroy                     (GtsMatrix * m);
-void          gts_vector_print                       (GtsVector v,
-						      FILE * fptr);
-void          gts_vector4_print                      (GtsVector4 v, 
-						      FILE * fptr);
-
-/* Kdtrees: kdtree.c */
-
-#define       gts_kdtree_destroy(tree)               g_node_destroy(tree)
-
-GNode *       gts_kdtree_new                         (GPtrArray * points,
-						      int (*compare)
-						      (const void *, 
-						       const void *));
-GSList *      gts_kdtree_range                       (GNode * tree,
-						      GtsBBox * bbox,
-						      int (*compare)
-						      (const void *, 
-						      const void *));
-
-/* Bboxtrees: bbtree.c */
-
-/**
- * GtsBBTreeTraverseFunc:
- * @bb1: a #GtsBBox.
- * @bb2: another #GtsBBox.
- * @data: user data passed to the function.
- *
- * User function called for each pair of overlapping bounding
- * boxes. See gts_bb_tree_traverse_overlapping().
- */
-typedef void   (*GtsBBTreeTraverseFunc)          (GtsBBox * bb1,
-						  GtsBBox * bb2,
-						  gpointer data);
-/**
- * GtsBBoxDistFunc:
- * @p: a #GtsPoint.
- * @bounded: an object bounded by a #GtsBBox.
- *
- * User function returning the (minimum) distance between the object
- * defined by @bounded and point @p.
- *
- * Returns: the distance between @p and @bounded.
- */
-typedef gdouble (*GtsBBoxDistFunc)               (GtsPoint * p,
-						  gpointer bounded);
-/**
- * GtsBBoxClosestFunc:
- * @p: a #GtsPoint.
- * @bounded: an object bounded by a #GtsBBox.
- * 
- * User function returning a #GtsPoint belonging to the object defined
- * by @bounded and closest to @p.
- *
- * Returns: a #GtsPoint.
- */
-typedef GtsPoint * (*GtsBBoxClosestFunc)         (GtsPoint * p,
-						  gpointer bounded);
-
-/**
- * GTS_IS_BBOX:
- * @obj: a #GtsObject.
- *
- * Evaluates to %TRUE if @obj is a #GtsBBox, %FALSE otherwise.
- */
-#define GTS_IS_BBOX(obj)  (gts_object_is_from_class (obj,\
-						     gts_bbox_class ()))
-/**
- * GTS_BBOX:
- * @obj: a #GtsObject.
- *
- * Casts @obj to #GtsBBox.
- */
-#define GTS_BBOX(obj)         GTS_OBJECT_CAST (obj,\
-					       GtsBBox,\
-					       gts_bbox_class ())
-/**
- * GTS_BBOX_CLASS:
- * @klass: a descendant of #GtsBBoxClass.
- *
- * Casts @klass to #GtsBBoxClass.
- */
-#define GTS_BBOX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\
-						     GtsBBoxClass,\
-						     gts_bbox_class ())
-
-struct _GtsBBox {
-  GtsObject object;
-  gpointer bounded;
-  gdouble x1, y1, z1;
-  gdouble x2, y2, z2;
-};
-
-struct _GtsBBoxClass {
-  GtsObjectClass parent_class;
-};
-
-GtsBBoxClass * gts_bbox_class                (void);
-GtsBBox *  gts_bbox_new                      (GtsBBoxClass * klass,
-					      gpointer bounded,
-					      gdouble x1, 
-					      gdouble y1, 
-					      gdouble z1,
-					      gdouble x2, 
-					      gdouble y2, 
-					      gdouble z2);
-void       gts_bbox_set                      (GtsBBox * bbox,
-					      gpointer bounded,
-					      gdouble x1, 
-					      gdouble y1, 
-					      gdouble z1,
-					      gdouble x2, 
-					      gdouble y2, 
-					      gdouble z2);
-GtsBBox *  gts_bbox_segment                  (GtsBBoxClass * klass,
-					      GtsSegment * s);
-GtsBBox *  gts_bbox_triangle                 (GtsBBoxClass * klass,
-					      GtsTriangle * t);
-GtsBBox *  gts_bbox_surface                  (GtsBBoxClass * klass, 
-					      GtsSurface * surface);
-GtsBBox *  gts_bbox_bboxes                   (GtsBBoxClass * klass,
-					      GSList * bboxes);
-GtsBBox *  gts_bbox_points                   (GtsBBoxClass * klass,
-					      GSList * points);
-/**
- * gts_bbox_point_is_inside:
- * @bbox: a #GtsBBox.
- * @p: a #GtsPoint.
- *
- * Evaluates to %TRUE if @p is inside (or on the boundary) of @bbox, %FALSE otherwise.
- */
-#define    gts_bbox_point_is_inside(bbox, p) ((p)->x >= (bbox)->x1 &&\
-					     (p)->y >= (bbox)->y1 &&\
-                                             (p)->z >= (bbox)->z1 &&\
-                                             (p)->x <= (bbox)->x2 &&\
-					     (p)->y <= (bbox)->y2 &&\
-                                             (p)->z <= (bbox)->z2)
-gboolean   gts_bboxes_are_overlapping        (GtsBBox * bb1, 
-					      GtsBBox * bb2);
-void       gts_bbox_draw                     (GtsBBox * bb, 
-					      FILE * fptr);
-gdouble    gts_bbox_diagonal2                (GtsBBox * bb);
-void       gts_bbox_point_distance2          (GtsBBox * bb, 
-					      GtsPoint * p,
-					      gdouble * min,
-					      gdouble * max);
-gboolean   gts_bbox_is_stabbed               (GtsBBox * bb, 
-					      GtsPoint * p);
-gboolean   gts_bbox_overlaps_triangle        (GtsBBox * bb,
-					      GtsTriangle * t);
-gboolean   gts_bbox_overlaps_segment         (GtsBBox * bb, 
-					      GtsSegment * s);
-
-GNode *    gts_bb_tree_new                   (GSList * bboxes);
-GNode *    gts_bb_tree_surface               (GtsSurface * s);
-GSList *   gts_bb_tree_stabbed               (GNode * tree, 
-					      GtsPoint * p);
-GSList *   gts_bb_tree_overlap               (GNode * tree, 
-					      GtsBBox * bbox);
-gboolean   gts_bb_tree_is_overlapping        (GNode * tree, 
-					      GtsBBox * bbox);
-void       gts_bb_tree_traverse_overlapping  (GNode * tree1, 
-					      GNode * tree2,
-					      GtsBBTreeTraverseFunc func,
-					      gpointer data);
-void       gts_bb_tree_draw                  (GNode * tree, 
-					      guint depth, 
-					      FILE * fptr);
-GSList *   gts_bb_tree_point_closest_bboxes  (GNode * tree, 
-					      GtsPoint * p);
-gdouble    gts_bb_tree_point_distance        (GNode * tree, 
-					      GtsPoint * p,
-					      GtsBBoxDistFunc distance,
-					      GtsBBox ** bbox);
-GtsPoint * gts_bb_tree_point_closest         (GNode * tree, 
-					      GtsPoint * p,
-					      GtsBBoxClosestFunc closest,
-					      gdouble * distance);
-void       gts_bb_tree_segment_distance      (GNode * tree, 
-					      GtsSegment * s,
-					      GtsBBoxDistFunc distance,
-					      gdouble delta,
-					      GtsRange * range);
-void       gts_bb_tree_triangle_distance     (GNode * tree, 
-					      GtsTriangle * t,
-					      GtsBBoxDistFunc distance,
-					      gdouble delta,
-					      GtsRange * range);
-void       gts_bb_tree_surface_distance      (GNode * tree,
-					      GtsSurface * s,
-					      GtsBBoxDistFunc distance,
-					      gdouble delta,
-					      GtsRange * range);
-void       gts_bb_tree_surface_boundary_distance 
-                                             (GNode * tree,
-					      GtsSurface * s,
-					      GtsBBoxDistFunc distance,
-					      gdouble delta,
-					      GtsRange * range);
-void       gts_bb_tree_destroy               (GNode * tree, 
-					      gboolean free_leaves);
-
-/* Surfaces: surface.c */
-
-typedef struct _GtsSurfaceStats        GtsSurfaceStats;
-typedef struct _GtsSurfaceQualityStats GtsSurfaceQualityStats;
-typedef GtsVertex * (*GtsRefineFunc)   (GtsEdge * e,
-					GtsVertexClass * klass,
-					gpointer data);
-typedef GtsVertex * (*GtsCoarsenFunc)  (GtsEdge * e,
-					GtsVertexClass * klass,
-					gpointer data);
-typedef gboolean    (*GtsStopFunc)     (gdouble cost,
-					guint nedge,
-					gpointer data);
-
-struct _GtsSurfaceStats {
-  guint n_faces;
-  guint n_incompatible_faces;
-  guint n_duplicate_faces;
-  guint n_duplicate_edges;
-  guint n_boundary_edges;
-  guint n_non_manifold_edges;
-  GtsRange edges_per_vertex, faces_per_edge;
-  GtsSurface * parent;
-};
-
-struct _GtsSurfaceQualityStats {
-  GtsRange face_quality;
-  GtsRange face_area;
-  GtsRange edge_length;
-  GtsRange edge_angle;
-  GtsSurface * parent;
-};
-
-struct _GtsSurface {
-  GtsObject object;
-
-#ifdef USE_SURFACE_BTREE
-  GTree * faces;
-#else /* not USE_SURFACE_BTREE */
-  GHashTable * faces;
-#endif /* not USE_SURFACE_BTREE */
-  GtsFaceClass * face_class;
-  GtsEdgeClass * edge_class;
-  GtsVertexClass * vertex_class;
-  gboolean keep_faces;
-};
-
-struct _GtsSurfaceClass {
-  GtsObjectClass parent_class;
-
-  void (* add_face)    (GtsSurface *, GtsFace *);
-  void (* remove_face) (GtsSurface *, GtsFace *);
-};
-
-#define GTS_IS_SURFACE(obj) (gts_object_is_from_class (obj,\
-						       gts_surface_class ()))
-#define GTS_SURFACE(obj)         GTS_OBJECT_CAST (obj,\
-						  GtsSurface,\
-						  gts_surface_class ())
-#define GTS_SURFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\
-							GtsSurfaceClass,\
-							gts_surface_class ())
-
-GtsSurfaceClass * gts_surface_class        (void);
-GtsSurface * gts_surface_new               (GtsSurfaceClass * klass,
-					    GtsFaceClass * face_class,
-					    GtsEdgeClass * edge_class,
-					    GtsVertexClass * vertex_class);
-void         gts_surface_add_face          (GtsSurface * s, 
-					    GtsFace * f);
-void         gts_surface_remove_face       (GtsSurface * s, 
-					    GtsFace * f);
-guint        gts_surface_read              (GtsSurface * surface,
-					    GtsFile * f);
-gdouble      gts_surface_area              (GtsSurface * s);
-void         gts_surface_stats             (GtsSurface * s, 
-					    GtsSurfaceStats * stats);
-void         gts_surface_quality_stats     (GtsSurface * s, 
-					    GtsSurfaceQualityStats * stats);
-void         gts_surface_print_stats       (GtsSurface * s, 
-					    FILE * fptr);
-void         gts_surface_write             (GtsSurface * s, 
-					    FILE * fptr);
-void         gts_surface_write_oogl        (GtsSurface * s, 
-					    FILE * fptr);
-void         gts_surface_write_vtk         (GtsSurface * s, 
-					    FILE * fptr);
-void         gts_surface_write_oogl_boundary (GtsSurface * s, 
-					      FILE * fptr);
-void         gts_surface_foreach_vertex    (GtsSurface * s, 
-					    GtsFunc func, 
-					    gpointer data);
-void         gts_surface_foreach_edge      (GtsSurface * s, 
-					    GtsFunc func, 
-					    gpointer data);
-void         gts_surface_foreach_face      (GtsSurface * s,
-					    GtsFunc func, 
-					    gpointer data);
-guint        gts_surface_foreach_face_remove (GtsSurface * s,
-					      GtsFunc func, 
-					      gpointer data);
-typedef struct _GtsSurfaceTraverse GtsSurfaceTraverse;
-GtsSurfaceTraverse * gts_surface_traverse_new (GtsSurface * s,
-					       GtsFace * f);
-GtsFace *    gts_surface_traverse_next     (GtsSurfaceTraverse * t,
-					    guint * level);
-void         gts_surface_traverse_destroy  (GtsSurfaceTraverse * t);
-void         gts_surface_refine            (GtsSurface * surface,
-					    GtsKeyFunc cost_func,
-					    gpointer cost_data,
-					    GtsRefineFunc refine_func,
-					    gpointer refine_data,
-					    GtsStopFunc stop_func,
-					    gpointer stop_data);
-gboolean     gts_edge_collapse_is_valid    (GtsEdge * e);
-void         gts_surface_coarsen           (GtsSurface * surface,
-					    GtsKeyFunc cost_func,
-					    gpointer cost_data,
-					    GtsCoarsenFunc coarsen_func,
-					    gpointer coarsen_data,
-					    GtsStopFunc stop_func,
-					    gpointer stop_data,
-					    gdouble minangle);
-gboolean     gts_coarsen_stop_number       (gdouble cost, 
-					    guint nedge, 
-					    guint * min_number);
-gboolean     gts_coarsen_stop_cost         (gdouble cost, 
-					    guint nedge, 
-					    gdouble * max_cost);
-void         gts_surface_tessellate        (GtsSurface * s,
-					    GtsRefineFunc refine_func,
-					    gpointer refine_data);
-GtsSurface * gts_surface_generate_sphere   (GtsSurface * s,
-					    guint geodesation_order);
-GtsSurface * gts_surface_copy              (GtsSurface * s1,
-					    GtsSurface * s2);
-void         gts_surface_merge             (GtsSurface * s, 
-					    GtsSurface * with);
-gboolean     gts_surface_is_manifold       (GtsSurface * s);
-gboolean     gts_surface_is_closed         (GtsSurface * s);
-gboolean     gts_surface_is_orientable     (GtsSurface * s);
-gdouble      gts_surface_volume            (GtsSurface * s);
-gdouble      gts_surface_center_of_mass    (GtsSurface * s,
-					    GtsVector cm);
-gdouble      gts_surface_center_of_area    (GtsSurface * s,
-					    GtsVector cm);
-guint        gts_surface_vertex_number     (GtsSurface * s);
-guint        gts_surface_edge_number       (GtsSurface * s);
-guint        gts_surface_face_number       (GtsSurface * s);
-void         gts_surface_distance          (GtsSurface * s1, 
-					    GtsSurface * s2, 
-					    gdouble delta,
-					    GtsRange * face_range, 
-					    GtsRange * boundary_range);
-GSList *     gts_surface_boundary          (GtsSurface * surface);
-GSList *     gts_surface_split             (GtsSurface * s);
-
-/* Discrete differential operators: curvature.c */
-
-gboolean gts_vertex_mean_curvature_normal  (GtsVertex * v, 
-					    GtsSurface * s, 
-					    GtsVector Kh);
-gboolean gts_vertex_gaussian_curvature     (GtsVertex * v, 
-					    GtsSurface * s, 
-					    gdouble * Kg);
-void     gts_vertex_principal_curvatures   (gdouble Kh, 
-					    gdouble Kg, 
-					    gdouble * K1, 
-					    gdouble * K2);
-void     gts_vertex_principal_directions   (GtsVertex * v, 
-					    GtsSurface * s, 
-					    GtsVector Kh,
-                                            gdouble Kg,
-					    GtsVector e1, 
-					    GtsVector e2);
-
-/* Volume optimization: vopt.c */
-typedef struct _GtsVolumeOptimizedParams   GtsVolumeOptimizedParams;
-
-struct _GtsVolumeOptimizedParams {
-  gdouble volume_weight;
-  gdouble boundary_weight;
-  gdouble shape_weight;
-};
-
-GtsVertex *  gts_volume_optimized_vertex   (GtsEdge * edge,
-					    GtsVertexClass * klass,
-					    GtsVolumeOptimizedParams * params);
-gdouble      gts_volume_optimized_cost     (GtsEdge * e,
-					    GtsVolumeOptimizedParams * params);
-
-/* bool operations: boolean.c */
-
-GSList *     gts_surface_intersection      (GtsSurface * s1,
-					    GtsSurface * s2,
-					    GNode * faces_tree1,
-					    GNode * faces_tree2);
-
-typedef struct _GtsSurfaceInter         GtsSurfaceInter;
-typedef struct _GtsSurfaceInterClass    GtsSurfaceInterClass;
-/**
- * GtsBooleanOperation:
- * @GTS_1_OUT_2: identifies the part of the first surface which lies
- * outside the second surface.
- * @GTS_1_IN_2: identifies the part of the first surface which lies
- * inside the second surface.
- * @GTS_2_OUT_1: identifies the part of the second surface which lies
- * outside the first surface.
- * @GTS_2_IN_1: identifies the part of the second surface which lies
- * inside the first surface.
- */
-typedef enum { GTS_1_OUT_2, 
-	       GTS_1_IN_2, 
-	       GTS_2_OUT_1, 
-	       GTS_2_IN_1 }             GtsBooleanOperation;
-
-/**
- * GTS_IS_SURFACE_INTER:
- * @obj: a #GtsObject.
- *
- * Evaluates to %TRUE if @obj is a #GtsSurfaceInter, %FALSE otherwise.
- */
-#define GTS_IS_SURFACE_INTER(obj) (gts_object_is_from_class (obj,\
-					      gts_surface_inter_class ()))
-/**
- * GTS_SURFACE_INTER:
- * @obj: a descendant of #GtsSurfaceInter.
- *
- * Casts @obj to #GtsSurfaceInter.
- */
-#define GTS_SURFACE_INTER(obj)         GTS_OBJECT_CAST (obj,\
-						  GtsSurfaceInter,\
-						  gts_surface_inter_class ())
-/**
- * GTS_SURFACE_INTER_CLASS:
- * @klass: a descendant of #GtsSurfaceInterClass.
- *
- * Casts @klass to #GtsSurfaceInterClass.
- */
-#define GTS_SURFACE_INTER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\
-						 GtsSurfaceInterClass,\
-						 gts_surface_inter_class ())
-
-struct _GtsSurfaceInter {
-  GtsObject object;
-
-  GtsSurface * s1;
-  GtsSurface * s2;
-  GSList * edges;
-};
-
-struct _GtsSurfaceInterClass {
-  GtsObjectClass parent_class;
-};
-
-GtsSurfaceInterClass *
-gts_surface_inter_class          (void);
-GtsSurfaceInter *
-gts_surface_inter_new            (GtsSurfaceInterClass * klass,
-				  GtsSurface * s1,
-				  GtsSurface * s2,
-				  GNode * faces_tree1,
-				  GNode * faces_tree2,
-				  gboolean is_open1,
-				  gboolean is_open2);
-gboolean 
-gts_surface_inter_check          (GtsSurfaceInter * si,
-				  gboolean * closed);
-void 
-gts_surface_inter_boolean        (GtsSurfaceInter * si, 
-				  GtsSurface * surface,
-				  GtsBooleanOperation op);
-gboolean gts_surface_foreach_intersecting_face (GtsSurface * s,
-					    GtsBBTreeTraverseFunc func,
-					    gpointer data);
-GtsSurface * 
-gts_surface_is_self_intersecting (GtsSurface * s);
-
-/* Binary Heap: heap.c */
-
-typedef struct _GtsHeap         GtsHeap;
-
-GtsHeap *    gts_heap_new          (GCompareFunc compare_func);
-void         gts_heap_insert       (GtsHeap * heap, gpointer p);
-gpointer     gts_heap_remove_top   (GtsHeap * heap);
-gpointer     gts_heap_top          (GtsHeap * heap);
-void         gts_heap_thaw         (GtsHeap * heap);
-void         gts_heap_foreach      (GtsHeap * heap, 
-				    GFunc func,
-				    gpointer user_data);
-void         gts_heap_freeze       (GtsHeap * heap);
-guint        gts_heap_size         (GtsHeap * heap);
-void         gts_heap_destroy      (GtsHeap * heap);
-
-/* Extended Binary Heap: eheap.c */
-
-typedef struct _GtsEHeap         GtsEHeap;
-typedef struct _GtsEHeapPair     GtsEHeapPair;
-
-struct _GtsEHeap {
-  GPtrArray * elts;
-  GtsKeyFunc func;
-  gpointer data;
-  gboolean frozen, randomized;
-};
-
-/**
- * _GtsEHeapPair:
- * @data: Points to the item stored in the heap.
- * @key: Value of the key for this item.
- * @pos: Private field.
- */
-struct _GtsEHeapPair {
-  gpointer data;
-  gdouble key;
-  guint pos;
-};
-
-GtsEHeap *     gts_eheap_new          (GtsKeyFunc key_func,
-				       gpointer data);
-GtsEHeapPair * gts_eheap_insert       (GtsEHeap * heap, 
-				       gpointer p);
-GtsEHeapPair * gts_eheap_insert_with_key (GtsEHeap * heap, 
-					  gpointer p, 
-					  gdouble key);
-gpointer       gts_eheap_remove_top   (GtsEHeap * heap,
-				       gdouble * key);
-gpointer       gts_eheap_top          (GtsEHeap * heap, 
-				       gdouble * key);
-void           gts_eheap_thaw         (GtsEHeap * heap);
-void           gts_eheap_foreach      (GtsEHeap * heap, 
-				       GFunc func,
-				       gpointer data);
-gpointer       gts_eheap_remove       (GtsEHeap * heap, 
-				       GtsEHeapPair * p);
-void           gts_eheap_decrease_key (GtsEHeap * heap,
-				       GtsEHeapPair * p,
-				       gdouble new_key);
-void           gts_eheap_freeze       (GtsEHeap * heap);
-guint          gts_eheap_size         (GtsEHeap * heap);
-void           gts_eheap_update       (GtsEHeap * heap);
-gdouble        gts_eheap_key          (GtsEHeap * heap,
-				       gpointer p);
-void           gts_eheap_randomized   (GtsEHeap * heap, 
-				       gboolean randomized);
-void           gts_eheap_destroy      (GtsEHeap * heap);
-
-/* FIFO queues: fifo.c */
-
-typedef struct _GtsFifo GtsFifo;
-
-GtsFifo *      gts_fifo_new           (void);
-void           gts_fifo_write         (GtsFifo * fifo, 
-				       FILE * fp);
-void           gts_fifo_push          (GtsFifo * fifo, 
-				       gpointer data);
-gpointer       gts_fifo_pop           (GtsFifo * fifo);
-gpointer       gts_fifo_top           (GtsFifo * fifo);
-guint          gts_fifo_size          (GtsFifo * fifo);
-gboolean       gts_fifo_is_empty      (GtsFifo * fifo);
-void           gts_fifo_foreach       (GtsFifo * fifo, 
-				       GtsFunc func, 
-				       gpointer data);
-void           gts_fifo_reverse       (GtsFifo * fifo);
-void           gts_fifo_destroy       (GtsFifo * fifo);
-
-/* Progressive surfaces */
-
-/* split.c */
-
-typedef struct _GtsSplit      GtsSplit;
-typedef struct _GtsSplitClass GtsSplitClass;
-typedef struct _GtsSplitCFace GtsSplitCFace;
-
-struct _GtsSplit {
-  GtsObject object;
-
-  GtsVertex * v;
-  GtsObject * v1;
-  GtsObject * v2;
-  GtsSplitCFace * cfaces;
-  guint ncf;
-};
-
-struct _GtsSplitClass {
-  GtsObjectClass parent_class;
-};
-
-#define GTS_IS_SPLIT(obj)    (gts_object_is_from_class (obj,\
-							gts_split_class ()))
-#define GTS_SPLIT(obj)              GTS_OBJECT_CAST (obj,\
-						     GtsSplit,\
-						     gts_split_class ())
-#define GTS_SPLIT_CLASS(klass)      GTS_OBJECT_CLASS_CAST (klass,\
-						     GtsSplitClass,\
-						     gts_split_class ())
-#define GTS_SPLIT_V1(vs)            (GTS_IS_SPLIT ((vs)->v1) ?\
-				     GTS_SPLIT ((vs)->v1)->v :\
-				     GTS_VERTEX ((vs)->v1))
-#define GTS_SPLIT_V2(vs)            (GTS_IS_SPLIT ((vs)->v2) ?\
-				     GTS_SPLIT ((vs)->v2)->v :\
-				     GTS_VERTEX ((vs)->v2))
-
-GtsSplitClass *  gts_split_class          (void);
-GtsSplit *       gts_split_new            (GtsSplitClass * klass,
-					   GtsVertex * v,
-					   GtsObject * o1,
-					   GtsObject * o2);
-void             gts_split_collapse       (GtsSplit * vs,
-					   GtsEdgeClass * klass,
-					   GtsEHeap * heap);
-void             gts_split_expand         (GtsSplit * vs, 
-					   GtsSurface * s,
-					   GtsEdgeClass * klass);
-typedef gboolean (*GtsSplitTraverseFunc)  (GtsSplit * vs,
-					   gpointer data);
-void             gts_split_traverse       (GtsSplit * root,
-					   GTraverseType        order,
-					   gint                 depth,
-					   GtsSplitTraverseFunc func,
-					   gpointer             data);
-guint            gts_split_height         (GtsSplit * root);
-
-/* psurface.c */
-
-typedef struct _GtsPSurface         GtsPSurface;
-typedef struct _GtsPSurfaceClass    GtsPSurfaceClass;
-
-struct _GtsPSurface {
-  GtsObject object;
-
-  GtsSurface * s;
-  GPtrArray * split;
-  GtsSplitClass * split_class;
-  guint pos, min;
-
-  GPtrArray * vertices;
-  GPtrArray * faces;
-};
-
-struct _GtsPSurfaceClass {
-  GtsObjectClass parent_class;
-};
-
-#define GTS_IS_PSURFACE(obj) (gts_object_is_from_class (obj,\
-							gts_psurface_class ()))
-#define GTS_PSURFACE(obj)           GTS_OBJECT_CAST (obj,\
-						     GtsPSurface,\
-						     gts_psurface_class ())
-#define GTS_PSURFACE_CLASS(klass)     GTS_OBJECT_CLASS_CAST (klass,\
-						     GtsPSurfaceClass,\
-						     gts_psurface_class ())
-#define GTS_PSURFACE_IS_CLOSED(ps)  (!(ps)->vertices)
-
-GtsPSurfaceClass * gts_psurface_class         (void);
-GtsPSurface * gts_psurface_new                (GtsPSurfaceClass * klass,
-					       GtsSurface * surface,
-					       GtsSplitClass * split_class,
-					       GtsKeyFunc cost_func,
-					       gpointer cost_data,
-					       GtsCoarsenFunc coarsen_func,
-					       gpointer coarsen_data,
-					       GtsStopFunc stop_func,
-					       gpointer stop_data,
-					       gdouble minangle);
-GtsSplit *    gts_psurface_add_vertex         (GtsPSurface * ps);
-GtsSplit *    gts_psurface_remove_vertex      (GtsPSurface * ps);
-guint         gts_psurface_max_vertex_number  (GtsPSurface * ps);
-guint         gts_psurface_min_vertex_number  (GtsPSurface * ps);
-void          gts_psurface_set_vertex_number  (GtsPSurface * ps, 
-					       guint n);
-guint         gts_psurface_get_vertex_number  (GtsPSurface * ps);
-void          gts_psurface_write              (GtsPSurface * ps,
-					       FILE * fptr);
-GtsPSurface * gts_psurface_open               (GtsPSurfaceClass * klass,
-					       GtsSurface * s,
-					       GtsSplitClass * split_class,
-					       GtsFile * f);
-GtsSplit *    gts_psurface_read_vertex        (GtsPSurface * ps, 
-					       GtsFile * fp);
-void          gts_psurface_close              (GtsPSurface * ps);
-void          gts_psurface_foreach_vertex     (GtsPSurface * ps, 
-					       GtsFunc func, 
-					       gpointer data);
-
-/* hsurface.c */
-
-typedef struct _GtsHSplit        GtsHSplit;
-typedef struct _GtsHSplitClass   GtsHSplitClass;
-typedef struct _GtsHSurface      GtsHSurface;
-typedef struct _GtsHSurfaceClass GtsHSurfaceClass;
-
-struct _GtsHSplit {
-  GtsSplit split;
-
-  GtsEHeapPair * index;
-  GtsHSplit * parent;
-  guint nchild;
-};
-
-struct _GtsHSplitClass {
-  GtsSplitClass parent_class;
-};
-
-#define GTS_IS_HSPLIT(obj) (gts_object_is_from_class (obj,\
-						      gts_hsplit_class ()))
-#define GTS_HSPLIT(obj)           GTS_OBJECT_CAST (obj,\
-						   GtsHSplit,\
-						   gts_hsplit_class ())
-#define GTS_HSPLIT_CLASS(klass)     GTS_OBJECT_CLASS_CAST (klass,\
-						   GtsHSplitClass,\
-						   gts_hsplit_class ())
-
-GtsHSplitClass * gts_hsplit_class             (void);
-GtsHSplit *   gts_hsplit_new                  (GtsHSplitClass * klass, 
-					       GtsSplit * vs);
-void          gts_hsplit_collapse             (GtsHSplit * hs,
-					       GtsHSurface * hsurface);
-void          gts_hsplit_expand               (GtsHSplit * hs,
-					       GtsHSurface * hsurface);
-void          gts_hsplit_force_expand         (GtsHSplit * hs,
-					       GtsHSurface * hsurface);
-
-struct _GtsHSurface {
-  GtsObject object;
-
-  GtsSurface * s;
-  GSList * roots;
-  GtsEHeap * expandable;
-  GtsEHeap * collapsable;
-  GPtrArray * split;
-  guint nvertex;
-};
-
-struct _GtsHSurfaceClass {
-  GtsObjectClass parent_class;
-};
-
-#define GTS_IS_HSURFACE(obj) (gts_object_is_from_class (obj,\
-							gts_hsurface_class ()))
-#define GTS_HSURFACE(obj)           GTS_OBJECT_CAST (obj,\
-						     GtsHSurface,\
-						     gts_hsurface_class ())
-#define GTS_HSURFACE_CLASS(klass)   GTS_OBJECT_CLASS_CAST (klass,\
-						     GtsHSurfaceClass,\
-						     gts_hsurface_class ())
-
-GtsHSurfaceClass * gts_hsurface_class    (void);
-GtsHSurface * gts_hsurface_new           (GtsHSurfaceClass * klass,
-					  GtsHSplitClass *   hsplit_class,
-					  GtsPSurface *      psurface,
-					  GtsKeyFunc         expand_key,
-					  gpointer           expand_data,
-					  GtsKeyFunc         collapse_key,
-					  gpointer           collapse_data);
-void          gts_hsurface_traverse      (GtsHSurface *        hsurface,
-					  GTraverseType        order,
-					  gint                 depth,
-					  GtsSplitTraverseFunc func,
-					  gpointer             data);
-void          gts_hsurface_foreach       (GtsHSurface *        hsurface,
-					  GTraverseType        order,
-					  GtsFunc              func,
-					  gpointer             data);
-guint         gts_hsurface_height        (GtsHSurface *        hsurface);
-
-/* Constrained Delaunay triangulation: cdt.c */
-
-/**
- * GTS_IS_CONSTRAINT:
- * @obj: a #GtsObject.
- *
- * Evaluates to %TRUE if @obj is a #GtsConstraint, %FALSE otherwise.
- */
-#define GTS_IS_CONSTRAINT(obj)      (gts_object_is_from_class (obj,\
-						    gts_constraint_class ()))
-/**
- * GTS_CONSTRAINT:
- * @obj: a descendant of #GtsConstraint.
- *
- * Casts @obj to #GtsConstraint.
- */
-#define GTS_CONSTRAINT(obj)          GTS_OBJECT_CAST (obj,\
-						  GtsConstraint,\
-						  gts_constraint_class ())
-/**
- * GTS_CONSTRAINT_CLASS:
- * @klass: a desscendant of #GtsConstraintClass.
- *
- * Casts @klass to #GtsConstraintClass.
- */
-#define GTS_CONSTRAINT_CLASS(klass)  GTS_OBJECT_CLASS_CAST (klass,\
-						  GtsConstraintClass,\
-						  gts_constraint_class ())
-
-struct _GtsConstraint {
-  GtsEdge edge;
-};
-
-struct _GtsConstraintClass {
-  GtsEdgeClass parent_class;
-};
-
-typedef struct _GtsConstraint        GtsConstraint;
-typedef struct _GtsConstraintClass   GtsConstraintClass;
-
-GtsConstraintClass * gts_constraint_class        (void);
-
-GtsFace *            gts_point_locate            (GtsPoint * p, 
-						  GtsSurface * surface,
-						  GtsFace * guess);
-GtsVertex *          gts_delaunay_add_vertex_to_face (GtsSurface * surface, 
-						      GtsVertex * v,
-						      GtsFace * f);
-GtsVertex *          gts_delaunay_add_vertex     (GtsSurface * surface, 
-						  GtsVertex * v,
-						  GtsFace * guess);
-void                 gts_delaunay_remove_vertex  (GtsSurface * surface, 
-						  GtsVertex * v);
-GtsFace *            gts_delaunay_check          (GtsSurface * surface);
-GSList *             gts_delaunay_add_constraint (GtsSurface * surface,
-						  GtsConstraint * c);
-void                 gts_delaunay_remove_hull    (GtsSurface * surface);
-
-/* GtsListFace: Header */
-
-typedef struct _GtsListFace         GtsListFace;
-
-struct _GtsListFace {
-  /*< private >*/
-  GtsFace parent;
-
-  /*< public >*/
-  GSList * points;
-};
-
-#define GTS_LIST_FACE(obj)            GTS_OBJECT_CAST (obj,\
-					         GtsListFace,\
-					         gts_list_face_class ())
-#define GTS_IS_LIST_FACE(obj)         (gts_object_is_from_class (obj,\
-						 gts_list_face_class ()))
-
-GtsFaceClass *       gts_list_face_class         (void);
-
-/* Constrained Delaunay refinement: refine.c */
-
-typedef gboolean   (* GtsEncroachFunc)           (GtsVertex * v,
-						  GtsEdge * e,
-						  GtsSurface * s,
-						  gpointer data);
-
-gboolean             gts_vertex_encroaches_edge  (GtsVertex * v, 
-						  GtsEdge * e);
-GtsVertex *          gts_edge_is_encroached      (GtsEdge * e,
-						  GtsSurface * s,
-						  GtsEncroachFunc encroaches,
-						  gpointer data);
-guint                gts_delaunay_conform        (GtsSurface * surface,
-						  gint steiner_max,
-						  GtsEncroachFunc encroaches,
-						  gpointer data);
-guint                gts_delaunay_refine         (GtsSurface * surface,
-						  gint steiner_max,
-						  GtsEncroachFunc encroaches,
-						  gpointer encroach_data,
-						  GtsKeyFunc cost,
-						  gpointer cost_data);
-
-/* Isosurfaces (marching cubes): iso.c */
-
-typedef struct _GtsGridPlane     GtsGridPlane;
-typedef struct _GtsIsoSlice      GtsIsoSlice;
-typedef struct _GtsCartesianGrid GtsCartesianGrid;
-
-struct _GtsGridPlane {
-  GtsPoint ** p;
-  guint nx, ny;
-};
-
-struct _GtsCartesianGrid {
-  guint nx, ny, nz;
-  gdouble x, dx, y, dy, z, dz;
-};
-
-typedef void (*GtsIsoCartesianFunc)         (gdouble ** a,
-					     GtsCartesianGrid g,
-					     guint i,
-					     gpointer data);
-
-GtsGridPlane * gts_grid_plane_new           (guint nx, 
-					     guint ny);
-void           gts_grid_plane_destroy       (GtsGridPlane * g);
-GtsIsoSlice *  gts_iso_slice_new            (guint nx, guint ny);
-void           gts_iso_slice_fill           (GtsIsoSlice * slice,
-					     GtsGridPlane * plane1,
-					     GtsGridPlane * plane2,
-					     gdouble ** f1,
-					     gdouble ** f2,
-					     gdouble iso,
-					     GtsVertexClass * klass);
-void           gts_iso_slice_fill_cartesian (GtsIsoSlice * slice,
-					     GtsCartesianGrid g,
-					     gdouble ** f1,
-					     gdouble ** f2,
-					     gdouble iso,
-					     GtsVertexClass * klass);
-void           gts_iso_slice_destroy        (GtsIsoSlice * slice);
-void           gts_isosurface_slice         (GtsIsoSlice * slice1,
-					     GtsIsoSlice * slice2,
-					     GtsSurface * surface);
-void           gts_isosurface_cartesian     (GtsSurface * surface,
-					     GtsCartesianGrid g,
-					     GtsIsoCartesianFunc f,
-					     gpointer data,
-					     gdouble iso);
-
-/* Isosurfaces (marching tetrahedra): isotetra.c */
-
-void           gts_isosurface_tetra         (GtsSurface * surface,
-					     GtsCartesianGrid g,
-					     GtsIsoCartesianFunc f,
-					     gpointer data,
-					     gdouble iso);
-void           gts_isosurface_tetra_bcl     (GtsSurface * surface,
-					     GtsCartesianGrid g,
-					     GtsIsoCartesianFunc f,
-					     gpointer data,
-					     gdouble iso);
-void           gts_isosurface_tetra_bounded (GtsSurface * surface,
-					     GtsCartesianGrid g,
-					     GtsIsoCartesianFunc f,
-					     gpointer data,
-					     gdouble iso);
-
-/* Named vertices, edges and triangles: named.c */
-
-#define GTS_NAME_LENGTH             40
-
-#define GTS_NVERTEX(obj)            GTS_OBJECT_CAST (obj,\
-						     GtsNVertex,\
-						     gts_nvertex_class ())
-#define GTS_NVERTEX_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-							   GtsNVertexClass,\
-							   gts_nvertex_class())
-#define GTS_IS_NVERTEX(obj)         (gts_object_is_from_class (obj,\
-				       gts_nvertex_class ()))
-
-typedef struct _GtsNVertex          GtsNVertex;
-typedef struct _GtsNVertexClass     GtsNVertexClass;
-
-struct _GtsNVertex {
-  GtsVertex parent;
-  char name[GTS_NAME_LENGTH];
-};
-
-struct _GtsNVertexClass {
-  GtsVertexClass parent_class;
-};
-
-GtsNVertexClass * gts_nvertex_class        (void);
-
-#define GTS_NEDGE(obj)            GTS_OBJECT_CAST (obj,\
-						   GtsNEdge,\
-						   gts_nedge_class ())
-#define GTS_NEDGE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-							 GtsNEdgeClass,\
-							 gts_nedge_class())
-#define GTS_IS_NEDGE(obj)         (gts_object_is_from_class (obj,\
-				       gts_nedge_class ()))
-
-typedef struct _GtsNEdge          GtsNEdge;
-typedef struct _GtsNEdgeClass     GtsNEdgeClass;
-
-struct _GtsNEdge {
-  GtsEdge parent;
-  char name[GTS_NAME_LENGTH];
-};
-
-struct _GtsNEdgeClass {
-  GtsEdgeClass parent_class;
-};
-
-GtsNEdgeClass *   gts_nedge_class        (void);
-
-#define GTS_NFACE(obj)            GTS_OBJECT_CAST (obj,\
-						   GtsNFace,\
-						   gts_nface_class ())
-#define GTS_NFACE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-							 GtsNFaceClass,\
-							 gts_nface_class())
-#define GTS_IS_NFACE(obj)         (gts_object_is_from_class (obj,\
-				       gts_nface_class ()))
-
-typedef struct _GtsNFace          GtsNFace;
-typedef struct _GtsNFaceClass     GtsNFaceClass;
-
-struct _GtsNFace {
-  GtsFace parent;
-  char name[GTS_NAME_LENGTH];
-};
-
-struct _GtsNFaceClass {
-  GtsFaceClass parent_class;
-};
-
-GtsNFaceClass *       gts_nface_class        (void);
-
-/* Cluster object for out-of-core simplification: oocs.c */
-
-#define GTS_CLUSTER(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsCluster,\
-					           gts_cluster_class ())
-#define GTS_CLUSTER_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsClusterClass,\
-						         gts_cluster_class())
-#define GTS_IS_CLUSTER(obj)         (gts_object_is_from_class (obj,\
-						   gts_cluster_class ()))
-     
-typedef struct _GtsCluster         GtsCluster;
-typedef struct _GtsClusterClass    GtsClusterClass;
-typedef struct _GtsClusterId       GtsClusterId;
-
-struct _GtsClusterId {
-  guint x, y, z;
-};
-
-struct _GtsCluster {
-  GtsObject parent;
-
-  GtsClusterId id;
-  GtsVertex * v;
-  guint n;
-};
-
-struct _GtsClusterClass {
-  GtsObjectClass parent_class;
-
-  void (* add) (GtsCluster * c, GtsPoint * p, gpointer data);
-  void (* update) (GtsCluster * c);
-};
-
-GtsClusterClass * gts_cluster_class                (void);
-GtsCluster *      gts_cluster_new                  (GtsClusterClass * klass,
-						    GtsClusterId id,
-						    GtsVertexClass * vklass);
-void              gts_cluster_add                  (GtsCluster * c, 
-						    GtsPoint * p,
-						    gpointer data);
-void              gts_cluster_update               (GtsCluster * c);
-
-/* Cluster group object for out-of-core simplification: oocs.c */
-
-#define GTS_CLUSTER_GRID(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsClusterGrid,\
-					           gts_cluster_grid_class ())
-#define GTS_CLUSTER_GRID_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						   GtsClusterGridClass,\
-						   gts_cluster_grid_class())
-#define GTS_IS_CLUSTER_GRID(obj)         (gts_object_is_from_class (obj,\
-						   gts_cluster_grid_class ()))
-     
-typedef struct _GtsClusterGrid         GtsClusterGrid;
-typedef struct _GtsClusterGridClass    GtsClusterGridClass;
-
-struct _GtsClusterGrid {
-  GtsObject parent;
-
-  GtsSurface * surface;
-  GtsBBox * bbox;
-  GtsVector size;
-
-  GtsClusterClass * cluster_class;
-  GHashTable * clusters;
-};
-
-struct _GtsClusterGridClass {
-  GtsObjectClass parent_class;
-};
-
-GtsClusterGridClass * gts_cluster_grid_class (void);
-GtsClusterGrid *      gts_cluster_grid_new   (GtsClusterGridClass * klass,
-					      GtsClusterClass * cluster_class,
-					      GtsSurface * s,
-					      GtsBBox * bbox,
-					      gdouble delta);
-void           gts_cluster_grid_add_triangle (GtsClusterGrid * cluster_grid,
-					      GtsPoint * p1,
-					      GtsPoint * p2,
-					      GtsPoint * p3,
-					      gpointer data);
-GtsRange       gts_cluster_grid_update       (GtsClusterGrid * cluster_grid);
-
-/* Triangle strip generation: stripe.c */
-GSList *       gts_surface_strip             (GtsSurface * s);
-
-/* GtsContainee: container.c */
-
-typedef struct _GtsContainee         GtsContainee;
-typedef struct _GtsContaineeClass    GtsContaineeClass;
-typedef struct _GtsContainer         GtsContainer;
-typedef struct _GtsContainerClass    GtsContainerClass;
-
-struct _GtsContainee {
-  GtsObject object;
-};
-
-struct _GtsContaineeClass {
-  GtsObjectClass parent_class;
-
-  void     (* add_container)    (GtsContainee *, GtsContainer *);
-  void     (* remove_container) (GtsContainee *, GtsContainer *);
-  void     (* foreach)          (GtsContainee *, GtsFunc, gpointer);
-  gboolean (* is_contained)     (GtsContainee *, GtsContainer *);
-  void     (* replace)          (GtsContainee *, GtsContainee *);
-};
-
-#define GTS_CONTAINEE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsContainee,\
-					           gts_containee_class ())
-#define GTS_CONTAINEE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsContaineeClass,\
-						         gts_containee_class())
-#define GTS_IS_CONTAINEE(obj)         (gts_object_is_from_class (obj,\
-						   gts_containee_class ()))
-     
-GtsContaineeClass * gts_containee_class        (void);
-GtsContainee *      gts_containee_new          (GtsContaineeClass * klass);
-gboolean            gts_containee_is_contained (GtsContainee * item, 
-						GtsContainer * c);
-void                gts_containee_replace      (GtsContainee * item,
-						GtsContainee * with);
-
-/* GtsSListContainee: container.c */
-
-typedef struct _GtsSListContainee         GtsSListContainee;
-typedef struct _GtsSListContaineeClass    GtsSListContaineeClass;
-
-struct _GtsSListContainee {
-  GtsContainee containee;
-
-  GSList * containers;
-};
-
-struct _GtsSListContaineeClass {
-  GtsContaineeClass parent_class;
-};
-
-#define GTS_SLIST_CONTAINEE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsSListContainee,\
-					           gts_slist_containee_class ())
-#define GTS_SLIST_CONTAINEE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsSListContaineeClass,\
-						         gts_slist_containee_class())
-#define GTS_IS_SLIST_CONTAINEE(obj)         (gts_object_is_from_class (obj,\
-						   gts_slist_containee_class ()))
-     
-GtsSListContaineeClass * gts_slist_containee_class   (void);
-
-/* GtsContainer: container.c */
-
-struct _GtsContainer {
-  GtsSListContainee object;
-};
-
-struct _GtsContainerClass {
-  GtsSListContaineeClass parent_class;
-
-  void  (* add)     (GtsContainer *, GtsContainee *);
-  void  (* remove)  (GtsContainer *, GtsContainee *);
-  void  (* foreach) (GtsContainer *, GtsFunc, gpointer);
-  guint (* size)    (GtsContainer *);
-};
-
-#define GTS_CONTAINER(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsContainer,\
-					           gts_container_class ())
-#define GTS_CONTAINER_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsContainerClass,\
-						         gts_container_class())
-#define GTS_IS_CONTAINER(obj)         (gts_object_is_from_class (obj,\
-						   gts_container_class ()))
-     
-GtsContainerClass * gts_container_class     (void);
-GtsContainer *      gts_container_new       (GtsContainerClass * klass);
-void                gts_container_add       (GtsContainer * c,
-					     GtsContainee * item);
-void                gts_container_remove    (GtsContainer * c,
-					     GtsContainee * item);
-void                gts_container_foreach   (GtsContainer * c,
-					     GtsFunc func,
-					     gpointer data);
-guint               gts_container_size      (GtsContainer * c);
-
-/* GtsHashContainer: container.c */
-
-typedef struct _GtsHashContainer         GtsHashContainer;
-typedef struct _GtsHashContainerClass    GtsHashContainerClass;
-
-struct _GtsHashContainer {
-  GtsContainer c;
-
-  GHashTable * items;
-  gboolean frozen;
-};
-
-struct _GtsHashContainerClass {
-  GtsContainerClass parent_class;
-};
-
-#define GTS_HASH_CONTAINER(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsHashContainer,\
-					           gts_hash_container_class ())
-#define GTS_HASH_CONTAINER_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsHashContainerClass,\
-						         gts_hash_container_class())
-#define GTS_IS_HASH_CONTAINER(obj)         (gts_object_is_from_class (obj,\
-						   gts_hash_container_class ()))
-     
-GtsHashContainerClass * gts_hash_container_class (void);
-
-/* GtsSListContainer: container.c */
-
-typedef struct _GtsSListContainer         GtsSListContainer;
-typedef struct _GtsSListContainerClass    GtsSListContainerClass;
-
-struct _GtsSListContainer {
-  GtsContainer c;
-
-  GSList * items;
-  gboolean frozen;
-};
-
-struct _GtsSListContainerClass {
-  GtsContainerClass parent_class;
-};
-
-#define GTS_SLIST_CONTAINER(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsSListContainer,\
-					           gts_slist_container_class ())
-#define GTS_SLIST_CONTAINER_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsSListContainerClass,\
-						         gts_slist_container_class())
-#define GTS_IS_SLIST_CONTAINER(obj)         (gts_object_is_from_class (obj,\
-						   gts_slist_container_class ()))
-     
-GtsSListContainerClass * gts_slist_container_class (void);
-
-/* GtsGNode: graph.c */
-
-typedef struct _GtsGNode         GtsGNode;
-typedef struct _GtsGNodeClass    GtsGNodeClass;
-typedef struct _GtsGraph         GtsGraph;
-typedef struct _GtsGraphClass    GtsGraphClass;
-
-struct _GtsGNode {
-  GtsSListContainer container;
-
-  guint level;
-};
-
-struct _GtsGNodeClass {
-  GtsSListContainerClass parent_class;
-
-  gfloat (* weight) (GtsGNode *);
-  void   (* write)  (GtsGNode *, FILE *);
-};
-
-#define GTS_GNODE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsGNode,\
-					           gts_gnode_class ())
-#define GTS_GNODE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsGNodeClass,\
-						         gts_gnode_class())
-#define GTS_IS_GNODE(obj)         (gts_object_is_from_class (obj,\
-						   gts_gnode_class ()))
-#define GTS_GNODE_NEIGHBOR(n,e)   (GTS_GEDGE (e)->n1 == n ? GTS_GEDGE (e)->n2 : GTS_GEDGE (e)->n2 == n ? GTS_GEDGE (e)->n1 : NULL)
-     
-GtsGNodeClass * gts_gnode_class                (void);
-GtsGNode *      gts_gnode_new                  (GtsGNodeClass * klass);
-void            gts_gnode_foreach_neighbor     (GtsGNode * n, 
-						GtsGraph * g,
-						GtsFunc func,
-						gpointer data);
-void            gts_gnode_foreach_edge         (GtsGNode * n,
-						GtsGraph * g,
-						GtsFunc func,
-						gpointer data);
-guint           gts_gnode_degree               (GtsGNode * n,
-						GtsGraph * g);
-gfloat          gts_gnode_move_cost            (GtsGNode * n,
-						GtsGraph * src,
-						GtsGraph * dst);
-gfloat          gts_gnode_weight               (GtsGNode * n);
-
-GTS_C_VAR
-gboolean        gts_allow_floating_gnodes;
-
-/* GtsNGNode: graph.c */
-
-typedef struct _GtsNGNode         GtsNGNode;
-typedef struct _GtsNGNodeClass    GtsNGNodeClass;
-
-struct _GtsNGNode {
-  GtsGNode node;
-
-  guint id;
-};
-
-struct _GtsNGNodeClass {
-  GtsGNodeClass parent_class;
-};
-
-#define GTS_NGNODE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsNGNode,\
-					           gts_ngnode_class ())
-#define GTS_NGNODE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsNGNodeClass,\
-						         gts_ngnode_class())
-#define GTS_IS_NGNODE(obj)         (gts_object_is_from_class (obj,\
-						   gts_ngnode_class ()))
-     
-GtsNGNodeClass * gts_ngnode_class                (void);
-GtsNGNode *      gts_ngnode_new                  (GtsNGNodeClass * klass,
-						  guint id);
-
-/* GtsWGNode: graph.c */
-
-typedef struct _GtsWGNode         GtsWGNode;
-typedef struct _GtsWGNodeClass    GtsWGNodeClass;
-
-struct _GtsWGNode {
-  GtsGNode node;
-  
-  gfloat weight;
-};
-
-struct _GtsWGNodeClass {
-  GtsGNodeClass parent_class;
-};
-
-#define GTS_WGNODE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsWGNode,\
-					           gts_wgnode_class ())
-#define GTS_WGNODE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsWGNodeClass,\
-						         gts_wgnode_class())
-#define GTS_IS_WGNODE(obj)         (gts_object_is_from_class (obj,\
-						   gts_wgnode_class ()))
-     
-GtsWGNodeClass * gts_wgnode_class                (void);
-GtsWGNode *      gts_wgnode_new                  (GtsWGNodeClass * klass,
-						  gfloat weight);
-
-/* GtsPNode */
-
-typedef struct _GtsPNode         GtsPNode;
-typedef struct _GtsPNodeClass    GtsPNodeClass;
-
-struct _GtsPNode {
-  GtsGNode node;
-
-  gpointer data;
-};
-
-struct _GtsPNodeClass {
-  GtsGNodeClass parent_class;
-};
-
-#define GTS_PNODE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsPNode,\
-					           gts_pnode_class ())
-#define GTS_PNODE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsPNodeClass,\
-						         gts_pnode_class())
-#define GTS_IS_PNODE(obj)         (gts_object_is_from_class (obj,\
-						   gts_pnode_class ()))
-     
-GtsPNodeClass * gts_pnode_class                (void);
-GtsPNode *      gts_pnode_new                  (GtsPNodeClass * klass,
-						gpointer data);
-
-/* GtsFNode */
-
-typedef struct _GtsFNode         GtsFNode;
-typedef struct _GtsFNodeClass    GtsFNodeClass;
-
-struct _GtsFNode {
-  GtsGNode node;
-
-  GtsFace * f;
-};
-
-struct _GtsFNodeClass {
-  GtsGNodeClass parent_class;
-};
-
-#define GTS_FNODE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsFNode,\
-					           gts_fnode_class ())
-#define GTS_FNODE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsFNodeClass,\
-						         gts_fnode_class())
-#define GTS_IS_FNODE(obj)         (gts_object_is_from_class (obj,\
-						   gts_fnode_class ()))
-     
-GtsFNodeClass * gts_fnode_class                (void);
-GtsFNode *      gts_fnode_new                  (GtsFNodeClass * klass,
-						GtsFace * f);
-
-/* GtsGEdge: graph.c */
-
-typedef struct _GtsGEdge         GtsGEdge;
-typedef struct _GtsGEdgeClass    GtsGEdgeClass;
-
-struct _GtsGEdge {
-  GtsContainee containee;
-
-  GtsGNode * n1;
-  GtsGNode * n2;
-};
-
-struct _GtsGEdgeClass {
-  GtsContaineeClass parent_class;
-
-  GtsGEdge * (* link)   (GtsGEdge * e, GtsGNode * n1, GtsGNode * n2);
-  gfloat     (* weight) (GtsGEdge * e);
-  void       (* write)  (GtsGEdge * e, FILE * fp);
-};
-
-#define GTS_GEDGE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsGEdge,\
-					           gts_gedge_class ())
-#define GTS_GEDGE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsGEdgeClass,\
-						         gts_gedge_class())
-#define GTS_IS_GEDGE(obj)         (gts_object_is_from_class (obj,\
-						   gts_gedge_class ()))
-     
-GtsGEdgeClass * gts_gedge_class                (void);
-GtsGEdge *      gts_gedge_new                  (GtsGEdgeClass * klass,
-						GtsGNode * n1,
-						GtsGNode * n2);
-gfloat          gts_gedge_weight               (GtsGEdge * e);
-#define         gts_gedge_connects(e, a1, a2)\
-   (((e)->n1 == a1 && (e)->n2 == a2) || ((e)->n1 == a2 && (e)->n2 == a1)) 
-
-/* GtsPGEdge: graph.c */
-
-typedef struct _GtsPGEdge         GtsPGEdge;
-typedef struct _GtsPGEdgeClass    GtsPGEdgeClass;
-
-struct _GtsPGEdge {
-  GtsGEdge gedge;
-
-  gpointer data;
-};
-
-struct _GtsPGEdgeClass {
-  GtsGEdgeClass parent_class;
-};
-
-#define GTS_PGEDGE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsPGEdge,\
-					           gts_pgedge_class ())
-#define GTS_PGEDGE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsPGEdgeClass,\
-						         gts_pgedge_class())
-#define GTS_IS_PGEDGE(obj)         (gts_object_is_from_class (obj,\
-						   gts_pgedge_class ()))
-     
-GtsPGEdgeClass * gts_pgedge_class                (void);
-GtsPGEdge *      gts_pgedge_new                  (GtsPGEdgeClass * klass,
-						  GtsGNode * n1,
-						  GtsGNode * n2,
-						  gpointer data);
-
-/* GtsWGEdge: graph.c */
-
-typedef struct _GtsWGEdge         GtsWGEdge;
-typedef struct _GtsWGEdgeClass    GtsWGEdgeClass;
-
-struct _GtsWGEdge {
-  GtsGEdge gedge;
-
-  gfloat weight;
-};
-
-struct _GtsWGEdgeClass {
-  GtsGEdgeClass parent_class;
-};
-
-#define GTS_WGEDGE(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsWGEdge,\
-					           gts_wgedge_class ())
-#define GTS_WGEDGE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsWGEdgeClass,\
-						         gts_wgedge_class())
-#define GTS_IS_WGEDGE(obj)         (gts_object_is_from_class (obj,\
-						   gts_wgedge_class ()))
-     
-GtsWGEdgeClass * gts_wgedge_class                (void);
-GtsWGEdge *      gts_wgedge_new                  (GtsWGEdgeClass * klass,
-						  GtsGNode * n1,
-						  GtsGNode * n2,
-						  gfloat weight);
-
-/* GtsGraph: graph.c */
-
-struct _GtsGraph {
-  GtsHashContainer object;
-
-  GtsGraphClass * graph_class;
-  GtsGNodeClass * node_class;
-  GtsGEdgeClass * edge_class;
-};
-
-struct _GtsGraphClass {
-  GtsHashContainerClass parent_class;
-
-  gfloat (* weight) (GtsGraph *);
-};
-
-#define GTS_GRAPH(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsGraph,\
-					           gts_graph_class ())
-#define GTS_GRAPH_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsGraphClass,\
-						         gts_graph_class())
-#define GTS_IS_GRAPH(obj)         (gts_object_is_from_class (obj,\
-						   gts_graph_class ()))
-     
-GtsGraphClass * gts_graph_class                  (void);
-GtsGraph *      gts_graph_new                    (GtsGraphClass * klass,
-						  GtsGNodeClass * node_class,
-						  GtsGEdgeClass * edge_class);
-void            gts_graph_print_stats            (GtsGraph * g,
-						  FILE * fp);
-typedef struct _GtsGraphTraverse GtsGraphTraverse;
-typedef enum   { GTS_BREADTH_FIRST
-               }   GtsTraverseType;
-GtsGraphTraverse * gts_graph_traverse_new        (GtsGraph * g, 
-						  GtsGNode * n,
-						  GtsTraverseType type,
-						  gboolean reinit);
-GtsGNode *         gts_graph_traverse_next       (GtsGraphTraverse * t);
-GtsGNode *         gts_graph_traverse_what_next  (GtsGraphTraverse * t);
-void               gts_graph_traverse_destroy    (GtsGraphTraverse * t);
-void               gts_graph_foreach_edge        (GtsGraph * g,
-						  GtsFunc func,
-						  gpointer data);
-gfloat             gts_graph_weight              (GtsGraph * g);
-guint              gts_graph_distance_sum        (GtsGraph * g, 
-						  GtsGNode * center);
-GtsGNode *         gts_graph_farthest            (GtsGraph * g, 
-						  GSList * gnodes);
-guint              gts_graph_edges_cut           (GtsGraph * g);
-gfloat             gts_graph_edges_cut_weight    (GtsGraph * g);
-void               gts_graph_write               (GtsGraph * g, 
-						  FILE * fp);
-void               gts_graph_write_dot           (GtsGraph * g, 
-						  FILE * fp);
-GtsGraph *         gts_graph_read                (GtsFile * fp);
-guint              gts_graph_read_jostle         (GtsGraph * g, 
-						  GtsFile * fp);
-
-/* GtsWGraph: graph.c */
-
-typedef struct _GtsWGraph      GtsWGraph;
-typedef struct _GtsWGraphClass GtsWGraphClass;
-
-struct _GtsWGraph {
-  GtsGraph graph;
-
-  gfloat weight;
-};
-
-struct _GtsWGraphClass {
-  GtsGraphClass parent_class;
-};
-
-#define GTS_WGRAPH(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsWGraph,\
-					           gts_wgraph_class ())
-#define GTS_WGRAPH_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsWGraphClass,\
-						         gts_wgraph_class())
-#define GTS_IS_WGRAPH(obj)         (gts_object_is_from_class (obj,\
-						   gts_wgraph_class ()))
-     
-GtsWGraphClass * gts_wgraph_class                (void);
-gfloat           gts_wgraph_weight_max           (GtsWGraph * wg);
-
-/* Surface graph: graph.c */
-
-GtsGraph *       gts_surface_graph_new           (GtsGraphClass * klass,
-						  GtsSurface * s);
-GtsSurface *     gts_surface_graph_surface       (GtsGraph * surface_graph,
-						  GtsSurface * s);
-
-/* Segments graph: graph.c */
-
-GtsGraph *       gts_segments_graph_new          (GtsGraphClass * klass,
-						  GSList * segments);
-
-/* GtsGNodeSplit: pgraph.c */
-
-typedef struct _GtsGNodeSplit         GtsGNodeSplit;
-typedef struct _GtsGNodeSplitClass    GtsGNodeSplitClass;
-
-struct _GtsGNodeSplit {
-  GtsObject object;
-
-  GtsGNode * n;
-  GtsObject * n1;
-  GtsObject * n2;
-};
-
-struct _GtsGNodeSplitClass {
-  GtsObjectClass parent_class;
-};
-
-#define GTS_GNODE_SPLIT(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsGNodeSplit,\
-					           gts_gnode_split_class ())
-#define GTS_GNODE_SPLIT_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsGNodeSplitClass,\
-						         gts_gnode_split_class())
-#define GTS_IS_GNODE_SPLIT(obj)         (gts_object_is_from_class (obj,\
-						   gts_gnode_split_class ()))
-#define GTS_GNODE_SPLIT_N1(ns) (GTS_IS_GNODE_SPLIT ((ns)->n1) ? GTS_GNODE_SPLIT ((ns)->n1)->n : GTS_GNODE ((ns)->n1))
-#define GTS_GNODE_SPLIT_N2(ns) (GTS_IS_GNODE_SPLIT ((ns)->n2) ? GTS_GNODE_SPLIT ((ns)->n2)->n : GTS_GNODE ((ns)->n2))
-     
-GtsGNodeSplitClass * gts_gnode_split_class    (void);
-GtsGNodeSplit *      gts_gnode_split_new      (GtsGNodeSplitClass * klass,
-					       GtsGNode * n,
-					       GtsObject * n1,
-					       GtsObject * n2);
-void                 gts_gnode_split_collapse (GtsGNodeSplit * ns,
-					       GtsGraph * g,
-					       GtsWGEdgeClass * klass);
-void                 gts_gnode_split_expand   (GtsGNodeSplit * ns,
-					       GtsGraph * g);
-
-/* GtsPGraph: pgraph.c */
-
-typedef struct _GtsPGraph         GtsPGraph;
-typedef struct _GtsPGraphClass    GtsPGraphClass;
-
-struct _GtsPGraph {
-  GtsObject object;
-
-  GtsGraph * g;
-  GPtrArray * split;
-  GArray * levels;
-  GtsGNodeSplitClass * split_class;
-  GtsWGEdgeClass * edge_class;
-  guint pos, min, level;
-};
-
-struct _GtsPGraphClass {
-  GtsObjectClass parent_class;
-};
-
-#define GTS_PGRAPH(obj)            GTS_OBJECT_CAST (obj,\
-					           GtsPGraph,\
-					           gts_pgraph_class ())
-#define GTS_PGRAPH_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
-						         GtsPGraphClass,\
-						         gts_pgraph_class())
-#define GTS_IS_PGRAPH(obj)         (gts_object_is_from_class (obj,\
-						   gts_pgraph_class ()))
-     
-GtsPGraphClass * gts_pgraph_class            (void);
-GtsPGraph *      gts_pgraph_new              (GtsPGraphClass * klass,
-					      GtsGraph * g,
-					      GtsGNodeSplitClass * split_class,
-					      GtsWGNodeClass * node_class,
-					      GtsWGEdgeClass * edge_class,
-					      guint min);
-GtsGNodeSplit *  gts_pgraph_add_node         (GtsPGraph * pg);
-GtsGNodeSplit *  gts_pgraph_remove_node      (GtsPGraph * pg);
-void             gts_pgraph_set_node_number  (GtsPGraph *pg,
-					      guint n);
-guint            gts_pgraph_get_node_number  (GtsPGraph *pg);
-guint            gts_pgraph_min_node_number  (GtsPGraph *pg);
-guint            gts_pgraph_max_node_number  (GtsPGraph *pg);
-void             gts_pgraph_foreach_node     (GtsPGraph *pg,
-					      GtsFunc func,
-					      gpointer data);
-gboolean         gts_pgraph_down             (GtsPGraph * pg,
-					      GtsFunc func,
-					      gpointer data);
-/* Graph partition: partition.c */
-
-GSList *         gts_graph_bubble_partition           (GtsGraph * g, 
-						       guint np, 
-						       guint niter,
-						       GtsFunc step_info,
-						       gpointer data);
-guint            gts_graph_partition_edges_cut        (GSList * partition);
-gfloat           gts_graph_partition_edges_cut_weight (GSList * partition);
-void             gts_graph_partition_print_stats      (GSList * partition,
-						       FILE * fp);
-gfloat           gts_graph_partition_balance          (GSList * partition);
-GSList *         gts_graph_partition_clone            (GSList * partition);
-GSList *         gts_graph_recursive_bisection        (GtsWGraph * wg,
-						       guint n,
-						       guint ntry,
-						       guint mmax,
-						       guint nmin,
-						       gfloat imbalance);
-void             gts_graph_partition_destroy          (GSList * partition);
-
-/* Graph bisection: partition.c */
-
-typedef struct _GtsGraphBisection GtsGraphBisection;
-
-struct _GtsGraphBisection {
-  GtsGraph * g;
-  GtsGraph * g1;
-  GtsGraph * g2;
-  GHashTable * bg1;
-  GHashTable * bg2;
-};
-
-gboolean            gts_graph_bisection_check      (GtsGraphBisection * bg);
-GtsGraphBisection * gts_graph_ggg_bisection        (GtsGraph * g, 
-						    guint ntry);
-GtsGraphBisection * gts_graph_bfgg_bisection       (GtsGraph * g, 
-						    guint ntry);
-gdouble             gts_graph_bisection_kl_refine  (GtsGraphBisection * bg,
-						    guint mmax);
-gdouble             gts_graph_bisection_bkl_refine (GtsGraphBisection * bg,
-						    guint mmax,
-						    gfloat imbalance);
-GtsGraphBisection * gts_graph_bisection_new        (GtsWGraph * wg,
-						    guint ntry,
-						    guint mmax,
-						    guint nmin,
-						    gfloat imbalance);
-void                gts_graph_bisection_destroy    (GtsGraphBisection * bg,
-						    gboolean destroy_graphs);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __GTS_H__ */
diff --git a/src_3rd/gts/heap.c b/src_3rd/gts/heap.c
deleted file mode 100644
index 4a37e58..0000000
--- a/src_3rd/gts/heap.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include "gts.h"
-
-#define PARENT(i) ((i) >= 2 ? (i)/2 : 0)
-#define LEFT_CHILD(i) (2*(i))
-#define RIGHT_CHILD(i) (2*(i) + 1)
-
-struct _GtsHeap {
-  GPtrArray * elts;
-  GCompareFunc func;
-  gboolean frozen;
-};
-
-/**
- * gts_heap_new:
- * @compare_func: a GCompareFunc.
- *
- * Returns: a new #GtsHeap using @compare_func as a sorting function.
- */
-GtsHeap * gts_heap_new (GCompareFunc compare_func)
-{
-  GtsHeap * heap;
-
-  g_return_val_if_fail (compare_func != NULL, NULL);
-  
-  heap = g_malloc (sizeof(GtsHeap));
-  heap->elts = g_ptr_array_new ();
-  heap->func = compare_func;
-  heap->frozen = FALSE;
-  return heap;
-}
-
-static void sift_up (GtsHeap * heap, guint i)
-{
-  gpointer parent, child;
-  guint p;
-  gpointer * pdata = heap->elts->pdata;
-  GCompareFunc func = heap->func;
-
-  child = pdata[i - 1];
-  while ((p = PARENT (i))) {
-    parent = pdata[p - 1];
-    if ((*func) (parent, child) > 0) {
-      pdata[p - 1] = child;
-      pdata[i - 1] = parent;
-      i = p;
-    }
-    else
-      i = 0;
-  }
-}
-
-/**
- * gts_heap_insert:
- * @heap: a #GtsHeap.
- * @p: a pointer to add to the heap.
- *
- * Inserts a new element @p in the heap.
- */
-void gts_heap_insert (GtsHeap * heap, gpointer p)
-{
-  g_return_if_fail (heap != NULL);
-
-  g_ptr_array_add (heap->elts, p);
-  if (!heap->frozen)
-    sift_up (heap, heap->elts->len);
-}
-
-static void sift_down (GtsHeap * heap, guint i)
-{
-  gpointer left_child, right_child, child, parent;
-  guint lc, rc, c;
-  gpointer * pdata = heap->elts->pdata;
-  guint len = heap->elts->len;
-  GCompareFunc func = heap->func;
-
-  lc = LEFT_CHILD (i);
-  rc = RIGHT_CHILD (i);
-  left_child = lc <= len ? pdata[lc - 1] : NULL;
-  right_child = rc <= len ? pdata[rc - 1] : NULL;
-
-  parent = pdata[i - 1];
-  while (left_child != NULL) {
-    if (right_child == NULL ||
-	(*func) (left_child, right_child) < 0) {
-      child = left_child;
-      c = lc;
-    }
-    else {
-      child = right_child;
-      c = rc;
-    }
-    if ((*func) (parent, child) > 0) {
-      pdata[i - 1] = child;
-      pdata[c - 1] = parent;
-      i = c;
-      lc = LEFT_CHILD (i);
-      rc = RIGHT_CHILD (i);
-      left_child = lc <= len ? pdata[lc - 1] : NULL;
-      right_child = rc <= len ? pdata[rc - 1] : NULL;      
-    }
-    else
-      left_child = NULL;
-  }
-}
-
-/**
- * gts_heap_remove_top:
- * @heap: a #GtsHeap.
- *
- * Removes the element at the top of the heap.
- *
- * Returns: the element at the top of the heap.
- */
-gpointer gts_heap_remove_top (GtsHeap * heap)
-{
-  gpointer root;
-  GPtrArray * elts;
-  guint len;
-
-  g_return_val_if_fail (heap != NULL, NULL);
-
-  elts = heap->elts; len = elts->len;
-
-  if (len == 0)
-    return NULL;
-  if (len == 1)
-    return g_ptr_array_remove_index (elts, 0);
-
-  root = elts->pdata[0];
-  elts->pdata[0] = g_ptr_array_remove_index (elts, len - 1);
-  sift_down (heap, 1);
-  return root;
-}
-
-/**
- * gts_heap_top:
- * @heap: a #GtsHeap.
- *
- * Returns: the element at the top of the heap.
- */
-gpointer gts_heap_top (GtsHeap * heap)
-{
-  GPtrArray * elts;
-  guint len;
-
-  g_return_val_if_fail (heap != NULL, NULL);
-
-  elts = heap->elts; 
-  len = elts->len;
-  if (len == 0)
-    return NULL;
-  return elts->pdata[0];
-}
-
-/**
- * gts_heap_destroy:
- * @heap: a #GtsHeap.
- * 
- * Free all the memory allocated for @heap.
- */
-void gts_heap_destroy (GtsHeap * heap)
-{
-  g_return_if_fail (heap != NULL);
-
-  g_ptr_array_free (heap->elts, TRUE);
-  g_free (heap);
-}
-
-/**
- * gts_heap_thaw:
- * @heap: a #GtsHeap.
- *
- * If @heap has been frozen previously using gts_heap_freeze(), reorder it
- * in O(n) time and unfreeze it.
- */
-void gts_heap_thaw (GtsHeap * heap)
-{
-  guint i;
-  
-  g_return_if_fail (heap != NULL);
-
-  if (!heap->frozen)
-    return;
-
-  for (i = heap->elts->len/2; i > 0; i--)
-    sift_down (heap, i);
-
-  heap->frozen = FALSE;
-}
-
-/**
- * gts_heap_foreach:
- * @heap: a #GtsHeap.
- * @func: the function to call for each element in the heap.
- * @user_data: to pass to @func.
- */
-void gts_heap_foreach (GtsHeap * heap, 
-		       GFunc func,
-		       gpointer user_data)
-{
-  guint i;
-  GPtrArray * elts;
-  
-  g_return_if_fail (heap != NULL);
-  g_return_if_fail (func != NULL);
-
-  elts = heap->elts;
-  for (i = 0; i < elts->len; i++)
-    (*func) (elts->pdata[i], user_data);
-}
-
-/**
- * gts_heap_freeze:
- * @heap: a #GtsHeap.
- *
- * Freezes the heap. Any subsequent operation will not preserve the heap
- * property. Used in conjunction with gts_heap_insert() and gts_heap_thaw()
- * to create a heap in O(n) time.
- */
-void gts_heap_freeze (GtsHeap * heap)
-{
-  g_return_if_fail (heap != NULL);
-
-  heap->frozen = TRUE;
-}
-
-/**
- * gts_heap_size:
- * @heap: a #GtsHeap.
- *
- * Returns: the number of items in @heap.
- */
-guint gts_heap_size (GtsHeap * heap)
-{
-  g_return_val_if_fail (heap != NULL, 0);
-
-  return heap->elts->len;
-}
diff --git a/src_3rd/gts/hsurface.c b/src_3rd/gts/hsurface.c
deleted file mode 100644
index 80ac66a..0000000
--- a/src_3rd/gts/hsurface.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include "gts.h"
-
-#define HEAP_INSERT_HSPLIT(h, e) ((e)->index = gts_eheap_insert (h, e))
-#define HEAP_REMOVE_HSPLIT(h, e) (gts_eheap_remove (h, (e)->index),\
-				  (e)->index = NULL)
-
-static void hsplit_init (GtsHSplit * hsplit)
-{
-  hsplit->index = NULL;
-  hsplit->parent = NULL;
-  hsplit->nchild = 0;
-}
-
-/**
- * gts_hsplit_class:
- *
- * Returns: the #GtsHSplitClass.
- */
-GtsHSplitClass * gts_hsplit_class (void)
-{
-  static GtsHSplitClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo hsplit_info = {
-      "GtsHSplit",
-      sizeof (GtsHSplit),
-      sizeof (GtsHSplitClass),
-      (GtsObjectClassInitFunc) NULL,
-      (GtsObjectInitFunc) hsplit_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_split_class ()), 
-				  &hsplit_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_hsplit_new:
- * @klass: a #GtsHSplitClass.
- * @vs: a #GtsSplit.
- *
- * Returns: a new #GtsHSplit, hierarchical extension of @vs.
- */
-GtsHSplit * gts_hsplit_new (GtsHSplitClass * klass, GtsSplit * vs)
-{
-  GtsHSplit * hs;
-
-  g_return_val_if_fail (vs != NULL, NULL);
-
-  hs = GTS_HSPLIT (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  memcpy (hs, vs, sizeof (GtsSplit));
-  GTS_OBJECT (hs)->reserved = NULL;
-
-  return hs;
-}
-
-/**
- * gts_hsplit_collapse:
- * @hs: a #GtsHSplit.
- * @hsurface: a #GtsHSurface.
- *
- * Collapses the #GtsSplit defined by @hs, updates the expandable and
- * collapsable priority heaps of @hsurface.  
- */
-void gts_hsplit_collapse (GtsHSplit * hs,
-			  GtsHSurface * hsurface)
-{
-  GtsHSplit * parent;
-  GtsSplit * vs;
-
-  g_return_if_fail (hs != NULL);
-  g_return_if_fail (hs->nchild == 2);
-  g_return_if_fail (hsurface != NULL);
-
-  gts_split_collapse (GTS_SPLIT (hs), hsurface->s->edge_class, NULL);
-
-  hsurface->nvertex--;
-  hs->nchild = 0;
-  HEAP_REMOVE_HSPLIT (hsurface->collapsable, hs);
-  HEAP_INSERT_HSPLIT (hsurface->expandable, hs);
-
-  vs = GTS_SPLIT (hs);
-  if (GTS_IS_HSPLIT (vs->v1))
-    HEAP_REMOVE_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v1));
-  if (GTS_IS_HSPLIT (vs->v2))
-    HEAP_REMOVE_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v2));
-
-  parent = hs->parent;
-  if (parent && ++parent->nchild == 2)
-    HEAP_INSERT_HSPLIT (hsurface->collapsable, parent);
-}
-
-/**
- * gts_hsplit_expand:
- * @hs: a #GtsHSplit.
- * @hsurface: a #GtsHSurface.
- *
- * Expands the #GtsSplit defined by @hs (which must be expandable)
- * and updates the priority heaps of @hsurface.
- */
-void gts_hsplit_expand (GtsHSplit * hs,
-			GtsHSurface * hsurface)
-{
-  GtsHSplit * parent;
-  GtsSplit * vs;
-
-  g_return_if_fail (hs != NULL);
-  g_return_if_fail (hsurface != NULL);
-  g_return_if_fail (hs->nchild == 0);
-
-  gts_split_expand (GTS_SPLIT (hs), hsurface->s, hsurface->s->edge_class);
-  hsurface->nvertex++;
-  hs->nchild = 2;
-  HEAP_REMOVE_HSPLIT (hsurface->expandable, hs);
-  HEAP_INSERT_HSPLIT (hsurface->collapsable, hs);
-
-  vs = GTS_SPLIT (hs);
-  if (GTS_IS_HSPLIT (vs->v1))
-    HEAP_INSERT_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v1));
-  if (GTS_IS_HSPLIT (vs->v2))
-    HEAP_INSERT_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v2));
-
-  parent = hs->parent;
-  if (parent && parent->nchild-- == 2)
-    HEAP_REMOVE_HSPLIT (hsurface->collapsable, parent);
-}
-
-static void hsurface_destroy (GtsObject * object)
-{
-  GtsHSurface * hs = GTS_HSURFACE (object);
-
-  gts_hsurface_traverse (hs, G_POST_ORDER, -1,
-			 (GtsSplitTraverseFunc) gts_object_destroy, 
-			 NULL);
-  g_slist_free (hs->roots);
-  if (hs->expandable)
-    gts_eheap_destroy (hs->expandable);
-  if (hs->collapsable)
-    gts_eheap_destroy (hs->collapsable);
-  g_ptr_array_free (hs->split, TRUE);
-
-  (* GTS_OBJECT_CLASS (gts_hsurface_class ())->parent_class->destroy) (object);
-}
-
-static void hsurface_class_init (GtsObjectClass * klass)
-{
-  klass->destroy = hsurface_destroy;
-}
-
-static void hsurface_init (GtsHSurface * hsurface)
-{
-  hsurface->s = NULL;
-  hsurface->roots = NULL;
-  hsurface->expandable = hsurface->collapsable = NULL;
-  hsurface->split = g_ptr_array_new ();
-  hsurface->nvertex = 0;
-}
-
-/**
- * gts_hsurface_class:
- *
- * Returns: the #GtsHSurfaceClass.
- */
-GtsHSurfaceClass * gts_hsurface_class (void)
-{
-  static GtsHSurfaceClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo hsurface_info = {
-      "GtsHSurface",
-      sizeof (GtsHSurface),
-      sizeof (GtsHSurfaceClass),
-      (GtsObjectClassInitFunc) hsurface_class_init,
-      (GtsObjectInitFunc) hsurface_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), 
-				  &hsurface_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_hsurface_new:
- * @klass: a #GtsHSurfaceClass.
- * @hsplit_class: a #GtsHSplitClass.
- * @psurface: a #GtsPSurface.
- * @expand_key: a #GtsKeyFunc used to order the priority heap of expandable 
- * #GtsHSplit.
- * @expand_data: data to be passed to @expand_key.
- * @collapse_key: a #GtsKeyFunc used to order the priority heap of collapsable
- * #GtsHSplit.
- * @collapse_data: data to be passed to @collapsed_key.
- *
- * Returns: a new #GtsHSurface, hierarchical extension of @psurface
- * and using #GtsHSplit of class @hsplit_class. Note that @psurface is
- * destroyed in the process.
- */
-GtsHSurface * gts_hsurface_new (GtsHSurfaceClass * klass,
-				GtsHSplitClass * hsplit_class,
-				GtsPSurface * psurface,
-				GtsKeyFunc expand_key,
-				gpointer expand_data,
-				GtsKeyFunc collapse_key,
-				gpointer collapse_data)
-{
-  GtsHSurface * hsurface;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (hsplit_class != NULL, NULL);
-  g_return_val_if_fail (psurface != NULL, NULL);
-  g_return_val_if_fail (expand_key != NULL, NULL);
-  g_return_val_if_fail (collapse_key != NULL, NULL);
-
-  hsurface = GTS_HSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  hsurface->s = psurface->s;
-  hsurface->expandable = gts_eheap_new (expand_key, expand_data);
-  hsurface->collapsable = gts_eheap_new (collapse_key, collapse_data);
-  g_ptr_array_set_size (hsurface->split, psurface->split->len);
-
-  while (gts_psurface_remove_vertex (psurface))
-    ;
-  while (psurface->pos) {
-    GtsSplit * vs = g_ptr_array_index (psurface->split, psurface->pos - 1);
-    GtsHSplit * hs = gts_hsplit_new (hsplit_class, vs);
-
-    g_ptr_array_index (hsurface->split, psurface->pos - 1) = hs;
-    psurface->pos--;
-
-    hs->parent = GTS_OBJECT (vs)->reserved;
-    if (hs->parent) {
-      GtsSplit * vsp = GTS_SPLIT (hs->parent);
-
-      if (vsp->v1 == GTS_OBJECT (vs)) {
-	g_assert (vsp->v2 != GTS_OBJECT (vs));
-	vsp->v1 = GTS_OBJECT (hs);
-      }
-      else {
-	g_assert (vsp->v2 == GTS_OBJECT (vs));
-	vsp->v2 = GTS_OBJECT (hs);
-      }
-    }
-    else
-      hsurface->roots = g_slist_prepend (hsurface->roots, hs);
-
-    hs->nchild = 0;
-    if (GTS_IS_SPLIT (vs->v1))
-      GTS_OBJECT (vs->v1)->reserved = hs;
-    else
-      hs->nchild++;
-    if (GTS_IS_SPLIT (vs->v2))
-      GTS_OBJECT (vs->v2)->reserved = hs;
-    else
-      hs->nchild++;
-    
-    gts_split_expand (vs, psurface->s, psurface->s->edge_class);
-
-    if (hs->nchild == 2)
-      HEAP_INSERT_HSPLIT (hsurface->collapsable, hs);
-  }
-
-  hsurface->nvertex = gts_surface_vertex_number (hsurface->s);
-  gts_object_destroy (GTS_OBJECT (psurface));
-
-  return hsurface;
-}
-
-/**
- * gts_hsurface_traverse:
- * @hsurface: a #GtsHSurface.
- * @order: the order in which nodes are visited - G_PRE_ORDER or G_POST_ORDER.
- * @depth: the maximum depth of the traversal. Nodes below this depth
- * will not be visited. If max_depth is -1 all nodes in the tree are
- * visited. If depth is 1, only the root is visited. If depth is 2,
- * the root and its children are visited. And so on.
- * @func: the function to call for each visited #GtsHSplit.
- * @data: user data to pass to the function.
- *
- * Traverses a hierarchical surface starting from its roots. It calls
- * the given function for each #GtsHSplit visited. 
- * See also gts_split_traverse().
- */
-void gts_hsurface_traverse (GtsHSurface *    hsurface,
-			    GTraverseType    order,
-			    gint             depth,
-			    GtsSplitTraverseFunc func,
-			    gpointer         data)
-{
-  GSList * i;
-
-  g_return_if_fail (hsurface != NULL);
-  g_return_if_fail (func != NULL);
-  g_return_if_fail (order < G_LEVEL_ORDER);
-  g_return_if_fail (depth == -1 || depth > 0);
-
-  i = hsurface->roots;
-  while (i) {
-    gts_split_traverse (i->data, order, depth, func, data);
-    i = i->next;
-  }
-}
-
-/**
- * gts_hsurface_foreach:
- * @hsurface: a #GtsHSurface.
- * @order: the order in which #GtsHSplit are visited - G_PRE_ORDER or 
- * G_POST_ORDER.
- * @func: the function to call for each visited #GtsHSplit.
- * @data: user data to pass to the function.
- *
- * Starts by expanding all the #GtsHSplit of @hsurface. If @order is
- * G_PRE_ORDER, calls @func for each #GtsHSplit and collapses it. If
- * order is G_POST_ORDER, collapses each #GtsHSplit first and then
- * calls @func. The traversal can be halted at any point by returning
- * TRUE from func.  
- */
-void gts_hsurface_foreach (GtsHSurface * hsurface,
-			   GTraverseType order,
-			   GtsFunc       func,
-			   gpointer      data)
-{
-  GtsHSplit * hs;
-  guint i = 0, len;
-  gboolean stop = FALSE;
-
-  g_return_if_fail (hsurface != NULL);
-  g_return_if_fail (func != NULL);
-  g_return_if_fail (order == G_PRE_ORDER || order == G_POST_ORDER);
-
-  while ((hs = gts_eheap_top (hsurface->expandable, NULL))) 
-    gts_hsplit_expand (hs, hsurface);
-
-  len = hsurface->split->len;
-  switch (order) {
-  case G_PRE_ORDER:
-    while (i < len && !stop) {
-      GtsHSplit * hs = g_ptr_array_index (hsurface->split, i);
-      stop = (*func) (hs, data);
-      if (!stop)
-	gts_hsplit_collapse (hs, hsurface);
-      i++;
-    }
-    break;
-  case G_POST_ORDER:
-    while (i < len && !stop) {
-      GtsHSplit * hs = g_ptr_array_index (hsurface->split, i);
-      gts_hsplit_collapse (hs, hsurface);
-      stop = (*func) (hs, data);
-      i++;
-    }
-    break;
-  default:
-    g_assert_not_reached ();
-  }
-}
-
-/**
- * gts_hsurface_height:
- * @hsurface: a #GtsHSurface.
- *
- * Returns: the maximum height of the tree described by @hsurface.
- */
-guint gts_hsurface_height (GtsHSurface * hsurface)
-{
-  GSList * i;
-  guint height = 0;
-
-  g_return_val_if_fail (hsurface != NULL, 0);
-
-  i = hsurface->roots;
-  while (i) {
-    guint tmp_height = gts_split_height (i->data);
-    if (tmp_height > height)
-      height = tmp_height;
-    i = i->next;
-  }
-
-  return height;
-}
diff --git a/src_3rd/gts/iso.c b/src_3rd/gts/iso.c
deleted file mode 100644
index 5995a19..0000000
--- a/src_3rd/gts/iso.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-typedef enum { LEFT = 0, RIGHT = 1 } Orientation;
-
-typedef struct {
-  GtsVertex * v;
-  Orientation orientation;
-} OrientedVertex;
-
-struct _GtsIsoSlice {
-  OrientedVertex *** vertices;
-  guint nx, ny;
-};
-
-/* coordinates of the edges of the cube (see doc/isocube.fig) */
-static guint c[12][4] = {
-  {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 0},
-  {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 1, 0, 1}, {1, 1, 0, 0},
-  {2, 0, 0, 0}, {2, 1, 0, 0}, {2, 1, 1, 0}, {2, 0, 1, 0}};
-
-/* first index is the edge number, second index is the edge orientation 
-   (RIGHT or LEFT), third index are the edges which this edge may connect to
-   in order */
-static guint edge[12][2][3] = {
-  {{9, 1, 8}, {4, 3, 7}},   /* 0 */
-  {{6, 2, 5}, {8, 0, 9}},   /* 1 */
-  {{10, 3, 11}, {5, 1, 6}}, /* 2 */
-  {{7, 0, 4}, {11, 2, 10}}, /* 3 */
-  {{3, 7, 0}, {8, 5, 11}},  /* 4 */
-  {{11, 4, 8}, {1, 6, 2}},  /* 5 */
-  {{2, 5, 1}, {9, 7, 10}},  /* 6 */
-  {{10, 6, 9}, {0, 4, 3}},  /* 7 */
-  {{5, 11, 4}, {0, 9, 1}},  /* 8 */
-  {{1, 8, 0}, {7, 10, 6}},  /* 9 */
-  {{6, 9, 7}, {3, 11, 2}},  /* 10 */
-  {{2, 10, 3}, {4, 8, 5}}   /* 11 */
-};
-
-static void ** malloc2D (guint nx, guint ny, gulong size)
-{
-  void ** m = g_malloc (nx*sizeof (void *));
-  guint i;
-
-  for (i = 0; i < nx; i++)
-    m[i] = g_malloc0 (ny*size);
-
-  return m;
-}
-
-static void free2D (void ** m, guint nx)
-{
-  guint i;
-
-  g_return_if_fail (m != NULL);
-
-  for (i = 0; i < nx; i++)
-    g_free (m[i]);
-  g_free (m);
-}
-
-/**
- * gts_grid_plane_new:
- * @nx:
- * @ny:
- *
- * Returns:
- */
-GtsGridPlane * gts_grid_plane_new (guint nx, guint ny)
-{
-  GtsGridPlane * g = g_malloc (sizeof (GtsGridPlane));
-
-  g->p = (GtsPoint **) malloc2D (nx, ny, sizeof (GtsPoint));
-  g->nx = nx;
-  g->ny = ny;
-  
-  return g;
-}
-
-/**
- * gts_grid_plane_destroy:
- * @g:
- *
- */
-void gts_grid_plane_destroy (GtsGridPlane * g)
-{
-  g_return_if_fail (g != NULL);
-
-  free2D ((void **) g->p, g->nx);
-  g_free (g);
-}
-
-/**
- * gts_iso_slice_new:
- * @nx: number of vertices in the x direction.
- * @ny: number of vertices in the y direction.
- *
- * Returns: a new #GtsIsoSlice.
- */
-GtsIsoSlice * gts_iso_slice_new (guint nx, guint ny)
-{
-  GtsIsoSlice * slice;
-
-  g_return_val_if_fail (nx > 1, NULL);
-  g_return_val_if_fail (ny > 1, NULL);
-
-  slice = g_malloc (sizeof (GtsIsoSlice));
-
-  slice->vertices = g_malloc (3*sizeof (OrientedVertex **));
-  slice->vertices[0] = 
-    (OrientedVertex **) malloc2D (nx, ny, sizeof (OrientedVertex));
-  slice->vertices[1] = 
-    (OrientedVertex **) malloc2D (nx - 1, ny, sizeof (OrientedVertex));
-  slice->vertices[2] = 
-    (OrientedVertex **) malloc2D (nx, ny - 1, sizeof (OrientedVertex));
-  slice->nx = nx;
-  slice->ny = ny;
-
-  return slice;
-}
-
-/**
- * gts_iso_slice_fill:
- * @slice: a #GtsIsoSlice.
- * @plane1: a #GtsGridPlane.
- * @plane2: another #GtsGridPlane.
- * @f1: values of the function corresponding to @plane1.
- * @f2: values of the function corresponding to @plane2.
- * @iso: isosurface value.
- * @klass: a #GtsVertexClass or one of its descendant to be used for the 
- * new vertices.
- *
- * Fill @slice with the coordinates of the vertices defined by 
- * f1 (x,y,z) = @iso and f2 (x, y, z) = @iso.
- */
-void gts_iso_slice_fill (GtsIsoSlice * slice,
-			 GtsGridPlane * plane1,
-			 GtsGridPlane * plane2,
-			 gdouble ** f1,
-			 gdouble ** f2,
-			 gdouble iso,
-			 GtsVertexClass * klass)
-{
-  OrientedVertex *** vertices;
-  GtsPoint ** p1, ** p2 = NULL;
-  guint i, j, nx, ny;
-
-  g_return_if_fail (slice != NULL);
-  g_return_if_fail (plane1 != NULL);
-  g_return_if_fail (f1 != NULL);
-  g_return_if_fail (f2 == NULL || plane2 != NULL);
-
-  p1 = plane1->p;
-  if (plane2) 
-    p2 = plane2->p;
-  vertices = slice->vertices;
-  nx = slice->nx;
-  ny = slice->ny;
-
-  if (f2)
-    for (i = 0; i < nx; i++)
-      for (j = 0; j < ny; j++) {
-	gdouble v1 = f1[i][j] - iso;
-	gdouble v2 = f2[i][j] - iso;
-	if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
-	  gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
-	  vertices[0][i][j].v = 
-	    gts_vertex_new (klass,
-			    c1*p1[i][j].x + c2*p2[i][j].x,
-			    c1*p1[i][j].y + c2*p2[i][j].y,
-			    c1*p1[i][j].z + c2*p2[i][j].z);
-	  vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
-	}
-	else
-	  vertices[0][i][j].v = NULL;
-      }
-  for (i = 0; i < nx - 1; i++)
-    for (j = 0; j < ny; j++) {
-      gdouble v1 = f1[i][j] - iso;
-      gdouble v2 = f1[i+1][j] - iso;
-      if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
-	gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
-	vertices[1][i][j].v = 
-	  gts_vertex_new (klass,
-			  c1*p1[i][j].x + c2*p1[i+1][j].x,
-			  c1*p1[i][j].y + c2*p1[i+1][j].y,
-			  c1*p1[i][j].z + c2*p1[i+1][j].z);
-	vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
-      }
-      else
-	vertices[1][i][j].v = NULL;
-    }
-  for (i = 0; i < nx; i++)
-    for (j = 0; j < ny - 1; j++) {
-      gdouble v1 = f1[i][j] - iso;
-      gdouble v2 = f1[i][j+1] - iso;
-      if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
-	gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
-	vertices[2][i][j].v = 
-	  gts_vertex_new (klass,
-			  c1*p1[i][j].x + c2*p1[i][j+1].x,
-			  c1*p1[i][j].y + c2*p1[i][j+1].y,
-			  c1*p1[i][j].z + c2*p1[i][j+1].z);
-	vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
-      }
-      else
-	vertices[2][i][j].v = NULL;
-    }
-}
- 
-/**
- * gts_iso_slice_fill_cartesian:
- * @slice: a #GtsIsoSlice.
- * @g: a #GtsCartesianGrid.
- * @f1: values of the function for plane z = @g.z.
- * @f2: values of the function for plane z = @g.z + @g.dz.
- * @iso: isosurface value.
- * @klass: a #GtsVertexClass.
- *
- * Fill @slice with the coordinates of the vertices defined by 
- * f1 (x,y,z) = @iso and f2 (x, y, z) = @iso.
- */
-void gts_iso_slice_fill_cartesian (GtsIsoSlice * slice,
-				   GtsCartesianGrid g,
-				   gdouble ** f1,
-				   gdouble ** f2,
-				   gdouble iso,
-				   GtsVertexClass * klass)
-{
-  OrientedVertex *** vertices;
-  guint i, j;
-  gdouble x, y;
-
-  g_return_if_fail (slice != NULL);
-  g_return_if_fail (f1 != NULL);
-
-  vertices = slice->vertices;
-
-  if (f2)
-    for (i = 0, x = g.x; i < g.nx; i++, x += g.dx)
-      for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) {
-	gdouble v1 = f1[i][j] - iso;
-	gdouble v2 = f2[i][j] - iso;
-	if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
-	  vertices[0][i][j].v = 
-	    gts_vertex_new (klass,
-			    x, y, g.z + g.dz*v1/(v1 - v2));
-	  vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
-	}
-	else
-	  vertices[0][i][j].v = NULL;
-      }
-  for (i = 0, x = g.x; i < g.nx - 1; i++, x += g.dx)
-    for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) {
-      gdouble v1 = f1[i][j] - iso;
-      gdouble v2 = f1[i+1][j] - iso;
-      if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
-	vertices[1][i][j].v = 
-	  gts_vertex_new (klass, x + g.dx*v1/(v1 - v2), y, g.z);
-	vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
-      }
-      else
-	vertices[1][i][j].v = NULL;
-    }
-  for (i = 0, x = g.x; i < g.nx; i++, x += g.dx)
-    for (j = 0, y = g.y; j < g.ny - 1; j++, y += g.dy) {
-      gdouble v1 = f1[i][j] - iso;
-      gdouble v2 = f1[i][j+1] - iso;
-      if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
-	vertices[2][i][j].v = 
-	  gts_vertex_new (klass, x, y + g.dy*v1/(v1 - v2), g.z);
-	vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
-      }
-      else
-	vertices[2][i][j].v = NULL;
-    }
-}
-
-/**
- * gts_iso_slice_destroy:
- * @slice: a #GtsIsoSlice.
- *
- * Free all memory allocated for @slice.
- */
-void gts_iso_slice_destroy (GtsIsoSlice * slice)
-{
-  g_return_if_fail (slice != NULL);
-
-  free2D ((void **) slice->vertices[0], slice->nx);
-  free2D ((void **) slice->vertices[1], slice->nx - 1);
-  free2D ((void **) slice->vertices[2], slice->nx);  
-  g_free (slice->vertices);
-  g_free (slice);
-}
-
-/**
- * gts_isosurface_slice:
- * @slice1: a #GtsIsoSlice.
- * @slice2: another #GtsIsoSlice.
- * @surface: a #GtsSurface.
- *
- * Given two successive slices @slice1 and @slice2 link their vertices with
- * segments and triangles which are added to @surface.
- */
-void gts_isosurface_slice (GtsIsoSlice * slice1,
-			   GtsIsoSlice * slice2,
-			   GtsSurface * surface)
-{
-  guint j, k, l, nx, ny;
-  OrientedVertex *** vertices[2];
-  GtsVertex * va[12];
-
-  g_return_if_fail (slice1 != NULL);
-  g_return_if_fail (slice2 != NULL);
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (slice1->nx == slice2->nx && slice1->ny == slice2->ny);
-
-  vertices[0] = slice1->vertices;
-  vertices[1] = slice2->vertices;
-  nx = slice1->nx;
-  ny = slice1->ny;
-
-  /* link vertices with segments and triangles */
-  for (j = 0; j < nx - 1; j++)
-    for (k = 0; k < ny - 1; k++) {
-      gboolean cube_is_cut = FALSE;
-      for (l = 0; l < 12; l++) {
-	guint nv = 0, e = l;
-	OrientedVertex ov = 
-	  vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]];
-	while (ov.v && !GTS_OBJECT (ov.v)->reserved) {
-	  guint m = 0, * ne = edge[e][ov.orientation];
-	  va[nv++] = ov.v;
-	  GTS_OBJECT (ov.v)->reserved = surface;
-	  ov.v = NULL;
-	  while (m < 3 && !ov.v) {
-	    e = ne[m++];
-	    ov = vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]];
-	  }
-	}
-	/* create edges and faces */
-	if (nv > 2) {
-	  GtsEdge * e1, * e2, * e3;
-	  guint m;
-	  if (!(e1 = GTS_EDGE (gts_vertices_are_connected (va[0], va[1]))))
-	    e1 = gts_edge_new (surface->edge_class, va[0], va[1]);
-	  for (m = 1; m < nv - 1; m++) {
-	    if (!(e2 = GTS_EDGE (gts_vertices_are_connected (va[m], va[m+1]))))
-	      e2 = gts_edge_new (surface->edge_class, va[m], va[m+1]);
-	    if (!(e3 = GTS_EDGE (gts_vertices_are_connected (va[m+1], va[0]))))
-	      e3 = gts_edge_new (surface->edge_class, va[m+1], va[0]);
-	    gts_surface_add_face (surface, 
-				  gts_face_new (surface->face_class,
-						e1, e2, e3));
-	    e1 = e3;
-	  }
-	}
-	if (nv > 0)
-	  cube_is_cut = TRUE;
-      }
-      if (cube_is_cut)
-	for (l = 0; l < 12; l++) {
-	  GtsVertex * v = 
-	    vertices[c[l][1]][c[l][0]][j + c[l][2]][k + c[l][3]].v;
-	  if (v)
-	    GTS_OBJECT (v)->reserved = NULL;
-	}
-    }
-}
-
-#define SWAP(s1, s2, tmp) (tmp = s1, s1 = s2, s2 = tmp)
-
-/**
- * gts_isosurface_cartesian:
- * @surface: a #GtsSurface.
- * @g: a #GtsCartesianGrid.
- * @f: a #GtsIsoCartesianFunc.
- * @data: user data to be passed to @f.
- * @iso: isosurface value.
- *
- * Adds to @surface new faces defining the isosurface f(x,y,z) = @iso. By
- * convention, the normals to the surface are pointing toward the positive
- * values of f(x,y,z) - @iso.
- *
- * The user function @f is called successively for each value of the z 
- * coordinate defined by @g. It must fill the corresponding (x,y) plane with
- * the values of the function for which the isosurface is to be computed.
- */
-void gts_isosurface_cartesian (GtsSurface * surface,
-			       GtsCartesianGrid g,
-			       GtsIsoCartesianFunc f,
-			       gpointer data,
-			       gdouble iso)
-{
-  void * tmp;
-  gdouble ** f1, ** f2;
-  GtsIsoSlice * slice1, * slice2;
-  guint i;
-
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (g.nx > 1);
-  g_return_if_fail (g.ny > 1);
-  g_return_if_fail (g.nz > 1);
-
-  slice1 = gts_iso_slice_new (g.nx, g.ny);
-  slice2 = gts_iso_slice_new (g.nx, g.ny);
-  f1 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble));
-  f2 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble));
-
-  (*f) (f1, g, 0, data);
-  g.z += g.dz;
-  (*f) (f2, g, 1, data);
-  g.z -= g.dz;
-  gts_iso_slice_fill_cartesian (slice1, g, f1, f2, iso, 
-				surface->vertex_class);
-  g.z += g.dz;
-  for (i = 2; i < g.nz; i++) {
-    g.z += g.dz;
-    (*f) (f1, g, i, data);
-    SWAP (f1, f2, tmp);
-    g.z -= g.dz;
-    gts_iso_slice_fill_cartesian (slice2, g, f1, f2, iso, 
-				  surface->vertex_class);
-    g.z += g.dz;
-    gts_isosurface_slice (slice1, slice2, surface);
-    SWAP (slice1, slice2, tmp);
-  }
-  gts_iso_slice_fill_cartesian (slice2, g, f2, NULL, iso,
-				surface->vertex_class);
-  gts_isosurface_slice (slice1, slice2, surface);
-
-  gts_iso_slice_destroy (slice1);
-  gts_iso_slice_destroy (slice2);
-  free2D ((void **) f1, g.nx);
-  free2D ((void **) f2, g.nx);
-}
diff --git a/src_3rd/gts/isotetra.c b/src_3rd/gts/isotetra.c
deleted file mode 100644
index 35fe2ba..0000000
--- a/src_3rd/gts/isotetra.c
+++ /dev/null
@@ -1,840 +0,0 @@
-/* GTS-Library conform marching tetrahedra algorithm 
- * Copyright (C) 2002 Gert Wollny
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include <string.h>
-#include <gts.h>
-#ifdef NATIVE_WIN32
-# include <memory.h>
-# define M_SQRT2		1.41421356237309504880
-#endif /* NATIVE_WIN32 */
-
-typedef struct {
-  gint nx, ny; 
-  gdouble ** data; 
-} slice_t;
-
-typedef struct {
-  gint x, y, z;
-  gboolean mid;
-  gdouble d; 
-} tetra_vertex_t; 
-
-/* this helper is a lookup table for vertices */
-typedef struct {
-  gint nx, ny; 
-  GtsVertex ** vtop, ** vmid, **vbot;
-} helper_t ;
-
-typedef struct {
-  GHashTable * vbot, * vtop;
-} helper_bcl ;
-
-
-static helper_t * init_helper (int nx, int ny) 
-{
-  gint nxy = 4*nx*ny; 
-  helper_t *retval = g_malloc0 (sizeof (helper_t));
-
-  retval->nx = nx; 
-  retval->ny = ny; 
-  retval->vtop = g_malloc0 (sizeof (GtsVertex *)*nxy);
-  retval->vmid = g_malloc0 (sizeof (GtsVertex *)*nxy);
-  retval->vbot = g_malloc0 (sizeof (GtsVertex *)*nxy);
-  return retval;
-}
-
-static helper_bcl * init_helper_bcl (void)
-{
-  helper_bcl *retval = g_malloc0 (sizeof (helper_bcl));
-
-  retval->vtop = g_hash_table_new (g_str_hash, g_str_equal);
-  retval->vbot = g_hash_table_new (g_str_hash, g_str_equal);
-  return retval;
-}
-
-static void free_helper (helper_t * h) 
-{
-  g_free (h->vtop);
-  g_free (h->vmid);
-  g_free (h->vbot);
-  g_free (h);
-}
-
-static void free_helper_bcl (helper_bcl * h) 
-{
-  g_hash_table_destroy (h->vtop);
-  g_hash_table_destroy (h->vbot);
-  g_free (h);
-}
-
-/* move the vertices in the bottom slice to the top, and clear the
-   other slices in the lookup tables */
-static void helper_advance (helper_t * h) 
-{
-  GtsVertex ** help = h->vbot;
-  h->vbot = h->vtop; 
-  h->vtop = help;
-  
-  memset (h->vmid, 0, 4*sizeof(GtsVertex *) * h->nx * h->ny);
-  memset (h->vbot, 0, 4*sizeof(GtsVertex *) * h->nx * h->ny);
-}
-
-static void helper_advance_bcl (helper_bcl * h) 
-{
-  GHashTable * help = g_hash_table_new (g_str_hash, g_str_equal);
-
-  g_hash_table_destroy (h->vbot);
-  h->vbot = h->vtop;
-  h->vtop = help;
-}
-
-/* find the zero-crossing of line through v1 and v2 and return the
-   corresponding GtsVertex */
-static GtsVertex * get_vertex (gint mz, 
-			       const tetra_vertex_t * v1, 
-			       const tetra_vertex_t * v2, 
-			       helper_t * help, 
-			       GtsCartesianGrid * g,
-			       GtsVertexClass * klass)
-{
-  GtsVertex ** vertex; 
-  gint x, y, index, idx2, z; 
-  gdouble dx, dy, dz, d; 
-
-  g_assert (v1->d - v2->d != 0.);
-  
-  dx = dy = dz = 0.0;
-  d = v1->d/(v1->d - v2->d);
-
-  index = 0;
-  
-  if (v1->x != v2->x) {
-    index |= 1;
-    dx = d;
-  }
-  
-  if (v1->y != v2->y) {
-    index |= 2;
-    dy = d;
-  }
-  
-  if (v1->z != v2->z) {
-    dz = d;
-  }
-
-  x = v1->x;
-  if (v1->x > v2->x) {  x = v2->x; dx = 1.0 - dx; }
-  
-  y = v1->y;
-  if (v1->y > v2->y) {  y = v2->y; dy = 1.0 - dy;}
-  
-  z = v1->z;
-  if (v1->z > v2->z) {  z = v2->z; dz = 1.0 - dz;}
-  
-  idx2 = 4 * ( x + y * help->nx ) + index;
-  
-  if (v1->z == v2->z)
-    vertex = (mz == z) ? &help->vtop[idx2] : &help->vbot[idx2];
-  else
-    vertex = &help->vmid[idx2];
-  
-  if (mz != z && dz != 0.0) {
-    fprintf(stderr, "%f \n", dz);
-  }
-  
-  /* if vertex is not yet created, do it now */
-  if (!*vertex)
-    *vertex = gts_vertex_new (klass,
-			      g->dx * ( x + dx) + g->x, 
-			      g->dy * ( y + dy) + g->y, 
-			      g->dz * ( z + dz) + g->z);
-  
-  return *vertex;
-}
-
-static GtsVertex * get_vertex_bcl (gint mz, 
-				   const tetra_vertex_t * v1, 
-				   const tetra_vertex_t * v2, 
-				   helper_bcl * help, 
-				   GtsCartesianGrid * g,
-				   GtsVertexClass * klass)
-{
-  GtsVertex * v;
-  GHashTable * table;
-  gchar * s1, * s2, * hash;
-  gdouble x1, x2, y1, y2, z1, z2, d;
-
-  g_assert (v1->d - v2->d != 0.);
-
-  /* first find correct hash table */  
-  if ((v1->z > mz) && (v2->z > mz))
-    table = help->vtop;
-  else
-    table = help->vbot;
-
-  d = v1->d / (v1->d - v2->d);
-
-  /* sort vertices */
-  s1 = g_strdup_printf ("%d %d %d %d", v1->x, v1->y, v1->z, v1->mid);
-  s2 = g_strdup_printf ("%d %d %d %d", v2->x, v2->y, v2->z, v2->mid);
-
-  hash = (d == 0.0) ? g_strdup (s1) :
-    (d == 1.0) ? g_strdup (s2) :
-    (strcmp (s1, s2) < 0) ? g_strjoin (" ", s1, s2, NULL) :
-    g_strjoin (" ", s2, s1, NULL);
-
-  /* return existing vertex or make a new one */
-  v = g_hash_table_lookup (table, hash);
-  if (!v){
-
-    x1 = g->dx * (v1->x + (v1->mid / 2.0)) + g->x;
-    x2 = g->dx * (v2->x + (v2->mid / 2.0)) + g->x;
-    y1 = g->dy * (v1->y + (v1->mid / 2.0)) + g->y;
-    y2 = g->dy * (v2->y + (v2->mid / 2.0)) + g->y;
-    z1 = g->dz * (v1->z + (v1->mid / 2.0)) + g->z;
-    z2 = g->dz * (v2->z + (v2->mid / 2.0)) + g->z;
-
-    v = gts_vertex_new (klass, x1 * (1.0 - d) + d * x2,
-			y1 * (1.0 - d) + d * y2,
-			z1 * (1.0 - d) + d * z2);
-
-    g_hash_table_insert (table, g_strdup(hash), v);
-  }
-  g_free (s1);
-  g_free (s2);
-  g_free (hash);
-
-  return v;
-}
-
-/* create an edge connecting the zero crossings of lines through a
-   pair of vertices, or return an existing one */
-static GtsEdge * get_edge (GtsVertex * v1, GtsVertex * v2,
-			   GtsEdgeClass * klass)
-{
-  GtsSegment *s;
-  GtsEdge *edge; 
-  
-  g_assert (v1);
-  g_assert (v2);
-  
-  s = gts_vertices_are_connected (v1, v2);
-  
-  if (GTS_IS_EDGE (s))
-    edge = GTS_EDGE(s);
-  else
-    edge = gts_edge_new (klass, v1, v2);
-  return edge; 
-}
-
-static void add_face (GtsSurface * surface, 
-		      const tetra_vertex_t * a1, const tetra_vertex_t * a2, 
-		      const tetra_vertex_t * b1, const tetra_vertex_t * b2, 
-		      const tetra_vertex_t * c1, const tetra_vertex_t * c2, 
-		      gint rev, helper_t * help, 
-		      gint z, GtsCartesianGrid * g)
-{
-  GtsFace * t; 
-  GtsEdge * e1, * e2, * e3; 	
-  GtsVertex * v1 = get_vertex (z, a1, a2, help, g, surface->vertex_class);
-  GtsVertex * v2 = get_vertex (z, b1, b2, help, g, surface->vertex_class);
-  GtsVertex * v3 = get_vertex (z, c1, c2, help, g, surface->vertex_class);
-
-  g_assert (v1 != v2);
-  g_assert (v2 != v3);
-  g_assert (v1 != v3);
-
-  if (!rev) {
-    e1 = get_edge (v1, v2, surface->edge_class);
-    e2 = get_edge (v2, v3, surface->edge_class);
-    e3 = get_edge (v1, v3, surface->edge_class);
-  } else {
-    e1 = get_edge (v1, v3, surface->edge_class);
-    e2 = get_edge (v2, v3, surface->edge_class);
-    e3 = get_edge (v1, v2, surface->edge_class);	
-  }
-  
-  t = gts_face_new (surface->face_class, e1, e2, e3);	
-  gts_surface_add_face (surface, t);
-}
-
-static void add_face_bcl (GtsSurface * surface, 
-			  const tetra_vertex_t * a1, 
-			  const tetra_vertex_t * a2, 
-			  const tetra_vertex_t * b1, 
-			  const tetra_vertex_t * b2, 
-			  const tetra_vertex_t * c1, 
-			  const tetra_vertex_t * c2, 
-			  gint rev, helper_bcl * help, 
-			  gint z, GtsCartesianGrid * g)
-{
-  GtsFace * t; 
-  GtsEdge * e1, * e2, * e3; 	
-  GtsVertex * v1 = get_vertex_bcl (z, a1, a2, help, g, surface->vertex_class);
-  GtsVertex * v2 = get_vertex_bcl (z, b1, b2, help, g, surface->vertex_class);
-  GtsVertex * v3 = get_vertex_bcl (z, c1, c2, help, g, surface->vertex_class);
-
-  if (v1 == v2 || v2 == v3 || v1 == v3)
-    return;
-
-  if (!rev) {
-    e1 = get_edge (v1, v2, surface->edge_class);
-    e2 = get_edge (v2, v3, surface->edge_class);
-    e3 = get_edge (v1, v3, surface->edge_class);
-  } else {
-    e1 = get_edge (v1, v3, surface->edge_class);
-    e2 = get_edge (v2, v3, surface->edge_class);
-    e3 = get_edge (v1, v2, surface->edge_class);	
-  }
-
-  t = gts_face_new (surface->face_class, e1, e2, e3);	
-  gts_surface_add_face (surface, t);
-}
-
-/* create a new slice of site nx \times ny */
-static slice_t * new_slice (gint nx, gint ny) 
-{
-  gint x; 
-  slice_t * retval = g_malloc (sizeof (slice_t));
-
-  retval->data = g_malloc (nx*sizeof(gdouble *));
-  retval->nx = nx;
-  retval->ny = ny;  
-  for (x = 0; x < nx; x++) 
-    retval->data[x] = g_malloc (ny*sizeof (gdouble));
-  return retval; 
-}
-
-/* initialize a slice with inival */
-static void slice_init (slice_t * slice, gdouble inival)
-{
-  gint x, y; 
-  
-  g_assert (slice);
-	
-  for (x = 0; x < slice->nx; x++) 
-    for (y = 0; y < slice->ny; y++)
-      slice->data[x][y] = inival; 
-}
-
-/* free the memory of a slice */
-static void free_slice (slice_t * slice) 
-{
-  gint x; 
-	
-  g_return_if_fail (slice != NULL);
-	
-  for (x = 0; x < slice->nx; x++) 
-    g_free (slice->data[x]);  
-  g_free (slice->data);
-  g_free (slice);
-}
-
-static void analyze_tetrahedra (const tetra_vertex_t * a, 
-				const tetra_vertex_t * b, 
-				const tetra_vertex_t * c, 
-				const tetra_vertex_t * d, 
-				gint parity, GtsSurface * surface, 
-				helper_t * help, 
-				gint z, GtsCartesianGrid * g)
-{
-  gint rev = parity; 
-  gint code = 0; 
-	
-  if (a->d >= 0.) code |= 1; 
-  if (b->d >= 0.) code |= 2; 
-  if (c->d >= 0.) code |= 4; 
-  if (d->d >= 0.) code |= 8;
-		
-  switch (code) {
-  case 15:
-  case 0: return; /* all inside or outside */		
-  
-  case 14:rev = !parity;
-  case  1:add_face (surface, a, b, a, d, a, c, rev, help, z, g);
-	  break;
-  case 13:rev = ! parity;  
-  case  2:add_face (surface, a, b, b, c, b, d, rev, help, z, g);
-	  break;
-  case 12:rev = !parity;	  
-  case  3:add_face (surface, a, d, a, c, b, c, rev, help, z, g);
-	  add_face (surface, a, d, b, c, b, d, rev, help, z, g);
-	  break;
-  case 11:rev = !parity;	  
-  case  4:add_face (surface, a, c, c, d, b, c, rev, help, z, g);
-	  break;
-  case 10:rev = !parity; 	  
-  case 5: add_face (surface, a, b, a, d, c, d, rev, help, z, g);
-	  add_face (surface, a, b, c, d, b, c, rev, help, z, g);
-	  break;	
-  case  9:rev = !parity; 
-  case  6:add_face (surface, a, b, a, c, c, d, rev, help, z, g);
-	  add_face (surface, a, b, c, d, b, d, rev, help, z, g);
-	  break;
-  case  7:rev = !parity;
-  case  8:add_face (surface, a, d, b, d, c, d, rev, help, z, g);
-    break; 
-  }
-}
-
-static void analyze_tetrahedra_bcl (const tetra_vertex_t * a, 
-				    const tetra_vertex_t * b, 
-				    const tetra_vertex_t * c, 
-				    const tetra_vertex_t * d, 
-				    GtsSurface * surface, 
-				    helper_bcl * help, 
-				    gint z, GtsCartesianGrid * g)
-{
-  gint rev = 0;
-  gint code = 0; 
-	
-  if (a->d >= 0.) code |= 1; 
-  if (b->d >= 0.) code |= 2; 
-  if (c->d >= 0.) code |= 4; 
-  if (d->d >= 0.) code |= 8;
-
-  switch (code) {
-  case 15:
-  case 0: return; /* all inside or outside */		
-
-  case 14:rev = !rev;
-  case  1:add_face_bcl (surface, a, b, a, d, a, c, rev, help, z, g);
-	  break;
-  case 13:rev = !rev;  
-  case  2:add_face_bcl (surface, a, b, b, c, b, d, rev, help, z, g);
-	  break;
-  case 12:rev = !rev;	  
-  case  3:add_face_bcl (surface, a, d, a, c, b, c, rev, help, z, g);
-	  add_face_bcl (surface, a, d, b, c, b, d, rev, help, z, g);
-	  break;
-  case 11:rev = !rev;	  
-  case  4:add_face_bcl (surface, a, c, c, d, b, c, rev, help, z, g);
-	  break;
-  case 10:rev = !rev; 	  
-  case 5: add_face_bcl (surface, a, b, a, d, c, d, rev, help, z, g);
-	  add_face_bcl (surface, a, b, c, d, b, c, rev, help, z, g);
-	  break;	
-  case  9:rev = !rev; 
-  case  6:add_face_bcl (surface, a, b, a, c, c, d, rev, help, z, g);
-	  add_face_bcl (surface, a, b, c, d, b, d, rev, help, z, g);
-	  break;
-  case  7:rev = !rev;
-  case  8:add_face_bcl (surface, a, d, b, d, c, d, rev, help, z, g);
-    break;
-  }
-}
-
-static void  iso_slice_evaluate (slice_t * s1, slice_t * s2, 
-				 GtsCartesianGrid g, 
-				 gint z, GtsSurface * surface, helper_t * help)
-{
-  gint x,y; 
-  tetra_vertex_t v0, v1, v2, v3, v4, v5, v6, v7; 
-  gdouble ** s1p = s1->data; 
-  gdouble ** s2p = s2->data; 
-	
-  for (y = 0; y < g.ny-1; y++)
-    for (x = 0; x < g.nx-1; x++) {
-      gint parity = (((x ^ y) ^ z) & 1);
-      
-      v0.x = x  ; v0.y = y  ; v0.z = z  ; v0.mid = FALSE; v0.d = s1p[x  ][y  ];
-      v1.x = x  ; v1.y = y+1; v1.z = z  ; v1.mid = FALSE; v1.d = s1p[x  ][y+1];
-      v2.x = x+1; v2.y = y  ; v2.z = z  ; v2.mid = FALSE; v2.d = s1p[x+1][y  ];
-      v3.x = x+1; v3.y = y+1; v3.z = z  ; v3.mid = FALSE; v3.d = s1p[x+1][y+1];
-      v4.x = x  ; v4.y = y  ; v4.z = z+1; v4.mid = FALSE; v4.d = s2p[x  ][y  ];
-      v5.x = x  ; v5.y = y+1; v5.z = z+1; v5.mid = FALSE; v5.d = s2p[x  ][y+1];
-      v6.x = x+1; v6.y = y  ; v6.z = z+1; v6.mid = FALSE; v6.d = s2p[x+1][y  ];
-      v7.x = x+1; v7.y = y+1; v7.z = z+1; v7.mid = FALSE; v7.d = s2p[x+1][y+1];
-      
-      if (parity == 0) {
-	analyze_tetrahedra (&v0, &v1, &v2, &v4, parity, surface, help, z, &g);
-	analyze_tetrahedra (&v7, &v1, &v4, &v2, parity, surface, help, z, &g);
-	analyze_tetrahedra (&v1, &v7, &v3, &v2, parity, surface, help, z, &g);
-	analyze_tetrahedra (&v1, &v7, &v4, &v5, parity, surface, help, z, &g);
-	analyze_tetrahedra (&v2, &v6, &v4, &v7, parity, surface, help, z, &g);
-      }else{
-	analyze_tetrahedra (&v4, &v5, &v6, &v0, parity, surface, help, z, &g);
-	analyze_tetrahedra (&v3, &v5, &v0, &v6, parity, surface, help, z, &g);
-	analyze_tetrahedra (&v5, &v3, &v7, &v6, parity, surface, help, z, &g);
-	analyze_tetrahedra (&v5, &v3, &v0, &v1, parity, surface, help, z, &g);
-	analyze_tetrahedra (&v6, &v2, &v0, &v3, parity, surface, help, z, &g);
-      }
-    }
-}
-
-static void  iso_slice_evaluate_bcl (slice_t * s1, slice_t * s2, slice_t * s3,
-				     GtsCartesianGrid g, 
-				     gint z, GtsSurface * surface, 
-				     helper_bcl * help)
-{
-  gint x,y; 
-  tetra_vertex_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, w0; 
-  gdouble ** s1p = s1->data;
-  gdouble ** s2p = s2->data;
-  gdouble ** s3p = s3->data;
-	
-  for (y = 0; y < g.ny-2; y++)
-    for (x = 0; x < g.nx-2; x++) {
-      v0.x = x  ; v0.y = y  ; v0.z = z  ; v0.mid = TRUE;
-      v0.d = (s1p[x  ][y  ] + s2p[x  ][y  ] +
-	      s1p[x  ][y+1] + s2p[x  ][y+1] +
-	      s1p[x+1][y  ] + s2p[x+1][y  ] +
-	      s1p[x+1][y+1] + s2p[x+1][y+1])/8.0;
-
-      v1.x = x+1; v1.y = y  ; v1.z = z  ; v1.mid = TRUE;
-      v1.d = (s1p[x+1][y  ] + s2p[x+1][y  ] +
-	      s1p[x+1][y+1] + s2p[x+1][y+1] +
-	      s1p[x+2][y  ] + s2p[x+2][y  ] +
-	      s1p[x+2][y+1] + s2p[x+2][y+1])/8.0;
-
-      v2.x = x  ; v2.y = y+1; v2.z = z  ; v2.mid = TRUE;
-      v2.d = (s1p[x  ][y+1] + s2p[x  ][y+1] +
-	      s1p[x  ][y+2] + s2p[x  ][y+2] +
-	      s1p[x+1][y+1] + s2p[x+1][y+1] +
-	      s1p[x+1][y+2] + s2p[x+1][y+2])/8.0;
-
-      v3.x = x  ; v3.y = y  ; v3.z = z+1; v3.mid = TRUE;
-      v3.d = (s2p[x  ][y  ] + s3p[x  ][y  ] +
-	      s2p[x  ][y+1] + s3p[x  ][y+1] +
-	      s2p[x+1][y  ] + s3p[x+1][y  ] +
-	      s2p[x+1][y+1] + s3p[x+1][y+1])/8.0;
-
-      v4.x = x+1; v4.y = y  ; v4.z = z  ; v4.mid = FALSE; v4.d = s1p[x+1][y  ];
-      v5.x = x  ; v5.y = y+1; v5.z = z  ; v5.mid = FALSE; v5.d = s1p[x  ][y+1];
-      v6.x = x+1; v6.y = y+1; v6.z = z  ; v6.mid = FALSE; v6.d = s1p[x+1][y+1];
-      v7.x = x+1; v7.y = y  ; v7.z = z+1; v7.mid = FALSE; v7.d = s2p[x+1][y  ];
-      v8.x = x  ; v8.y = y+1; v8.z = z+1; v8.mid = FALSE; v8.d = s2p[x  ][y+1];
-      v9.x = x+1; v9.y = y+1; v9.z = z+1; v9.mid = FALSE; v9.d = s2p[x+1][y+1];
-      w0.x = x  ; w0.y = y  ; w0.z = z+1; w0.mid = FALSE; w0.d = s2p[x  ][y  ];
-
-      analyze_tetrahedra_bcl (&v0, &v9, &v6, &v1, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v6, &v4, &v1, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v4, &v7, &v1, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v7, &v9, &v1, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v5, &v6, &v2, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v6, &v9, &v2, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v9, &v8, &v2, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v8, &v5, &v2, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v8, &v9, &v3, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v9, &v7, &v3, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &v7, &w0, &v3, surface, help, z, &g);
-      analyze_tetrahedra_bcl (&v0, &w0, &v8, &v3, surface, help, z, &g);
-    }
-}
-
-/*  copy src into dest by stripping off the iso value and leave out
-    the boundary (which should be G_MINDOUBLE) */
-static void copy_to_bounded (slice_t * dest, slice_t * src, 
-			     gdouble iso, gdouble fill)
-{
-  gint x,y; 
-  gdouble * src_ptr;
-  gdouble * dest_ptr = dest->data[0];
-  
-  g_assert(dest->ny == src->ny + 2);
-  g_assert(dest->nx == src->nx + 2);
-	
-  for (y = 0; y < dest->ny; ++y, ++dest_ptr)
-    *dest_ptr = fill; 
-	
-  for (x = 1; x < src->nx - 1; ++x) {
-    dest_ptr = dest->data[x];
-    src_ptr = src->data[x-1];
-    *dest_ptr++ = fill;
-    for (y = 0; y < src->ny; ++y, ++dest_ptr, ++src_ptr)
-      *dest_ptr  = *src_ptr - iso;
-    *dest_ptr++ = fill; 
-  }
-  
-  dest_ptr = dest->data[y];
-  
-  for (y = 0; y < dest->ny; ++y, ++dest_ptr)
-    *dest_ptr = fill; 
-}
-
-static void iso_sub (slice_t * s, gdouble iso)
-{
-  gint x,y; 
-
-  for (x = 0; x < s->nx; ++x) {
-    gdouble *ptr = s->data[x];
-
-    for (y = 0; y < s->ny; ++y, ++ptr)
-      *ptr -= iso; 
-  }
-}
-
-
-/**
- * gts_isosurface_tetra_bounded:
- * @surface: a #GtsSurface.
- * @g: a #GtsCartesianGrid.
- * @f: a #GtsIsoCartesianFunc.
- * @data: user data to be passed to @f.
- * @iso: isosurface value.
- *
- * Adds to @surface new faces defining the isosurface f(x,y,z) =
- * @iso. By convention, the normals to the surface are pointing toward
- * the positive values of f(x,y,z) - @iso. To ensure a closed object,
- * a boundary of G_MINDOUBLE is added around the domain
- *
- * The user function @f is called successively for each value of the z
- * coordinate defined by @g. It must fill the corresponding (x,y)
- * plane with the values of the function for which the isosurface is
- * to be computed.  
- */
-void gts_isosurface_tetra_bounded (GtsSurface * surface,
-				   GtsCartesianGrid g,
-				   GtsIsoCartesianFunc f,
-				   gpointer data,
-				   gdouble iso)
-{
-  slice_t *slice1, *slice2, *transfer_slice; 
-  GtsCartesianGrid g_intern = g; 
-  helper_t *helper;
-  gint z; 
-	
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (g.nx > 1);
-  g_return_if_fail (g.ny > 1);
-  g_return_if_fail (g.nz > 1);
-
-  /* create the helper slices */
-  slice1 = new_slice (g.nx + 2, g.ny + 2);
-  slice2 = new_slice (g.nx + 2, g.ny + 2);
-	
-  /*  initialize the first slice as OUTSIDE */
-  slice_init (slice1, -1.0);
-	
-  /* create a slice of the original image size */
-  transfer_slice = new_slice (g.nx, g.ny);
-	
-  /* adapt the parameters to our enlarged image */
-  g_intern.x -= g.dx;
-  g_intern.y -= g.dy; 
-  g_intern.z -= g.dz;
-  g_intern.nx = g.nx + 2;
-  g_intern.ny = g.ny + 2; 	
-  g_intern.nz = g.nz;
-	
-  /* create the helper for vertex-lookup */
-  helper = init_helper (g_intern.nx, g_intern.ny);
-	
-  /* go slicewise through the data */
-  z = 0; 
-  while (z < g.nz) {
-    slice_t * hs; 
-    
-    /* request slice */
-    f (transfer_slice->data, g, z, data);
-    g.z += g.dz; 
-    
-    /* copy slice in enlarged image and mark the border as OUTSIDE */
-    copy_to_bounded (slice2, transfer_slice, iso, -1.);
-    
-    /* triangulate */
-    iso_slice_evaluate (slice1, slice2, g_intern, z, surface, helper);
-    
-    /* switch the input slices */
-    hs = slice1; slice1 = slice2; slice2 = hs; 
-    
-    /* switch the vertex lookup tables */
-    helper_advance(helper);
-    ++z; 
-  }
-  
-  /* initialize the last slice as OUTSIDE */
-  slice_init (slice2, - 1.0);
-		
-  /* close the object */
-  iso_slice_evaluate(slice1, slice2, g_intern, z, surface, helper);
-  
-  free_helper (helper);
-  free_slice (slice1);
-  free_slice (slice2);
-  free_slice (transfer_slice);	
-}
-
-/**
- * gts_isosurface_tetra:
- * @surface: a #GtsSurface.
- * @g: a #GtsCartesianGrid.
- * @f: a #GtsIsoCartesianFunc.
- * @data: user data to be passed to @f.
- * @iso: isosurface value.
- *
- * Adds to @surface new faces defining the isosurface f(x,y,z) =
- * @iso. By convention, the normals to the surface are pointing toward
- * the positive values of f(x,y,z) - @iso.
- *
- * The user function @f is called successively for each value of the z
- * coordinate defined by @g. It must fill the corresponding (x,y)
- * plane with the values of the function for which the isosurface is
- * to be computed.  
- */
-void gts_isosurface_tetra (GtsSurface * surface,
-			   GtsCartesianGrid g,
-			   GtsIsoCartesianFunc f,
-			   gpointer data,
-			   gdouble iso)
-{
-  slice_t *slice1, *slice2; 
-  helper_t *helper;
-  gint z; 
-  GtsCartesianGrid g_internal;
-  
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (g.nx > 1);
-  g_return_if_fail (g.ny > 1);
-  g_return_if_fail (g.nz > 1);
-
-  memcpy (&g_internal, &g, sizeof (GtsCartesianGrid));
-	
-  /* create the helper slices */
-  slice1 = new_slice (g.nx, g.ny);
-  slice2 = new_slice (g.nx, g.ny);
-  
-  /* create the helper for vertex-lookup */
-  helper = init_helper (g.nx, g.ny);
-	
-  z = 0;
-  f (slice1->data, g, z, data);
-  iso_sub (slice1, iso); 
-  
-  z++; 
-  g.z += g.dz;
-  
-  /* go slicewise through the data */
-  while (z < g.nz) {
-    slice_t * hs; 
-    
-    /* request slice */
-    f (slice2->data, g, z, data);
-    iso_sub (slice2, iso);
-     
-    g.z += g.dz;
-    
-    /* triangulate */
-    iso_slice_evaluate (slice1, slice2, g_internal, z-1, surface, helper);
-    
-    /* switch the input slices */
-    hs = slice1; slice1 = slice2; slice2 = hs; 
-    
-    /* switch the vertex lookup tables */
-    helper_advance (helper);
-    
-    ++z; 
-  }
-
-  free_helper(helper);
-  free_slice(slice1);
-  free_slice(slice2);	
-}
-
-/**
- * gts_isosurface_tetra_bcl:
- * @surface: a #GtsSurface.
- * @g: a #GtsCartesianGrid.
- * @f: a #GtsIsoCartesianFunc.
- * @data: user data to be passed to @f.
- * @iso: isosurface value.
- *
- * Adds to @surface new faces defining the isosurface f(x,y,z) =
- * @iso. By convention, the normals to the surface are pointing toward
- * the positive values of f(x,y,z) - @iso.
- *
- * The user function @f is called successively for each value of the z
- * coordinate defined by @g. It must fill the corresponding (x,y)
- * plane with the values of the function for which the isosurface is
- * to be computed.  
- *
- * This version produces the dual "body-centered" faces relative to
- * the faces produced by gts_isosurface_tetra().
- */
-void gts_isosurface_tetra_bcl (GtsSurface * surface,
-			       GtsCartesianGrid g,
-			       GtsIsoCartesianFunc f,
-			       gpointer data,
-			       gdouble iso)
-{
-  slice_t *slice1, *slice2, *slice3;
-  helper_bcl *helper;
-  gint z; 
-  GtsCartesianGrid g_internal;
-  
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (g.nx > 1);
-  g_return_if_fail (g.ny > 1);
-  g_return_if_fail (g.nz > 1);
-
-  memcpy (&g_internal, &g, sizeof (GtsCartesianGrid));
-	
-  /* create the helper slices */
-  slice1 = new_slice (g.nx, g.ny);
-  slice2 = new_slice (g.nx, g.ny);
-  slice3 = new_slice (g.nx, g.ny);
-  
-  /* create the helper for vertex-lookup */
-  helper = init_helper_bcl ();
-	
-  z = 0;
-  f (slice1->data, g, z, data);
-  iso_sub (slice1, iso); 
-
-  z++; 
-  g.z += g.dz;
-
-  f (slice2->data, g, z, data);
-  iso_sub (slice1, iso); 
-  
-  z++; 
-  g.z += g.dz;
-  
-  /* go slicewise through the data */
-  while (z < g.nz) {
-    slice_t * hs; 
-    
-    /* request slice */
-    f (slice3->data, g, z, data);
-    iso_sub (slice3, iso);
-     
-    g.z += g.dz;
-    
-    /* triangulate */
-    iso_slice_evaluate_bcl (slice1, slice2, slice3, g_internal, z-2, 
-			    surface, helper);
-    
-    /* switch the input slices */
-    hs = slice1; slice1 = slice2; slice2 = slice3; slice3 = hs;
-    
-    /* switch the vertex lookup tables */
-    helper_advance_bcl (helper);
-    
-    ++z; 
-  }
-
-  free_helper_bcl(helper);
-  free_slice(slice1);
-  free_slice(slice2);	
-  free_slice(slice3);	
-}
diff --git a/src_3rd/gts/kdtree.c b/src_3rd/gts/kdtree.c
deleted file mode 100644
index ec5d422..0000000
--- a/src_3rd/gts/kdtree.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include "gts.h"
-
-
-static int compare_x (const void * p1, const void * p2) {
-  GtsPoint 
-    * pp1 = *((gpointer *) p1),
-    * pp2 = *((gpointer *) p2);
-  if (pp1->x > pp2->x)
-    return 1;
-  return -1;
-}
-
-static int compare_y (const void * p1, const void * p2) {
-  GtsPoint
-    * pp1 = *((gpointer *) p1),
-    * pp2 = *((gpointer *) p2);
-  if (pp1->y > pp2->y)
-    return 1;
-  return -1;
-}
-
-static int compare_z (const void * p1, const void * p2) {
-  GtsPoint 
-    * pp1 = *((gpointer *) p1),
-    * pp2 = *((gpointer *) p2);
-  if (pp1->z > pp2->z)
-    return 1;
-  return -1;
-}
-
-/**
- * gts_kdtree_new:
- * @points: an array of #GtsPoint.
- * @compare: always %NULL.
- *
- * Note that the order of the points in array @points is modified by this
- * function.
- * 
- * Returns: a new 3D tree for @points.
- */
-GNode * gts_kdtree_new (GPtrArray * points, 
-			int (*compare) (const void *, const void *))
-{
-  guint middle;
-  GPtrArray array;
-  GNode * node;
-  GtsPoint * point;
-
-  g_return_val_if_fail (points != NULL, NULL);
-  g_return_val_if_fail (points->len > 0, NULL);
-
-  /* sort the points */
-  if (compare == compare_x) compare = compare_y;
-  else if (compare == compare_y) compare = compare_z;
-  else compare = compare_x;
-  qsort (points->pdata, points->len, sizeof (gpointer), compare);
-
-  middle = (points->len - 1)/2;
-  point = points->pdata[middle];
-  node = g_node_new (point);
-
-  if (points->len > 1) {
-    array.len = middle;
-    if (array.len > 0) {
-      array.pdata = points->pdata;
-      g_node_prepend (node, gts_kdtree_new (&array, compare));
-    }
-    else
-      g_node_prepend (node, g_node_new (NULL));
-    
-    array.len = points->len - middle - 1;
-    if (array.len > 0) {
-      array.pdata = &(points->pdata[middle + 1]);
-      g_node_prepend (node, gts_kdtree_new (&array, compare));
-    }
-    else
-      g_node_prepend (node, g_node_new (NULL));
-  }
-
-  return node;
-}
-
-/**
- * gts_kdtree_range:
- * @tree: a 3D tree.
- * @bbox: a #GtsBBox.
- * @compare: always %NULL.
- *
- * Returns: a list of #GtsPoint belonging to @tree which are inside @bbox.
- */
-GSList * gts_kdtree_range (GNode * tree_3d,
-			   GtsBBox * bbox,
-			   int (*compare) (const void *, const void *))
-{
-  GSList * list = NULL;
-  GtsPoint * p;
-  gdouble left, right, v;
-  GNode * node;
-
-  g_return_val_if_fail (tree_3d != NULL, NULL);
-  g_return_val_if_fail (bbox != NULL, NULL);
-
-  p = tree_3d->data;
-  if (p == NULL)
-    return NULL;
-
-  if (gts_bbox_point_is_inside (bbox, p))
-    list = g_slist_prepend (list, p);
-
-  if (compare == compare_x) {
-    left = bbox->y1; right = bbox->y2; v = p->y;
-    compare = compare_y;
-  }
-  else if (compare == compare_y) {
-    left = bbox->z1; right = bbox->z2; v = p->z;
-    compare = compare_z;
-  }
-  else {
-    left = bbox->x1; right = bbox->x2; v = p->x;
-    compare = compare_x;
-  }
-
-  if ((node = tree_3d->children)) {
-    if (right >= v)
-      list = g_slist_concat (list, gts_kdtree_range (node, bbox, compare));
-    node = node->next;
-    if (left <= v)
-      list = g_slist_concat (list, gts_kdtree_range (node, bbox, compare));
-  }
-  return list;
-}
-
diff --git a/src_3rd/gts/matrix.c b/src_3rd/gts/matrix.c
deleted file mode 100644
index 7ada15d..0000000
--- a/src_3rd/gts/matrix.c
+++ /dev/null
@@ -1,725 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include "gts.h"
-
-/**
- * gts_matrix_new:
- * @a00: element [0][0].
- * @a01: element [0][1].
- * @a02: element [0][2].
- * @a03: element [0][3].
- * @a10: element [1][0].
- * @a11: element [1][1].
- * @a12: element [1][2].
- * @a13: element [1][3].
- * @a20: element [2][0].
- * @a21: element [2][1].
- * @a22: element [2][2].
- * @a23: element [2][3].
- * @a30: element [3][0].
- * @a31: element [3][1].
- * @a32: element [3][2].
- * @a33: element [3][3].
- *
- * Allocates memory and initializes a new #GtsMatrix.
- *
- * Returns: a pointer to the newly created #GtsMatrix.
- */
-GtsMatrix * gts_matrix_new (gdouble a00, gdouble a01, gdouble a02, gdouble a03,
-			    gdouble a10, gdouble a11, gdouble a12, gdouble a13,
-			    gdouble a20, gdouble a21, gdouble a22, gdouble a23,
-			    gdouble a30, gdouble a31, gdouble a32, gdouble a33)
-{
-  GtsMatrix * m;
-
-  m = g_malloc (4*sizeof (GtsVector4));
-
-  m[0][0] = a00; m[1][0] = a10; m[2][0] = a20; m[3][0] = a30;
-  m[0][1] = a01; m[1][1] = a11; m[2][1] = a21; m[3][1] = a31;
-  m[0][2] = a02; m[1][2] = a12; m[2][2] = a22; m[3][2] = a32;
-  m[0][3] = a03; m[1][3] = a13; m[2][3] = a23; m[3][3] = a33;
-
-  return m;
-}
-
-/**
- * gts_matrix_assign:
- * @m: a #GtsMatrix.
- * @a00: element [0][0].
- * @a01: element [0][1].
- * @a02: element [0][2].
- * @a03: element [0][3].
- * @a10: element [1][0].
- * @a11: element [1][1].
- * @a12: element [1][2].
- * @a13: element [1][3].
- * @a20: element [2][0].
- * @a21: element [2][1].
- * @a22: element [2][2].
- * @a23: element [2][3].
- * @a30: element [3][0].
- * @a31: element [3][1].
- * @a32: element [3][2].
- * @a33: element [3][3].
- *
- * Set values of matrix elements.
- */
-void gts_matrix_assign (GtsMatrix * m,
-			gdouble a00, gdouble a01, gdouble a02, gdouble a03,
-			gdouble a10, gdouble a11, gdouble a12, gdouble a13,
-			gdouble a20, gdouble a21, gdouble a22, gdouble a23,
-			gdouble a30, gdouble a31, gdouble a32, gdouble a33)
-{
-  g_return_if_fail (m != NULL);
-
-  m[0][0] = a00; m[1][0] = a10; m[2][0] = a20; m[3][0] = a30;
-  m[0][1] = a01; m[1][1] = a11; m[2][1] = a21; m[3][1] = a31;
-  m[0][2] = a02; m[1][2] = a12; m[2][2] = a22; m[3][2] = a32;
-  m[0][3] = a03; m[1][3] = a13; m[2][3] = a23; m[3][3] = a33;
-}
-
-/**
- * gts_matrix_projection:
- * @t: a #GtsTriangle.
- *
- * Creates a new #GtsMatrix representing the projection onto a plane of normal
- * given by @t.
- *
- * Returns: a pointer to the newly created #GtsMatrix.
- */
-GtsMatrix * gts_matrix_projection (GtsTriangle * t)
-{
-  GtsVertex * v1, * v2, * v3;
-  GtsEdge * e1, * e2, * e3;
-  GtsMatrix * m;
-  gdouble x1, y1, z1, x2, y2, z2, x3, y3, z3, l;
-  
-  g_return_val_if_fail (t != NULL, NULL);
-
-  m = g_malloc (4*sizeof (GtsVector4));
-  gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3);
-
-  x1 = GTS_POINT (v2)->x - GTS_POINT (v1)->x; 
-  y1 = GTS_POINT (v2)->y - GTS_POINT (v1)->y; 
-  z1 = GTS_POINT (v2)->z - GTS_POINT (v1)->z;
-  x2 = GTS_POINT (v3)->x - GTS_POINT (v1)->x; 
-  y2 = GTS_POINT (v3)->y - GTS_POINT (v1)->y; 
-  z2 = GTS_POINT (v3)->z - GTS_POINT (v1)->z;
-  x3 = y1*z2 - z1*y2; y3 = z1*x2 - x1*z2; z3 = x1*y2 - y1*x2;
-  x2 = y3*z1 - z3*y1; y2 = z3*x1 - x3*z1; z2 = x3*y1 - y3*x1;
-
-  g_assert ((l = sqrt (x1*x1 + y1*y1 + z1*z1)) > 0.0);
-  m[0][0] = x1/l; m[1][0] = y1/l; m[2][0] = z1/l; m[3][0] = 0.;
-  g_assert ((l = sqrt (x2*x2 + y2*y2 + z2*z2)) > 0.0);
-  m[0][1] = x2/l; m[1][1] = y2/l; m[2][1] = z2/l; m[3][1] = 0.;
-  g_assert ((l = sqrt (x3*x3 + y3*y3 + z3*z3)) > 0.0);
-  m[0][2] = x3/l; m[1][2] = y3/l; m[2][2] = z3/l; m[3][2] = 0.;
-  m[0][3] = 0; m[1][3] = 0.; m[2][3] = 0.; m[3][3] = 1.;
-
-  return m;
-}
-
-/**
- * gts_matrix_transpose:
- * @m: a #GtsMatrix.
- *
- * Returns: a pointer to a newly created #GtsMatrix transposed of @m.
- */
-GtsMatrix * gts_matrix_transpose (GtsMatrix * m)
-{
-  GtsMatrix * mi;
-
-  g_return_val_if_fail (m != NULL, NULL);
-
-  mi = g_malloc (4*sizeof (GtsVector4));
-
-  mi[0][0] = m[0][0]; mi[1][0] = m[0][1]; 
-  mi[2][0] = m[0][2]; mi[3][0] = m[0][3];
-  mi[0][1] = m[1][0]; mi[1][1] = m[1][1]; 
-  mi[2][1] = m[1][2]; mi[3][1] = m[1][3];
-  mi[0][2] = m[2][0]; mi[1][2] = m[2][1]; 
-  mi[2][2] = m[2][2]; mi[3][2] = m[2][3];
-  mi[0][3] = m[3][0]; mi[1][3] = m[3][1]; 
-  mi[2][3] = m[3][2]; mi[3][3] = m[3][3];
-
-  return mi;
-}
-
-/*
- * calculate the determinant of a 2x2 matrix.
- * 
- * Adapted from:
- * Matrix Inversion
- * by Richard Carling
- * from "Graphics Gems", Academic Press, 1990
- */
-static gdouble det2x2 (gdouble a, gdouble b, gdouble c, gdouble d)
-{
-  gdouble ans2;
-
-  ans2 = a*d - b*c;
-  return ans2;
-}
-
-/*
- * calculate the determinant of a 3x3 matrix
- * in the form
- *
- *     | a1,  b1,  c1 |
- *     | a2,  b2,  c2 |
- *     | a3,  b3,  c3 |
- *
- * Adapted from:
- * Matrix Inversion
- * by Richard Carling
- * from "Graphics Gems", Academic Press, 1990
- */
-static gdouble det3x3 (gdouble a1, gdouble a2, gdouble a3, 
-		       gdouble b1, gdouble b2, gdouble b3, 
-		       gdouble c1, gdouble c2, gdouble c3)
-{
-  gdouble ans3;
-
-  ans3 = a1 * det2x2( b2, b3, c2, c3 )
-    - b1 * det2x2( a2, a3, c2, c3 )
-    + c1 * det2x2( a2, a3, b2, b3 );
-  return ans3;
-}
-
-/**
- * gts_matrix_determinant:
- * @m: a #GtsMatrix.
- *
- * Returns: the value of det(@m).
- */
-gdouble gts_matrix_determinant (GtsMatrix * m)
-{
-  gdouble ans4;
-  gdouble a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;
-
-  g_return_val_if_fail (m != NULL, 0.0);
-
-  a1 = m[0][0]; b1 = m[0][1]; 
-  c1 = m[0][2]; d1 = m[0][3];
-  
-  a2 = m[1][0]; b2 = m[1][1]; 
-  c2 = m[1][2]; d2 = m[1][3];
-  
-  a3 = m[2][0]; b3 = m[2][1]; 
-  c3 = m[2][2]; d3 = m[2][3];
-  
-  a4 = m[3][0]; b4 = m[3][1]; 
-  c4 = m[3][2]; d4 = m[3][3];
-  
-  ans4 = a1 * det3x3 (b2, b3, b4, c2, c3, c4, d2, d3, d4)
-    - b1 * det3x3 (a2, a3, a4, c2, c3, c4, d2, d3, d4)
-    + c1 * det3x3 (a2, a3, a4, b2, b3, b4, d2, d3, d4)
-    - d1 * det3x3 (a2, a3, a4, b2, b3, b4, c2, c3, c4);
-
-  return ans4;
-}
-
-/* 
- *   adjoint( original_matrix, inverse_matrix )
- * 
- *     calculate the adjoint of a 4x4 matrix
- *
- *      Let  a   denote the minor determinant of matrix A obtained by
- *           ij
- *
- *      deleting the ith row and jth column from A.
- *
- *                    i+j
- *     Let  b   = (-1)    a
- *          ij            ji
- *
- *    The matrix B = (b  ) is the adjoint of A
- *                     ij
- */
-static GtsMatrix * adjoint (GtsMatrix * m)
-{
-  gdouble a1, a2, a3, a4, b1, b2, b3, b4;
-  gdouble c1, c2, c3, c4, d1, d2, d3, d4;
-  GtsMatrix * ma;
-
-  a1 = m[0][0]; b1 = m[0][1]; 
-  c1 = m[0][2]; d1 = m[0][3];
-  
-  a2 = m[1][0]; b2 = m[1][1]; 
-  c2 = m[1][2]; d2 = m[1][3];
-  
-  a3 = m[2][0]; b3 = m[2][1];
-  c3 = m[2][2]; d3 = m[2][3];
-  
-  a4 = m[3][0]; b4 = m[3][1]; 
-  c4 = m[3][2]; d4 = m[3][3];
-
-  ma = g_malloc (4*sizeof (GtsVector4));
-
-  /* row column labeling reversed since we transpose rows & columns */
-
-  ma[0][0]  =   det3x3 (b2, b3, b4, c2, c3, c4, d2, d3, d4);
-  ma[1][0]  = - det3x3 (a2, a3, a4, c2, c3, c4, d2, d3, d4);
-  ma[2][0]  =   det3x3 (a2, a3, a4, b2, b3, b4, d2, d3, d4);
-  ma[3][0]  = - det3x3 (a2, a3, a4, b2, b3, b4, c2, c3, c4);
-  
-  ma[0][1]  = - det3x3 (b1, b3, b4, c1, c3, c4, d1, d3, d4);
-  ma[1][1]  =   det3x3 (a1, a3, a4, c1, c3, c4, d1, d3, d4);
-  ma[2][1]  = - det3x3 (a1, a3, a4, b1, b3, b4, d1, d3, d4);
-  ma[3][1]  =   det3x3 (a1, a3, a4, b1, b3, b4, c1, c3, c4);
-  
-  ma[0][2]  =   det3x3 (b1, b2, b4, c1, c2, c4, d1, d2, d4);
-  ma[1][2]  = - det3x3 (a1, a2, a4, c1, c2, c4, d1, d2, d4);
-  ma[2][2]  =   det3x3 (a1, a2, a4, b1, b2, b4, d1, d2, d4);
-  ma[3][2]  = - det3x3 (a1, a2, a4, b1, b2, b4, c1, c2, c4);
-  
-  ma[0][3]  = - det3x3 (b1, b2, b3, c1, c2, c3, d1, d2, d3);
-  ma[1][3]  =   det3x3 (a1, a2, a3, c1, c2, c3, d1, d2, d3);
-  ma[2][3]  = - det3x3 (a1, a2, a3, b1, b2, b3, d1, d2, d3);
-  ma[3][3]  =   det3x3 (a1, a2, a3, b1, b2, b3, c1, c2, c3);
-  
-  return ma;
-}
-
-
-/**
- * gts_matrix_inverse:
- * @m: a #GtsMatrix.
- *
- * Returns: a pointer to a newly created #GtsMatrix inverse of @m or %NULL
- * if @m is not invertible.
- */
-GtsMatrix * gts_matrix_inverse (GtsMatrix * m)
-{
-  GtsMatrix * madj;
-  gdouble det;
-  gint i, j;
-
-  g_return_val_if_fail (m != NULL, NULL);
-  
-  det = gts_matrix_determinant (m);
-  if (det == 0.)
-    return NULL;
-
-  madj = adjoint (m);
-  for (i = 0; i < 4; i++)
-    for(j = 0; j < 4; j++)
-      madj[i][j] /= det;
-
-  return madj;
-}
-
-/**
- * gts_matrix3_inverse:
- * @m: a 3x3 #GtsMatrix.
- *
- * Returns: a pointer to a newly created 3x3 #GtsMatrix inverse of @m or %NULL
- * if @m is not invertible.
- */
-GtsMatrix * gts_matrix3_inverse (GtsMatrix * m)
-{
-  GtsMatrix * mi;
-  gdouble det;
-
-  g_return_val_if_fail (m != NULL, NULL);
-  
-  det = (m[0][0]*(m[1][1]*m[2][2] - m[2][1]*m[1][2]) - 
-	 m[0][1]*(m[1][0]*m[2][2] - m[2][0]*m[1][2]) + 
-	 m[0][2]*(m[1][0]*m[2][1] - m[2][0]*m[1][1]));
-  if (det == 0.0)
-    return NULL;
-
-  mi = g_malloc0 (4*sizeof (GtsVector));
-
-  mi[0][0] = (m[1][1]*m[2][2] - m[1][2]*m[2][1])/det; 
-  mi[0][1] = (m[2][1]*m[0][2] - m[0][1]*m[2][2])/det;
-  mi[0][2] = (m[0][1]*m[1][2] - m[1][1]*m[0][2])/det; 
-  mi[1][0] = (m[1][2]*m[2][0] - m[1][0]*m[2][2])/det; 
-  mi[1][1] = (m[0][0]*m[2][2] - m[2][0]*m[0][2])/det; 
-  mi[1][2] = (m[1][0]*m[0][2] - m[0][0]*m[1][2])/det; 
-  mi[2][0] = (m[1][0]*m[2][1] - m[2][0]*m[1][1])/det; 
-  mi[2][1] = (m[2][0]*m[0][1] - m[0][0]*m[2][1])/det; 
-  mi[2][2] = (m[0][0]*m[1][1] - m[0][1]*m[1][0])/det; 
-
-  return mi;
-}
-
-/**
- * gts_matrix_print:
- * @m: a #GtsMatrix.
- * @fptr: a file descriptor.
- * 
- * Print @m to file @fptr.
- */
-void gts_matrix_print (GtsMatrix * m, FILE * fptr)
-{
-  g_return_if_fail (m != NULL);
-  g_return_if_fail (fptr != NULL);
-
-  fprintf (fptr, 
-	   "[[%15.7g %15.7g %15.7g %15.7g]\n"
-	   " [%15.7g %15.7g %15.7g %15.7g]\n"
-	   " [%15.7g %15.7g %15.7g %15.7g]\n"
-	   " [%15.7g %15.7g %15.7g %15.7g]]\n",
-	   m[0][0], m[0][1], m[0][2], m[0][3],
-	   m[1][0], m[1][1], m[1][2], m[1][3],
-	   m[2][0], m[2][1], m[2][2], m[2][3],
-	   m[3][0], m[3][1], m[3][2], m[3][3]);
-}
-
-/**
- * gts_vector_print:
- * @v: a #GtsVector.
- * @fptr: a file descriptor.
- * 
- * Print @s to file @fptr.
- */
-void gts_vector_print (GtsVector v, FILE * fptr)
-{
-  g_return_if_fail (fptr != NULL);
-
-  fprintf (fptr, 
-	   "[%15.7g %15.7g %15.7g ]\n",
-	   v[0], v[1], v[2]);
-}
-
-/**
- * gts_vector4_print:
- * @v: a #GtsVector4.
- * @fptr: a file descriptor.
- * 
- * Print @v to file @fptr.
- */
-void gts_vector4_print (GtsVector4 v, FILE * fptr)
-{
-  g_return_if_fail (fptr != NULL);
-
-  fprintf (fptr, 
-	   "[%15.7g %15.7g %15.7g %15.7g]\n",
-	   v[0], v[1], v[2], v[3]);
-}
-
-/* [cos(alpha)]^2 */
-#define COSALPHA2 0.999695413509 /* alpha = 1 degree */
-/* [sin(alpha)]^2 */
-#define SINALPHA2 3.04586490453e-4 /* alpha = 1 degree */
-
-/**
- * gts_matrix_compatible_row:
- * @A: a #GtsMatrix.
- * @b: a #GtsVector.
- * @n: the number of previous constraints of @A.x=@b.
- * @A1: a #GtsMatrix.
- * @b1: a #GtsVector.
- *
- * Given a system of @n constraints @A.x=@b adds to it the compatible
- * constraints defined by @A1.x=@b1. The compatibility is determined
- * by insuring that the resulting system is well-conditioned (see
- * Lindstrom and Turk (1998, 1999)).
- *
- * Returns: the number of constraints of the resulting system.  
- */
-guint gts_matrix_compatible_row (GtsMatrix * A,
-				 GtsVector b,
-				 guint n,
-				 GtsVector A1,
-				 gdouble b1)
-{
-  gdouble na1;
-  
-  g_return_val_if_fail (A != NULL, 0);
-
-  na1 = gts_vector_scalar (A1, A1);
-  if (na1 == 0.0)
-    return n;
-
-  /* normalize row */
-  na1 = sqrt (na1);
-  A1[0] /= na1; A1[1] /= na1; A1[2] /= na1; b1 /= na1;
-
-  if (n == 1) {
-    gdouble a0a1 = gts_vector_scalar (A[0], A1);
-    if (a0a1*a0a1 >= COSALPHA2)
-      return 1;
-  }
-  else if (n == 2) {
-    GtsVector V;
-    gdouble s;
-    
-    gts_vector_cross (V, A[0], A[1]);
-    s = gts_vector_scalar (V, A1);
-    if (s*s <= gts_vector_scalar (V, V)*SINALPHA2)
-      return 2;
-  }
-
-  A[n][0] = A1[0]; A[n][1] = A1[1]; A[n][2] = A1[2]; b[n] = b1;
-  return n + 1;
-}
-
-/**
- * gts_matrix_quadratic_optimization:
- * @A: a #GtsMatrix.
- * @b: a #GtsVector.
- * @n: the number of constraints (must be smaller than 3).
- * @H: a symmetric positive definite Hessian.
- * @c: a #GtsVector.
- *
- * Solve a quadratic optimization problem: Given a quadratic objective function
- * f which can be written as: f(x) = x^t. at H.x + @c^t.x + k, where @H is the 
- * symmetric positive definite Hessian of f and k is a constant, find the
- * minimum of f subject to the set of @n prior linear constraints, defined by
- * the first @n rows of @A and @b (@A.x = @b). The new constraints given by
- * the minimization are added to @A and @b only if they are linearly
- * independent as determined by gts_matrix_compatible_row().
- *
- * Returns: the new number of constraints defined by @A and @b.
- */
-guint gts_matrix_quadratic_optimization (GtsMatrix * A,
-					 GtsVector b,
-					 guint n,
-					 GtsMatrix * H,
-					 GtsVector c)
-{
-  g_return_val_if_fail (A != NULL, 0);
-  g_return_val_if_fail (b != NULL, 0);
-  g_return_val_if_fail (n < 3, 0);
-  g_return_val_if_fail (H != NULL, 0);
-
-  switch (n) {
-  case 0: {
-    n = gts_matrix_compatible_row (A, b, n, H[0], - c[0]);
-    n = gts_matrix_compatible_row (A, b, n, H[1], - c[1]);
-    n = gts_matrix_compatible_row (A, b, n, H[2], - c[2]);
-    return n;
-  }
-  case 1: {
-    GtsVector Q0 = {0., 0., 0.};
-    GtsVector Q1 = {0., 0., 0.};
-    GtsVector A1;
-    gdouble max = A[0][0]*A[0][0];
-    guint d = 0;
-
-    /* build a vector orthogonal to the constraint */
-    if (A[0][1]*A[0][1] > max) { max = A[0][1]*A[0][1]; d = 1; }
-    if (A[0][2]*A[0][2] > max) { max = A[0][2]*A[0][2]; d = 2; }
-    switch (d) {
-    case 0: Q0[0] = - A[0][2]/A[0][0]; Q0[2] = 1.0; break;
-    case 1: Q0[1] = - A[0][2]/A[0][1]; Q0[2] = 1.0; break;
-    case 2: Q0[2] = - A[0][0]/A[0][2]; Q0[0] = 1.0; break;
-    }
-
-    /* build a second vector orthogonal to the first and to the constraint */
-    gts_vector_cross (Q1, A[0], Q0);
-
-    A1[0] = gts_vector_scalar (Q0, H[0]);
-    A1[1] = gts_vector_scalar (Q0, H[1]);
-    A1[2] = gts_vector_scalar (Q0, H[2]);
-
-    n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q0, c));
-    
-    A1[0] = gts_vector_scalar (Q1, H[0]);
-    A1[1] = gts_vector_scalar (Q1, H[1]);
-    A1[2] = gts_vector_scalar (Q1, H[2]);
-
-    n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q1, c));
-
-    return n;
-  }
-  case 2: {
-    /* build a vector orthogonal to the two constraints */
-    GtsVector A1, Q;
-
-    gts_vector_cross (Q, A[0], A[1]);
-    A1[0] = gts_vector_scalar (Q, H[0]);
-    A1[1] = gts_vector_scalar (Q, H[1]);
-    A1[2] = gts_vector_scalar (Q, H[2]);
-    
-    n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q, c));
-
-    return n;
-  }
-  default:
-    g_assert_not_reached ();
-  }
-  return 0;
-}
-
-/**
- * gts_matrix_destroy:
- * @m: a #GtsMatrix.
- *
- * Free all the memory allocated for @m.
- */
-void gts_matrix_destroy (GtsMatrix * m)
-{
-  g_free (m);
-}
-
-/**
- * gts_matrix_product:
- * @m1: a #GtsMatrix.
- * @m2: another #GtsMatrix.
- *
- * Returns: a new #GtsMatrix, product of @m1 and @m2.
- */
-GtsMatrix * gts_matrix_product (GtsMatrix * m1, GtsMatrix * m2)
-{
-  guint i, j;
-  GtsMatrix * m;
-
-  g_return_val_if_fail (m1 != NULL, NULL);
-  g_return_val_if_fail (m2 != NULL, NULL);
-  g_return_val_if_fail (m1 != m2, NULL);
-
-  m = g_malloc (4*sizeof (GtsVector4));
-
-  for (i = 0; i < 4; i++)
-    for (j = 0; j < 4; j++)
-      m[i][j] = m1[i][0]*m2[0][j] + m1[i][1]*m2[1][j] +
-        m1[i][2]*m2[2][j] + m1[i][3]*m2[3][j];
-  return m;
-}
-
-/**
- * gts_matrix_zero:
- * @m: a #GtsMatrix or $NULL.
- *
- * Initializes @m to zeros. Allocates a matrix if @m is %NULL.
- *
- * Returns: the zero'ed matrix.
- */
-GtsMatrix * gts_matrix_zero (GtsMatrix * m)
-{
-  if (m == NULL)
-    m = g_malloc0 (4*sizeof (GtsVector4));
-  else {
-    m[0][0] = m[1][0] = m[2][0] = m[3][0] = 0.;
-    m[0][1] = m[1][1] = m[2][1] = m[3][1] = 0.;
-    m[0][2] = m[1][2] = m[2][2] = m[3][2] = 0.;
-    m[0][3] = m[1][3] = m[2][3] = m[3][3] = 0.;
-  }
-  return m;
-}
-
-/**
- * gts_matrix_identity:
- * @m: a #GtsMatrix or %NULL.
- *
- * Initializes @m to an identity matrix. Allocates a matrix if @m is %NULL.
- *
- * Returns: the identity matrix.
- */
-GtsMatrix * gts_matrix_identity (GtsMatrix * m)
-{
-  m = gts_matrix_zero (m);
-  m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.;
-  return m;
-}
-
-/**
- * gts_matrix_scale:
- * @m: a #GtsMatrix or %NULL.
- * @s: the scaling vector.
- *
- * Initializes @m to a scaling matrix for @s. Allocates a matrix if @m
- * is %NULL.
- *
- * Returns: the scaling matrix.
- */
-GtsMatrix * gts_matrix_scale (GtsMatrix * m, GtsVector s)
-{
-  m = gts_matrix_zero (m);
-  m[0][0] = s[0];
-  m[1][1] = s[1];
-  m[2][2] = s[2];
-  m[3][3] = 1.;
-  return m;
-}
-
-/**
- * gts_matrix_translate:
- * @m: a #GtsMatrix or %NULL.
- * @t: the translation vector.
- *
- * Initializes @m to a translation matrix for @t.  Allocates a new
- * matrix if @m is %NULL.
- *
- * Returns: the translation matix.
- */
-GtsMatrix * gts_matrix_translate (GtsMatrix * m, GtsVector t)
-{
-  m = gts_matrix_zero (m);
-  m[0][3] = t[0];
-  m[1][3] = t[1];
-  m[2][3] = t[2];
-  m[3][3] = 1.;
-  m[0][0] = m[1][1] = m[2][2] = 1.;
-  return m;
-}
-
-/**
- * gts_matrix_rotate:
- * @m: a #GtsMatrix or %NULL.
- * @r: the rotation axis.
- * @angle: the angle (in radians) to rotate by.
- *
- * Initializes @m to a rotation matrix around @r by @angle.
- * Allocates a new matrix if @m is %NULL.
- *
- * Returns: the rotation matrix.
- */
-GtsMatrix * gts_matrix_rotate (GtsMatrix * m,
-			       GtsVector r,
-			       gdouble angle)
-{
-  gdouble c, c1, s;
-
-  gts_vector_normalize (r);
-
-  c = cos (angle);
-  c1 = 1. - c;
-  s = sin (angle);
-
-  if (m == NULL)
-    m = g_malloc (4*sizeof (GtsVector4));
-
-  m[0][0] = r[0]*r[0]*c1 + c;
-  m[0][1] = r[0]*r[1]*c1 - r[2]*s;
-  m[0][2] = r[0]*r[2]*c1 + r[1]*s;
-  m[0][3] = 0.;
-
-  m[1][0] = r[1]*r[0]*c1 + r[2]*s;
-  m[1][1] = r[1]*r[1]*c1 + c;
-  m[1][2] = r[1]*r[2]*c1 - r[0]*s;
-  m[1][3] = 0.;
-
-  m[2][0] = r[2]*r[0]*c1 - r[1]*s;
-  m[2][1] = r[2]*r[1]*c1 + r[0]*s;
-  m[2][2] = r[2]*r[2]*c1 + c;
-  m[2][3] = 0.;
-
-  m[3][0] = 0.;
-  m[3][1] = 0.;
-  m[3][2] = 0.;
-  m[3][3] = 1.;
-
-  return m;
-}
diff --git a/src_3rd/gts/misc.c b/src_3rd/gts/misc.c
deleted file mode 100644
index 393ba06..0000000
--- a/src_3rd/gts/misc.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "gts.h"
-#include "gts-private.h"
-#include "config.h"
-
-const guint gts_major_version = GTS_MAJOR_VERSION;
-const guint gts_minor_version = GTS_MINOR_VERSION;
-const guint gts_micro_version = GTS_MICRO_VERSION;
-const guint gts_interface_age = 1;
-const guint gts_binary_age = 1;
-
-static gboolean char_in_string (char c, const char * s)
-{
-  while (*s != '\0')
-    if (*(s++) == c)
-      return TRUE;
-  return FALSE;
-}
-
-static GtsFile * file_new (void)
-{
-  GtsFile * f;
-
-  f = g_malloc (sizeof (GtsFile));
-  f->fp = NULL;
-  f->s = f->s1 = NULL;
-  f->curline = 1;
-  f->curpos = 1;
-  f->token = g_string_new ("");
-  f->type = '\0';
-  f->error = NULL;
-  f->next_token = '\0';
-
-  f->scope = f->scope_max = 0;
-  f->delimiters = g_strdup (" \t");
-  f->comments = g_strdup (GTS_COMMENTS);
-  f->tokens = g_strdup ("\n{}()=");
-
-  return f;
-}
-
-/**
- * gts_file_new:
- * @fp: a file pointer.
- *
- * Returns: a new #GtsFile.
- */
-GtsFile * gts_file_new (FILE * fp)
-{
-  GtsFile * f;
-
-  g_return_val_if_fail (fp != NULL, NULL);
-
-  f = file_new ();
-  f->fp = fp;
-  gts_file_next_token (f);
-
-  return f;
-}
-
-/**
- * gts_file_new_from_string:
- * @s: a string.
- *
- * Returns: a new #GtsFile.
- */
-GtsFile * gts_file_new_from_string (const gchar * s)
-{
-  GtsFile * f;
-
-  g_return_val_if_fail (s != NULL, NULL);
-
-  f = file_new ();
-  f->s1 = f->s = g_strdup (s);
-  gts_file_next_token (f);
-
-  return f;
-}
-
-/**
- * gts_file_destroy:
- * @f: a #GtsFile.
- *
- * Frees all the memory allocated for @f.
- */
-void gts_file_destroy (GtsFile * f)
-{
-  g_return_if_fail (f != NULL);
-
-  g_free (f->delimiters);
-  g_free (f->comments);
-  g_free (f->tokens);
-  if (f->error)
-    g_free (f->error);
-  if (f->s1)
-    g_free (f->s1);
-  g_string_free (f->token, TRUE);
-  g_free (f);
-}
-
-/**
- * gts_file_verror:
- * @f: a @GtsFile.
- * @format: the standard sprintf() format string.
- * @args: the list of parameters to insert into the format string.
- *
- * Sets the @error field of @f using g_strdup_vprintf().
- *
- * This function can be called only once and disables any other
- * operation on @f (gts_file_close() excepted).
- */
-void gts_file_verror (GtsFile * f,
-		      const gchar * format,
-		      va_list args)
-{
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (format != NULL);
-
-  g_assert (f->type != GTS_ERROR);
-  f->error = g_strdup_vprintf (format, args);
-  f->type = GTS_ERROR;
-}
-
-/**
- * gts_file_error:
- * @f: a @GtsFile.
- * @format: the standard sprintf() format string.
- * @...: the parameters to insert into the format string.
- *
- * Sets the @error field of @f using gts_file_verror().
- *
- * This function can be called only once and disables any other
- * operation on @f (gts_file_close() excepted).
- */
-void gts_file_error (GtsFile * f,
-		     const gchar * format,
-		     ...)
-{
-  va_list args;
-
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (format != NULL);
-
-  va_start (args, format);  
-  gts_file_verror (f, format, args);
-  va_end (args);
-}
-
-static gint next_char (GtsFile * f)
-{
-  if (f->fp)
-    return fgetc (f->fp);
-  else if (*f->s == '\0')
-    return EOF;
-  return *(f->s++);
-}
-
-/**
- * gts_file_getc :
- * @f: a #GtsFile.
- *
- * Returns: the next character in @f or EOF if the end of the file is
- * reached or if an error occured.
- */
-gint gts_file_getc (GtsFile * f)
-{
-  gint c;
-
-  g_return_val_if_fail (f != NULL, EOF);
-
-  if (f->type == GTS_ERROR)
-    return EOF;
-
-  c = next_char (f);
-  f->curpos++;
-  while (char_in_string (c, f->comments)) {
-    while (c != EOF && c != '\n')
-      c = next_char (f);
-    if (c == '\n') {
-      f->curline++;
-      f->curpos = 1;
-      c = next_char (f);
-    }
-  }
-  switch (c) {
-  case '\n': 
-    f->curline++;
-    f->curpos = 1; 
-    break;
-  case '{':
-    f->scope++; 
-    break;
-  case '}':
-    if (f->scope == 0) {
-      f->line = f->curline;
-      f->pos = f->curpos - 1;
-      gts_file_error (f, "no matching opening brace");
-      c = EOF;
-    }
-    else
-      f->scope--;
-  }
-  return c;
-}
-
-/**
- * gts_file_read:
- * @f: a #GtsFile.
- * @ptr: a pointer.
- * @size: size of an element.
- * @nmemb: number of elements.
- *
- * Reads @nmemb elements of data, each @size bytes long, from @f,
- * storing them at the location given by @ptr.
- *
- * Returns: the number of elements read.
- */
-guint gts_file_read (GtsFile * f, gpointer ptr, guint size, guint nmemb)
-{
-  guint i, n;
-  gchar * p;
-
-  g_return_val_if_fail (f != NULL, 0);
-  g_return_val_if_fail (ptr != NULL, 0);
-  g_return_val_if_fail (f->fp != NULL, 0);
-
-  if (f->type == GTS_ERROR)
-    return 0;
-
-  n = fread (ptr, size, nmemb, f->fp);
-  for (i = 0, p = ptr; i < n*size; i++, p++) {
-    f->curpos++;
-    if (*p == '\n') {
-      f->curline++;
-      f->curpos = 1;
-    }
-  }
-  return n;
-}
-
-/**
- * gts_file_getc_scope :
- * @f: a #GtsFile.
- *
- * Returns: the next character in @f in the scope defined by
- * @f->scope_max or EOF if the end of the file is reached or if an
- * error occured.
- */
-gint gts_file_getc_scope (GtsFile * f)
-{
-  gint c;
-
-  g_return_val_if_fail (f != NULL, EOF);
-
-  if (f->type == GTS_ERROR)
-    return EOF;
-  
-  if (f->scope <= f->scope_max)
-    c = gts_file_getc (f);
-  else {
-    c = gts_file_getc (f);
-    while (c != EOF && f->scope > f->scope_max)
-      c = gts_file_getc (f);    
-  }
-  return c;
-}
-
-/**
- * gts_file_next_token:
- * @f: a #GtsFile.
- *
- * Reads next token from @f and updates its @token and @delim fields.
- */
-void gts_file_next_token (GtsFile * f)
-{
-  gint c;
-  gboolean in_string = FALSE;
-
-  g_return_if_fail (f != NULL);
-
-  if (f->type == GTS_ERROR)
-    return;
-  f->token->str[0] = '\0';
-  f->token->len = 0;
-  if (f->next_token != '\0') {
-    if (char_in_string (f->next_token, f->tokens)) {
-      f->line = f->curline;
-      f->pos = f->curpos - 1;
-      g_string_append_c (f->token, f->next_token);
-      f->type = f->next_token;
-      f->next_token = '\0';
-      return;
-    }
-    else {
-      c = f->next_token;
-      f->next_token = '\0';
-    }
-  }
-  else
-    c = gts_file_getc_scope (f);
-  f->type = GTS_NONE;
-  while (c != EOF && (!in_string || !char_in_string (c, f->delimiters))) {
-    if (in_string) {
-      if (char_in_string (c, f->tokens)) {
-	f->next_token = c;
-	break;
-      }
-      g_string_append_c (f->token, c);
-    }
-    else if (!char_in_string (c, f->delimiters)) {
-      in_string = TRUE;
-      f->line = f->curline;
-      f->pos = f->curpos - 1;
-      g_string_append_c (f->token, c);
-      if (char_in_string (c, f->tokens)) {
-	f->type = c;
-	break;
-      }
-    }
-    c = gts_file_getc_scope (f);
-  }
-  if (f->type == GTS_NONE && f->token->len > 0) {
-    gchar * a;
-
-    a = f->token->str;
-    while (*a != '\0' && char_in_string (*a, "+-")) a++;
-    if (*a == '\0') {
-      f->type = GTS_STRING;
-      return;
-    }
-    a = f->token->str;
-    while (*a != '\0' && char_in_string (*a, "+-0123456789")) a++;
-    if (*a == '\0') {
-      f->type = GTS_INT;
-      return;
-    }
-    a = f->token->str;
-    while (*a != '\0' && char_in_string (*a, "+-eE.")) a++;
-    if (*a == '\0') {
-      f->type = GTS_STRING;
-      return;
-    }
-    a = f->token->str;
-    while (*a != '\0' && char_in_string (*a, "+-0123456789eE.")) a++;
-    if (*a == '\0') {
-      f->type = GTS_FLOAT;
-      return;
-    }
-    a = f->token->str;
-    if (!strncmp (a, "0x", 2) || 
-	!strncmp (a, "-0x", 3) || 
-	!strncmp (a, "+0x", 3)) {
-      while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx")) a++;
-      if (*a == '\0') {
-	f->type = GTS_INT;
-	return;
-      }
-      a = f->token->str;
-      while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx.p")) a++;
-      if (*a == '\0') {
-	f->type = GTS_FLOAT;
-	return;
-      }
-    }
-    f->type = GTS_STRING;
-  }
-}
-
-/**
- * gts_file_first_token_after:
- * @f: a #GtsFile.
- * @type: a #GtsTokenType.
- *
- * Finds and sets the first token of a type different from @type 
- * occuring after a token of type @type.
- */
-void gts_file_first_token_after (GtsFile * f, GtsTokenType type)
-{
-  g_return_if_fail (f != NULL);
-
-  while (f->type != GTS_ERROR && 
-	 f->type != GTS_NONE &&
-	 f->type != type)
-    gts_file_next_token (f);
-  while (f->type == type)
-    gts_file_next_token (f);
-}
-
-/**
- * gts_file_assign_start:
- * @f: a #GtsFile.
- * @vars: a %GTS_NONE terminated array of #GtsFileVariable.
- *
- * Opens a block delimited by braces to read a list of optional
- * arguments specified by @vars.  
- *
- * If an error is encountered the @error field of @f is set.
- */
-void gts_file_assign_start (GtsFile * f, GtsFileVariable * vars)
-{
-  GtsFileVariable * var;
-
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (vars != NULL);
-
-  var = vars;
-  while (var->type != GTS_NONE)
-    (var++)->set = FALSE;
-
-  if (f->type != '{') {
-    gts_file_error (f, "expecting an opening brace");
-    return;
-  }
-
-  f->scope_max++;
-  gts_file_next_token (f);
-}
-
-/**
- * gts_file_assign_next:
- * @f: a #GtsFile.
- * @vars: a %GTS_NONE terminated array of #GtsFileVariable.
- *
- * Assigns the next optional argument of @vars read from @f.
- *
- * Returns: the variable of @vars which has been assigned or %NULL if
- * no variable has been assigned (if an error has been encountered the
- * @error field of @f is set).  
- */
-GtsFileVariable * gts_file_assign_next (GtsFile * f, GtsFileVariable * vars)
-{
-  GtsFileVariable * var;
-  gboolean found = FALSE;
-
-  g_return_val_if_fail (f != NULL, NULL);
-  g_return_val_if_fail (vars != NULL, NULL);
-
-  while (f->type == '\n')
-    gts_file_next_token (f);
-  if (f->type == '}') {
-    f->scope_max--;
-    gts_file_next_token (f);
-    return NULL;
-  }
-  if (f->type == GTS_ERROR)
-    return NULL;
-
-  var = vars;
-  while (f->type != GTS_ERROR && var->type != GTS_NONE && !found) {
-    if (!strcmp (var->name, f->token->str)) {
-      found = TRUE;
-      if (var->unique && var->set)
-	gts_file_error (f, "variable `%s' was already set at line %d:%d", 
-			var->name, var->line, var->pos);
-      else {
-	var->line = f->line;
-	var->pos = f->pos;
-	gts_file_next_token (f);
-	if (f->type != '=')
-	  gts_file_error (f, "expecting `='");
-	else {
-	  var->set = TRUE;
-	  switch (var->type) {
-	  case GTS_FILE:
-	    break;
-	  case GTS_INT:
-	    gts_file_next_token (f);
-	    if (f->type != GTS_INT) {
-	      gts_file_error (f, "expecting an integer");
-	      var->set = FALSE;
-	    }
-	    else if (var->data)
-	      *((gint *) var->data) = atoi (f->token->str); 
-	    break;
-	  case GTS_UINT:
-	    gts_file_next_token (f);
-	    if (f->type != GTS_INT) {
-	      gts_file_error (f, "expecting an integer");
-	      var->set = FALSE;
-	    }
-	    else if (var->data)
-	      *((guint *) var->data) = atoi (f->token->str); 
-	    break;
-	  case GTS_FLOAT:
-	    gts_file_next_token (f);
-	    if (f->type != GTS_INT && f->type != GTS_FLOAT) {
-	      gts_file_error (f, "expecting a number");
-	      var->set = FALSE;
-	    }
-	    else if (var->data)
-	      *((gfloat *) var->data) = atof (f->token->str); 
-	    break;
-	  case GTS_DOUBLE:
-	    gts_file_next_token (f);
-	    if (f->type != GTS_INT && f->type != GTS_FLOAT) {
-	      gts_file_error (f, "expecting a number");
-	      var->set = FALSE;
-	    }
-	    else if (var->data)
-	      *((gdouble *) var->data) = atof (f->token->str); 
-	    break;
-	  case GTS_STRING:
-	    gts_file_next_token (f);
-	    if (f->type != GTS_INT && 
-		f->type != GTS_FLOAT && 
-		f->type != GTS_STRING) {
-	      gts_file_error (f, "expecting a string");
-	      var->set = FALSE;
-	    }
-	    else if (var->data)
-	      *((gchar **) var->data) = g_strdup (f->token->str); 
-	    break;
-	  default:
-	    g_assert_not_reached ();
-	  }
-	}
-      }
-    }
-    else
-      var++;
-  }
-  if (!found)
-    gts_file_error (f, "unknown identifier `%s'", f->token->str);
-  else if (f->type != GTS_ERROR) {
-    g_assert (var->set);
-    gts_file_next_token (f);
-    return var;
-  }
-  return NULL;
-}
-
-/**
- * gts_file_assign_variables:
- * @f: a #GtsFile.
- * @vars: an array of #GtsFileVariable.
- *
- * Assigns all the variables belonging to @vars found in @f.
- *
- * If an error is encountered the @error field of @f is set.
- */
-void gts_file_assign_variables (GtsFile * f, GtsFileVariable * vars)
-{
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (vars != NULL);
-
-  gts_file_assign_start (f, vars);
-  while (gts_file_assign_next (f, vars))
-    ;
-}
-
-/**
- * gts_file_variable_error:
- * @f: a #GtsFile.
- * @vars: an array of #GtsFileVariable.
- * @name: the name of a variable in @vars.
- * @format: the standard sprintf() format string.
- * @...: the parameters to insert into the format string.
- *
- * Sets the @error field of @f using gts_file_verror().
- *
- * String @name must match one of the variable names in @vars.
- *
- * If variable @name has been assigned (using gts_file_assign_variables())
- * sets the @line and @pos fields of @f to the line and position where
- * it has been assigned.
- */
-void gts_file_variable_error (GtsFile * f, 
-			      GtsFileVariable * vars,
-			      const gchar * name,
-			      const gchar * format,
-			      ...)
-{
-  va_list args;
-  GtsFileVariable * var;
-
-  g_return_if_fail (f != NULL);
-  g_return_if_fail (vars != NULL);
-  g_return_if_fail (name != NULL);
-  g_return_if_fail (format != NULL);
-
-  var = vars;
-  while (var->type != GTS_NONE && strcmp (var->name, name))
-    var++;
-
-  g_return_if_fail (var->type != GTS_NONE); /* @name not found in @vars */
-
-  if (var->set) {
-    f->line = var->line;
-    f->pos = var->pos;
-  }
-
-  va_start (args, format);  
-  gts_file_verror (f, format, args);
-  va_end (args);
-}
-
-#ifdef DEBUG_FUNCTIONS
-static GHashTable * ids = NULL;
-static guint next_id = 1;
-
-guint id (gpointer p)
-{
-  g_return_val_if_fail (p != NULL, 0);
-  g_return_val_if_fail (ids != NULL, 0);
-  g_assert (g_hash_table_lookup (ids, p));
-  return GPOINTER_TO_UINT (g_hash_table_lookup (ids, p));
-}
-
-void id_insert (gpointer p)
-{
-  g_return_if_fail (p != NULL);
-  if (ids == NULL) ids = g_hash_table_new (NULL, NULL);
-  g_assert (g_hash_table_lookup (ids, p) == NULL);
-  g_hash_table_insert (ids, p, GUINT_TO_POINTER (next_id++));
-}
-
-void id_remove (gpointer p)
-{
-  g_assert (g_hash_table_lookup (ids, p));  
-  g_hash_table_remove (ids, p);
-}
-
-void gts_write_triangle (GtsTriangle * t, 
-			 GtsPoint * o,
-			 FILE * fptr)
-{
-  gdouble xo = o ? o->x : 0.0;
-  gdouble yo = o ? o->y : 0.0;
-  gdouble zo = o ? o->z : 0.0;
-
-  g_return_if_fail (t != NULL && fptr != NULL);
-
-  fprintf (fptr, "(hdefine geometry \"t%d\" { =\n", id (t));
-  fprintf (fptr, "OFF 3 1 0\n"
-	   "%g %g %g\n%g %g %g\n%g %g %g\n3 0 1 2\n})\n"
-	   "(geometry \"t%d\" { : \"t%d\"})\n"
-	   "(normalization \"t%d\" none)\n",
-	   GTS_POINT (GTS_SEGMENT (t->e1)->v1)->x - xo, 
-	   GTS_POINT (GTS_SEGMENT (t->e1)->v1)->y - yo,
-	   GTS_POINT (GTS_SEGMENT (t->e1)->v1)->z - zo,
-	   GTS_POINT (GTS_SEGMENT (t->e1)->v2)->x - xo, 
-	   GTS_POINT (GTS_SEGMENT (t->e1)->v2)->y - yo, 
-	   GTS_POINT (GTS_SEGMENT (t->e1)->v2)->z - zo,
-	   GTS_POINT (gts_triangle_vertex (t))->x - xo,
-	   GTS_POINT (gts_triangle_vertex (t))->y - yo,
-	   GTS_POINT (gts_triangle_vertex (t))->z - zo,
-	   id (t), id (t), id (t));
-}
-
-void gts_write_segment (GtsSegment * s, 
-			GtsPoint * o,
-			FILE * fptr)
-{
-  gdouble xo = o ? o->x : 0.0;
-  gdouble yo = o ? o->y : 0.0;
-  gdouble zo = o ? o->z : 0.0;
-
-  g_return_if_fail (s != NULL && fptr != NULL);
-
-  fprintf (fptr, "(geometry \"s%d\" { =\n", id (s));
-  fprintf (fptr, "VECT 1 2 0 2 0 %g %g %g %g %g %g })\n"
-	   "(normalization \"s%d\" none)\n",
-	   GTS_POINT (s->v1)->x - xo, 
-	   GTS_POINT (s->v1)->y - yo, 
-	   GTS_POINT (s->v1)->z - zo,
-	   GTS_POINT (s->v2)->x - xo, 
-	   GTS_POINT (s->v2)->y - yo, 
-	   GTS_POINT (s->v2)->z - zo,
-	   id (s));
-}
-#endif /* DEBUG_FUNCTIONS */
diff --git a/src_3rd/gts/named.c b/src_3rd/gts/named.c
deleted file mode 100644
index 379f9f6..0000000
--- a/src_3rd/gts/named.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <string.h>
-#include "gts.h"
-
-static void nvertex_read (GtsObject ** po, GtsFile * fp)
-{
-  if ((*po)->klass->parent_class->read)
-    (* (*po)->klass->parent_class->read) (po, fp);
-
-  if (fp->type != '\n' && fp->type != GTS_ERROR) {
-    strncpy (GTS_NVERTEX (*po)->name, fp->token->str, GTS_NAME_LENGTH);
-    gts_file_next_token (fp);
-  }
-}
-
-static void nvertex_write (GtsObject * o, FILE * fptr)
-{
-  GtsNVertex * nv = GTS_NVERTEX (o);
-
-  (* o->klass->parent_class->write) (o, fptr);
-  if (nv->name[0] != '\0')
-    fprintf (fptr, " %s", nv->name);
-}
-
-static void nvertex_class_init (GtsNVertexClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->read = nvertex_read;
-  GTS_OBJECT_CLASS (klass)->write = nvertex_write;
-}
-
-static void nvertex_init (GtsNVertex * nvertex)
-{
-  nvertex->name[0] = '\0';
-}
-
-/**
- * gts_nvertex_class:
- *
- * Returns: the #GtsNVertexClass.
- */
-GtsNVertexClass * gts_nvertex_class (void)
-{
-  static GtsNVertexClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo nvertex_info = {
-      "GtsNVertex",
-      sizeof (GtsNVertex),
-      sizeof (GtsNVertexClass),
-      (GtsObjectClassInitFunc) nvertex_class_init,
-      (GtsObjectInitFunc) nvertex_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()), 
-				  &nvertex_info);
-  }
-
-  return klass;
-}
-
-static void nedge_read (GtsObject ** po, GtsFile * fp)
-{
-  if (fp->type != GTS_STRING) {
-    gts_file_error (fp, "expecting a string (name)");
-    return;
-  }
-  strncpy (GTS_NEDGE (*po)->name, fp->token->str, GTS_NAME_LENGTH);
-  gts_file_next_token (fp);
-}
-
-static void nedge_write (GtsObject * o, FILE * fptr)
-{
-  GtsNEdge * ne = GTS_NEDGE (o);
-
-  if (ne->name[0] != '\0')
-    fprintf (fptr, " %s", ne->name);
-}
-
-static void nedge_class_init (GtsNEdgeClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->read = nedge_read;
-  GTS_OBJECT_CLASS (klass)->write = nedge_write;
-}
-
-static void nedge_init (GtsNEdge * nedge)
-{
-  nedge->name[0] = '\0';
-}
-
-/**
- * gts_nedge_class:
- *
- * Returns: the #GtsNEdgeClass.
- */
-GtsNEdgeClass * gts_nedge_class (void)
-{
-  static GtsNEdgeClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo nedge_info = {
-      "GtsNEdge",
-      sizeof (GtsNEdge),
-      sizeof (GtsNEdgeClass),
-      (GtsObjectClassInitFunc) nedge_class_init,
-      (GtsObjectInitFunc) nedge_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_edge_class ()), 
-				  &nedge_info);
-  }
-
-  return klass;
-}
-
-static void nface_read (GtsObject ** po, GtsFile * fp)
-{
-  if (fp->type != GTS_STRING) {
-    gts_file_error (fp, "expecting a string (name)");
-    return;
-  }
-  strncpy (GTS_NFACE (*po)->name, fp->token->str, GTS_NAME_LENGTH);
-  gts_file_next_token (fp);
-}
-
-static void nface_write (GtsObject * o, FILE * fptr)
-{
-  GtsNFace * nf = GTS_NFACE (o);
-
-  if (nf->name[0] != '\0')
-    fprintf (fptr, " %s", GTS_NFACE (o)->name);
-}
-
-static void nface_class_init (GtsNFaceClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->read = nface_read;
-  GTS_OBJECT_CLASS (klass)->write = nface_write;
-}
-
-static void nface_init (GtsNFace * nface)
-{
-  nface->name[0] = '\0';
-}
-
-/**
- * gts_nface_class:
- *
- * Returns: the #GtsNFaceClass.
- */
-GtsNFaceClass * gts_nface_class (void)
-{
-  static GtsNFaceClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo nface_info = {
-      "GtsNFace",
-      sizeof (GtsNFace),
-      sizeof (GtsNFaceClass),
-      (GtsObjectClassInitFunc) nface_class_init,
-      (GtsObjectInitFunc) nface_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_face_class ()), 
-				  &nface_info);
-  }
-
-  return klass;
-}
diff --git a/src_3rd/gts/object.c b/src_3rd/gts/object.c
deleted file mode 100644
index 5970e50..0000000
--- a/src_3rd/gts/object.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <string.h>
-#include "gts.h"
-#include "gts-private.h"
-
-static GHashTable * class_table = NULL;
-
-static void gts_object_class_init (GtsObjectClass * klass,
-				   GtsObjectClass * parent_class)
-{
-  if (parent_class) {
-    gts_object_class_init (klass, parent_class->parent_class);
-    if (parent_class->info.class_init_func)
-      (*parent_class->info.class_init_func) (klass);
-  }
-}
-
-/**
- * gts_object_class_new:
- * @parent_class: a #GtsObjectClass.
- * @info: a #GtsObjectClassInfo, description of the new class to create.
- *
- * Returns: a new #GtsObjectClass derived from @parent_class and described by
- * @info.
- */
-gpointer gts_object_class_new (GtsObjectClass * parent_class,
-			       GtsObjectClassInfo * info)
-{
-  GtsObjectClass * klass;
-
-  g_return_val_if_fail (info != NULL, NULL);
-  g_return_val_if_fail (parent_class == NULL ||
-			info->object_size >= parent_class->info.object_size,
-			NULL);
-  g_return_val_if_fail (parent_class == NULL ||
-			info->class_size >= parent_class->info.class_size,
-			NULL);
-
-  klass = g_malloc0 (info->class_size);
-  klass->info = *info;
-  klass->parent_class = parent_class;
-  gts_object_class_init (klass, klass);
-
-  if (!class_table)
-    class_table = g_hash_table_new (g_str_hash, g_str_equal);
-  g_hash_table_insert (class_table, klass->info.name, klass);
-
-  return klass;
-}
-
-/**
- * gts_object_class_from_name:
- * @name: the name of a #GtsObjectClass.
- *
- * Returns: the #GtsObjectClass with name @name or %NULL if it hasn't been 
- * instantiated yet.
- */
-GtsObjectClass * gts_object_class_from_name (const gchar * name)
-{
-  g_return_val_if_fail (name != NULL, NULL);
-
-  if (!class_table)
-    return NULL;
-  return g_hash_table_lookup (class_table, name);
-}
-
-static void object_destroy (GtsObject * object)
-{
-#ifdef DEBUG_IDENTITY
-#ifdef DEBUG_LEAKS
-  fprintf (stderr, "destroy %s %p->%d\n", 
-	   object->klass->info.name,
-	   object, 
-	   id (object));
-#endif
-  id_remove (object);
-#endif
-  object->klass = NULL;
-  g_free (object);
-}
-
-static void object_clone (GtsObject * clone, GtsObject * object)
-{
-  memcpy (clone, object, object->klass->info.object_size);
-  clone->reserved = NULL;
-}
-
-static void object_class_init (GtsObjectClass * klass)
-{
-  klass->clone = object_clone;
-  klass->destroy = object_destroy;
-  klass->read = NULL;
-  klass->write = NULL;
-  klass->color = NULL;  
-  klass->attributes = NULL;
-}
-
-static void object_init (GtsObject * object)
-{
-  object->reserved = NULL;
-  object->flags = 0;
-}
-
-/**
- * gts_object_class:
- *
- * Returns: the #GtsObjectClass.
- */
-GtsObjectClass * gts_object_class (void)
-{
-  static GtsObjectClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo object_info = {
-      "GtsObject",
-      sizeof (GtsObject),
-      sizeof (GtsObjectClass),
-      (GtsObjectClassInitFunc) object_class_init,
-      (GtsObjectInitFunc) object_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (NULL, &object_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_object_check_cast:
- * @object: a #GtsObject.
- * @klass: a #GtsObjectClass.
- *
- * Returns: @object while emitting warnings if @object is not of class @klass.
- */
-gpointer gts_object_check_cast (gpointer object, 
-				gpointer klass)
-{
-  if (!object) {
-    g_warning ("invalid cast from (NULL) pointer to `%s'",
-	       GTS_OBJECT_CLASS (klass)->info.name);
-    return object;
-  }
-  if (!((GtsObject *) object)->klass) {
-    g_warning ("invalid unclassed pointer in cast to `%s'",
-	       GTS_OBJECT_CLASS (klass)->info.name);
-    return object;
-  }
-  if (!gts_object_is_from_class (object, klass)) {
-    g_warning ("invalid cast from `%s' to `%s'",
-	       ((GtsObject *) object)->klass->info.name,
-	       GTS_OBJECT_CLASS (klass)->info.name);
-    return object;
-  }
-  return object;
-}
-
-/**
- * gts_object_class_check_cast:
- * @klass: a #GtsObjectClass.
- * @from: a #GtsObjectClass.
- *
- * Returns: @klass while emitting warnings if @klass is not derived from
- * @from.
- */
-gpointer gts_object_class_check_cast (gpointer klass, 
-				      gpointer from)
-{
-  if (!klass) {
-    g_warning ("invalid cast from (NULL) pointer to `%s'",
-	       GTS_OBJECT_CLASS (from)->info.name);
-    return klass;
-  }
-  if (!gts_object_class_is_from_class (klass, from)) {
-    g_warning ("invalid cast from `%s' to `%s'",
-	       GTS_OBJECT_CLASS (klass)->info.name,
-	       GTS_OBJECT_CLASS (from)->info.name);
-    return klass;
-  }
-  return klass;
-}
-
-/**
- * gts_object_init:
- * @object: a #GtsObject.
- * @klass: a #GtsObjectClass.
- *
- * Calls the init method of @klass with @object as argument. This is done 
- * recursively in the correct order (from the base class to the top). You
- * should rarely need this function as it is called automatically by the
- * constructor for each class.
- */
-void gts_object_init (GtsObject * object, GtsObjectClass * klass)
-{
-  GtsObjectClass * parent_class;
-
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (klass != NULL);
-
-  parent_class = klass->parent_class;
-  if (parent_class)
-    gts_object_init (object, parent_class);
-  if (klass->info.object_init_func)
-    (*klass->info.object_init_func) (object);
-}
-
-/**
- * gts_object_new:
- * @klass: a #GtsObjectClass.
- *
- * Returns: a new initialized object of class @klass.
- */
-GtsObject * gts_object_new (GtsObjectClass * klass)
-{
-  GtsObject * object;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  object = g_malloc0 (klass->info.object_size);
-  object->klass = klass;
-  gts_object_init (object, klass);
-
-#ifdef DEBUG_IDENTITY
-  id_insert (object);
-#ifdef DEBUG_LEAKS
-  fprintf (stderr, "new %s %p->%d\n", klass->info.name, 
-	   object, 
-	   id (object));
-#endif
-#endif
-
-  return object;
-}
-
-/**
- * gts_object_clone:
- * @object: a #GtsObject.
- *
- * Calls the clone method of @object. The call to this function will fail
- * if no clone method exists for the given object.
- *
- * Returns: a new object clone of @object.
- */
-GtsObject * gts_object_clone (GtsObject * object)
-{
-  GtsObject * clone;
-
-  g_return_val_if_fail (object != NULL, NULL);
-  g_return_val_if_fail (object->klass->clone, NULL);
-
-  clone = g_malloc0 (object->klass->info.object_size);
-  clone->klass = object->klass;
-  object_init (clone);
-  (* object->klass->clone) (clone, object);
-
-#ifdef DEBUG_IDENTITY
-  id_insert (clone);
-#ifdef DEBUG_LEAKS
-  fprintf (stderr, "clone %s %p->%d\n", clone->klass->info.name, 
-	   clone, 
-	   id (clone));
-#endif
-#endif
-
-  return clone;
-}
-
-/**
- * gts_object_destroy:
- * @object: a #GtsObject.
- *
- * Calls the destroy method of @object, freeing all memory allocated for it.
- */
-void gts_object_destroy (GtsObject * object)
-{
-  g_assert (object->klass->destroy);
-  GTS_OBJECT_SET_FLAGS (object, GTS_DESTROYED);
-  (* object->klass->destroy) (object);
-}
-
-/**
- * gts_object_reset_reserved:
- * @object: a #GtsObject.
- *
- * Reset the reserved field of @object.
- */
-void gts_object_reset_reserved (GtsObject * object)
-{
-  g_return_if_fail (object != NULL);
-
-  object->reserved = NULL;
-}
-
-/**
- * gts_object_attributes:
- * @object: a #GtsObject.
- * @from: a #GtsObject.
- *
- * Calls the attributes() method of @object using @from as source.
- */
-void gts_object_attributes (GtsObject * object, GtsObject * from)
-{
-  g_return_if_fail (object != NULL);
-
-  if (object->klass->attributes)
-    (* object->klass->attributes) (object, from);
-}
-
-static void free_class (gchar * name, GtsObjectClass * klass)
-{
-  g_free (klass);
-}
-
-/**
- * gts_finalize:
- *
- * Free all the memory allocated by the object system of GTS. No other
- * GTS function can be called after this function has been called.
- */
-void gts_finalize (void)
-{
-  if (class_table) {
-    g_hash_table_foreach (class_table, (GHFunc) free_class, NULL);
-    g_hash_table_destroy (class_table);
-    class_table = NULL;
-  }
-}
diff --git a/src_3rd/gts/oocs.c b/src_3rd/gts/oocs.c
deleted file mode 100644
index f0d76bf..0000000
--- a/src_3rd/gts/oocs.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include "gts.h"
-
-static void cluster_destroy (GtsObject * object)
-{
-  GtsCluster * c = GTS_CLUSTER (object);
-
-  if (c->v && gts_vertex_is_unattached (c->v))
-    gts_object_destroy (GTS_OBJECT (c->v));
-
-  /* do not forget to call destroy method of the parent */
-  (* GTS_OBJECT_CLASS (gts_cluster_class ())->parent_class->destroy) (object);
-}
-
-static void cluster_add (GtsCluster * c, GtsPoint * p, gpointer data)
-{
-  GtsPoint * cp;
-
-  g_return_if_fail (c != NULL);
-  g_return_if_fail (c->v != NULL);
-  g_return_if_fail (p != NULL);
-
-  cp = GTS_POINT (c->v);
-  
-  cp->x += p->x;
-  cp->y += p->y;
-  cp->z += p->z;
-  c->n++;
-}
-
-static void cluster_update (GtsCluster * c)
-{
-  GtsPoint * p;
-
-  g_return_if_fail (c != NULL);
-  g_return_if_fail (c->v != NULL);
-
-  if (c->n > 1) {
-    p = GTS_POINT (c->v);
-    p->x /= c->n;
-    p->y /= c->n;
-    p->z /= c->n;
-  }
-}
-
-static void cluster_class_init (GtsClusterClass * klass)
-{
-  klass->add = cluster_add;
-  klass->update = cluster_update;
-
-  GTS_OBJECT_CLASS (klass)->destroy = cluster_destroy;
-}
-
-static void cluster_init (GtsCluster * c)
-{
-  c->v = NULL;
-  c->n = 0;
-}
-
-/**
- * gts_cluster_class:
- *
- * Returns: the #GtsClusterClass.
- */
-GtsClusterClass * gts_cluster_class (void)
-{
-  static GtsClusterClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo cluster_info = {
-      "GtsCluster",
-      sizeof (GtsCluster),
-      sizeof (GtsClusterClass),
-      (GtsObjectClassInitFunc) cluster_class_init,
-      (GtsObjectInitFunc) cluster_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), &cluster_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_cluster_new:
- * @klass: a #GtsClusterClass.
- * @id: the id of the new cluster.
- * @vklass: a #GtsVertexClass for the representative vertex of the cluster.
- *
- * Returns: a new #GtsCluster.
- */
-GtsCluster * gts_cluster_new (GtsClusterClass * klass,
-			      GtsClusterId id,
-			      GtsVertexClass * vklass)
-{
-  GtsCluster * c;
-
-  c = GTS_CLUSTER (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  c->id = id;
-  c->v = gts_vertex_new (vklass, 0., 0., 0.);
-
-  return c;
-}
-
-/**
- * gts_cluster_add:
- * @c: a #GtsCluster.
- * @p: a #GtsPoint.
- * @data: data to pass to the add() virtual method of #GtsClusterClass.
- *
- * Adds point @p to cluster @c.
- */
-void gts_cluster_add (GtsCluster * c, GtsPoint * p, gpointer data)
-{
-  g_return_if_fail (c != NULL);
-  g_return_if_fail (p != NULL);
-
-  (* GTS_CLUSTER_CLASS (GTS_OBJECT (c)->klass)->add) (c, p, data);
-}
-
-/**
- * gts_cluster_update:
- * @c: a #GtsCluster.
- *
- * Updates the position of the vertex representative of all the
- * vertices added to @c.  
- */
-void gts_cluster_update (GtsCluster * c)
-{
-  g_return_if_fail (c != NULL);
-
-  (* GTS_CLUSTER_CLASS (GTS_OBJECT (c)->klass)->update) (c);
-}
-
-static void destroy_cluster (GtsClusterId * id, GtsObject * cluster)
-{
-  gts_object_destroy (cluster);
-}
-
-static void cluster_grid_destroy (GtsObject * object)
-{
-  GtsClusterGrid * cluster_grid = GTS_CLUSTER_GRID (object);
-
-  g_hash_table_foreach (cluster_grid->clusters, 
-			(GHFunc) destroy_cluster, NULL);
-  g_hash_table_destroy (cluster_grid->clusters);
-  
-  (* GTS_OBJECT_CLASS (gts_cluster_grid_class ())->parent_class->destroy) 
-    (object);
-}
-
-static void cluster_grid_class_init (GtsClusterGridClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->destroy = cluster_grid_destroy;
-}
-
-static gint cluster_id_equal (gconstpointer v1,
-			      gconstpointer v2)
-{
-  const GtsClusterId * id1 = (const GtsClusterId *) v1;
-  const GtsClusterId * id2 = (const GtsClusterId *) v2;
-  return ((id1->x == id2->x) && (id1->y == id2->y) && (id1->z == id2->z));
-}
-
-static guint cluster_id_hash (gconstpointer key)
-{
-  const GtsClusterId * id = (const GtsClusterId *) key;
-  return id->x + id->y + id->z;
-}
-
-static void cluster_grid_init (GtsClusterGrid * cluster_grid)
-{
-  cluster_grid->surface = NULL;
-  cluster_grid->bbox = NULL;
-  cluster_grid->cluster_class = gts_cluster_class ();
-  cluster_grid->clusters = g_hash_table_new (cluster_id_hash,
-					      cluster_id_equal);
-}
-
-/**
- * gts_cluster_grid_class:
- *
- * Returns: the #GtsClusterGridClass.
- */
-GtsClusterGridClass * gts_cluster_grid_class (void)
-{
-  static GtsClusterGridClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo cluster_grid_info = {
-      "GtsClusterGrid",
-      sizeof (GtsClusterGrid),
-      sizeof (GtsClusterGridClass),
-      (GtsObjectClassInitFunc) cluster_grid_class_init,
-      (GtsObjectInitFunc) cluster_grid_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), &cluster_grid_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_cluster_grid_new:
- * @klass: a #GtsClusterGridClass.
- * @cluster_class: the klass to be used for the vertex clusters.
- * @s: the simplified surface.
- * @bbox: bounding box of the surface to be simplified.
- * @delta: the size of one grid cell of the simplification grid.
- *
- * Returns: a new #GtsClusterGrid.
- */
-GtsClusterGrid * gts_cluster_grid_new (GtsClusterGridClass * klass,
-				       GtsClusterClass * cluster_class,
-				       GtsSurface * s,
-				       GtsBBox * bbox,
-				       gdouble delta)
-{
-  GtsClusterGrid * cluster_grid;
-  GtsVector size;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (cluster_class != NULL, NULL);
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (bbox != NULL, NULL);
-  g_return_val_if_fail (delta > 0., NULL);
-
-  size[0] = ceil ((bbox->x2 - bbox->x1)/delta);
-  size[1] = ceil ((bbox->y2 - bbox->y1)/delta);
-  size[2] = ceil ((bbox->z2 - bbox->z1)/delta);
-  g_return_val_if_fail (size[0] <= 2.*G_MAXINT + 2. &&
-			size[1] <= 2.*G_MAXINT + 2. &&
-			size[2] <= 2.*G_MAXINT + 2., NULL);
-  cluster_grid = 
-    GTS_CLUSTER_GRID (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  cluster_grid->cluster_class = cluster_class;
-  cluster_grid->surface = s;
-  cluster_grid->bbox = bbox;
-  cluster_grid->size[0] = size[0];
-  cluster_grid->size[1] = size[1];
-  cluster_grid->size[2] = size[2];
-
-  return cluster_grid;
-}
-
-static GtsClusterId cluster_index (GtsPoint * p,
-				   GtsBBox * bb,
-				   GtsVector n)
-{
-  GtsClusterId id = {0, 0, 0};
-  
-  g_return_val_if_fail (p->x >= bb->x1 && p->x <= bb->x2, id);
-  g_return_val_if_fail (p->y >= bb->y1 && p->y <= bb->y2, id);
-  g_return_val_if_fail (p->z >= bb->z1 && p->z <= bb->z2, id);
-  
-  id.x = (guint) (p->x == bb->x2 ? n[0] - 1. : n[0]*(p->x - bb->x1)/(bb->x2 - bb->x1));
-  id.y = (guint) (p->y == bb->y2 ? n[1] - 1. : n[1]*(p->y - bb->y1)/(bb->y2 - bb->y1));
-  id.z = (guint) (p->z == bb->z2 ? n[2] - 1. : n[2]*(p->z - bb->z1)/(bb->z2 - bb->z1));
-
-  return id;
-}
-
-static GtsCluster * cluster_grid_add_point (GtsClusterGrid * cluster_grid,
-					    GtsPoint * p,
-					    gpointer data)
-{
-  GtsClusterId id = cluster_index (p, 
-				   cluster_grid->bbox, 
-				   cluster_grid->size);
-  GtsCluster * c = g_hash_table_lookup (cluster_grid->clusters, &id);
-
-  if (c == NULL) {
-    c = gts_cluster_new (cluster_grid->cluster_class, id, 
-			 cluster_grid->surface->vertex_class);
-    g_hash_table_insert (cluster_grid->clusters, &c->id, c);
-  }
-  
-  gts_cluster_add (c, p, data);
-  
-  return c;
-}
-
-/**
- * gts_cluster_grid_add_triangle:
- * @cluster_grid: a #GtsClusterGrid.
- * @p1: a #GtsPoint.
- * @p2: a #GtsPoint.
- * @p3: a #GtsPoint.
- * @data: user data to pass to the cluster add() method.
- *
- * Adds the triangle defined by @p1, @p2 and @p3 to the respective clusters
- * of @cluster_grid.
- */
-void gts_cluster_grid_add_triangle (GtsClusterGrid * cluster_grid,
-				    GtsPoint * p1,
-				    GtsPoint * p2,
-				    GtsPoint * p3,
-				    gpointer data)
-{
-  GtsCluster * c1, * c2, * c3;
-
-  g_return_if_fail (cluster_grid != NULL);
-  g_return_if_fail (p1 != NULL);
-  g_return_if_fail (p2 != NULL);
-  g_return_if_fail (p3 != NULL);
-  g_return_if_fail (cluster_grid->surface != NULL);
-
-  c1 = cluster_grid_add_point (cluster_grid, p1, data);
-  c2 = cluster_grid_add_point (cluster_grid, p2, data);
-  c3 = cluster_grid_add_point (cluster_grid, p3, data);
-  
-  if (c1 != c2 && c2 != c3 && c3 != c1) {
-    GtsVertex * v1, * v2, * v3;
-    GtsEdge * e1, * e2, * e3;
-    gboolean new_edge = FALSE;
-    
-    v1 = c1->v; v2 = c2->v; v3 = c3->v;
-
-    if ((e1 = GTS_EDGE (gts_vertices_are_connected (v1, v2))) == NULL) {
-      e1 = gts_edge_new (cluster_grid->surface->edge_class, v1, v2);
-      new_edge = TRUE;
-    }
-    if ((e2 = GTS_EDGE (gts_vertices_are_connected (v2, v3))) == NULL) {
-      e2 = gts_edge_new (cluster_grid->surface->edge_class, v2, v3);
-      new_edge = TRUE;
-    }
-    if ((e3 = GTS_EDGE (gts_vertices_are_connected (v3, v1))) == NULL) {
-      e3 = gts_edge_new (cluster_grid->surface->edge_class, v3, v1);
-      new_edge = TRUE;
-    }
-    if (new_edge || !gts_triangle_use_edges (e1, e2, e3))
-      gts_surface_add_face (cluster_grid->surface, 
-			    gts_face_new (cluster_grid->surface->face_class, 
-					  e1, e2, e3));
-  }
-}
-
-static void update_cluster (gint * id, GtsCluster * cluster, GtsRange * stats)
-{
-  gts_cluster_update (cluster);
-  gts_range_add_value (stats, cluster->n);
-}
-
-/**
- * gts_cluster_grid_update:
- * @cluster_grid: a #GtsClusterGrid.
- *
- * Updates the representative vertices of all the clusters of @cluster_grid.
- *
- * Returns: a #GtsRange describing the statistics for the number of vertices
- * added to each cluster of @cluster_grid.
- */
-GtsRange gts_cluster_grid_update (GtsClusterGrid * cluster_grid)
-{
-  GtsRange stats;
-
-  gts_range_init (&stats);
-  g_return_val_if_fail (cluster_grid != NULL, stats);
-
-  g_hash_table_foreach (cluster_grid->clusters, 
-			(GHFunc) update_cluster, &stats);
-  gts_range_update (&stats);
-
-  return stats;
-}
diff --git a/src_3rd/gts/partition.c b/src_3rd/gts/partition.c
deleted file mode 100644
index 3b73e68..0000000
--- a/src_3rd/gts/partition.c
+++ /dev/null
@@ -1,1219 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-
-#include "gts.h"
-
-/* #define DEBUG */
-
-/* Graph partition */
-
-/**
- * gts_graph_partition_edges_cut:
- * @partition: a list of @GtsGraph representing a partition.
- *
- * Returns: the number of edges cut by the partition.
- */
-guint gts_graph_partition_edges_cut (GSList * partition)
-{
-  guint cuts = 0;
-
-  while (partition) {
-    cuts += gts_graph_edges_cut (partition->data);
-    partition = partition->next;
-  }
-
-  return cuts/2;
-}
-
-/**
- * gts_graph_partition_edges_cut_weight:
- * @partition: a list of @GtsGraph representing a partition.
- *
- * Returns: the total weight of the edges cut by the partition.
- */
-gfloat gts_graph_partition_edges_cut_weight (GSList * partition)
-{
-  gfloat weight = 0.;
-
-  while (partition) {
-    weight += gts_graph_edges_cut_weight (partition->data);
-    partition = partition->next;
-  }
-
-  return weight/2.;
-}
-
-/**
- * gts_graph_partition_print_stats:
- * @partition: a list of @GtsGraph representing a partition.
- * @fp: a file pointer.
- *
- * Writes to @fp a summary of the properties of @partition.
- */
-void gts_graph_partition_print_stats (GSList * partition,
-				      FILE * fp)
-{
-  GtsRange weight;
-  GSList * i;
-
-  g_return_if_fail (partition != NULL);
-  g_return_if_fail (fp != NULL);
-
-  gts_range_init (&weight);
-  i = partition;
-  while (i) {
-    gts_range_add_value (&weight, gts_graph_weight (i->data));
-    i = i->next;
-  }
-  gts_range_update (&weight);
-
-  fprintf (fp, 
-	   "# parts: %d\n"
-	   "#   edge cuts: %5d edge cuts weight: %5g\n"
-	   "#   weight: ",
-	   g_slist_length (partition),
-	   gts_graph_partition_edges_cut (partition),
-	   gts_graph_partition_edges_cut_weight (partition));
-  gts_range_print (&weight, fp);
-  fputc ('\n', fp);
-}
-
-/**
- * gts_graph_partition_balance:
- * @partition: a list of @GtsGraph representing a partition.
- *
- * Returns: the difference between the maximum and the minimum weight
- * of the graphs in @partition.  
- */
-gfloat gts_graph_partition_balance (GSList * partition)
-{
-  gfloat wmin = G_MAXFLOAT;
-  gfloat wmax = - G_MAXFLOAT;
-
-  g_return_val_if_fail (partition != NULL, 0.);
-
-  while (partition) {
-    gfloat weight = gts_graph_weight (partition->data);
-    if (weight < wmin)
-      wmin = weight;
-    if (weight > wmax)
-      wmax = weight;
-    partition = partition->next;
-  }
-  return wmax - wmin;
-}
-
-/**
- * gts_graph_partition_clone:
- * @partition: a list of @GtsGraph representing a partition.
- *
- * Returns: a new partition clone of @partition (i.e. a list of new
- * graphs clones of the graphs in @partition).  
- */
-GSList * gts_graph_partition_clone (GSList * partition)
-{
-  GSList * cparts = NULL;
-
-  while (partition) {
-    cparts = 
-      g_slist_prepend (cparts, 
-		       gts_object_clone (GTS_OBJECT (partition->data)));
-    partition = partition->next;
-  }
-  return cparts;
-}
-
-/**
- * gts_graph_partition_destroy:
- * @partition: a list of @GtsGraph representing a partition.
- *
- * Destroys all the graphs in @partition and frees @partition.
- */
-void gts_graph_partition_destroy (GSList * partition)
-{
-  GSList * i = partition;
-
-  while (i) {
-    gts_object_destroy (GTS_OBJECT (i->data));
-    i = i->next;
-  }
-  g_slist_free (partition);
-}
-
-static void find_smallest_degree (GtsGNode * n, gpointer * data)
-{
-  GtsGNode ** nmin = data[0];
-  GtsGraph * g = data[1];
-  guint * min = data[2];
-  guint degree = gts_gnode_degree (n, g);
-
-  if (degree < *min) {
-    *min = degree;
-    *nmin = n;
-  }
-}
-
-static gint graph_comp_weight (GtsGraph * g1, GtsGraph * g2)
-{
-  if (gts_graph_weight (g1) > gts_graph_weight (g2))
-    return 1;
-  return -1;
-}
-
-static void partition_update (GSList * list, GtsGraph * g)
-{
-  GSList * i;
-  GtsGraph * g1;
-  GtsHeap * size_heap;
-  gboolean reinit = TRUE;
-
-  /* initialize traversals */
-  i = list;
-  while (i) {
-    GtsGNode * seed = GTS_OBJECT (i->data)->reserved;
-    GTS_OBJECT (seed)->reserved = 
-      gts_graph_traverse_new (g, seed, GTS_BREADTH_FIRST, reinit);
-    reinit = FALSE;
-    i = i->next;
-  }
-  
-  size_heap = gts_heap_new ((GCompareFunc) graph_comp_weight);
-  i = list;
-  while (i) {
-    gts_heap_insert (size_heap, i->data);
-    i = i->next;
-  }
-  while ((g1 = gts_heap_remove_top (size_heap))) {
-    GtsGraphTraverse * t = GTS_OBJECT (GTS_OBJECT (g1)->reserved)->reserved;
-    GtsGNode * n = gts_graph_traverse_next (t);
-    if (n) {
-      gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
-      gts_heap_insert (size_heap, g1);
-    }
-  }
-  gts_heap_destroy (size_heap);
-
-  /* destroy traversals */
-  i = list;
-  while (i) {
-    GtsGNode * seed = GTS_OBJECT (i->data)->reserved;
-    gts_graph_traverse_destroy (GTS_OBJECT (seed)->reserved);
-    GTS_OBJECT (seed)->reserved = NULL;
-    i = i->next;
-  }
-}
-
-static void better_seed (GtsGNode * n, gpointer * data)
-{
-  guint * sum = data[0];
-  GtsGNode ** seed = data[1];
-  GtsGraph * g = data[2];
-  guint sum1 = gts_graph_distance_sum (g, n);
-  
-  if (sum1 < *sum) {
-    *sum = sum1;
-    *seed = n;
-  }
-}
-
-static GtsGNode * graph_new_seed (GtsGraph * g, GtsGNode * seed)
-{
-  guint sum = gts_graph_distance_sum (g, seed);
-  gpointer data[3];
-  GtsGNode * new_seed = seed;
-
-  data[0] = ∑
-  data[1] = &new_seed;
-  data[2] = g;
-  gts_gnode_foreach_neighbor (seed, g, (GtsFunc) better_seed, data);
-
-  return new_seed;
-}
-
-/**
- * gts_graph_bubble_partition:
- * @g: a #GtsGraph.
- * @np: number of partitions.
- * @niter: the maximum number of iterations.
- * @step_info: a #GtsFunc or %NULL.
- * @data: user data to pass to @step_info.
- *
- * An implementation of the "bubble partitioning algorithm" of
- * Diekmann, Preis, Schlimbach and Walshaw (2000). The maximum number
- * of iteration on the positions of the graph growing seeds is
- * controlled by @niter.
- *
- * If not %NULL @step_info is called after each iteration on the seeds
- * positions passing the partition (a GSList) as argument.
- *
- * Returns: a list of @np new #GtsGraph representing the partition.  
- */
-GSList * gts_graph_bubble_partition (GtsGraph * g, 
-				     guint np, 
-				     guint niter,
-				     GtsFunc step_info,
-				     gpointer data)
-{
-  GSList * list = NULL, * seeds = NULL;
-  GtsGNode * seed = NULL;
-  guint min = G_MAXINT/2 - 1;
-  gpointer info[3];
-  GtsGraph * g1;
-  gboolean changed = TRUE;
-
-  g_return_val_if_fail (g != NULL, NULL);
-  g_return_val_if_fail (np > 0, NULL);
-
-  info[0] = &seed;
-  info[1] = g;
-  info[2] = &min;
-  gts_container_foreach (GTS_CONTAINER (g), 
-			 (GtsFunc) find_smallest_degree,
-			 info);
-  if (seed == NULL)
-    return NULL;
-
-  g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
-  gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
-  list = g_slist_prepend (list, g1);
-  GTS_OBJECT (g1)->reserved = seed;
-  seeds = g_slist_prepend (seeds, seed);
-
-  while (--np && seed)
-    if ((seed = gts_graph_farthest (g, seeds))) {
-      g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
-      gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
-      list = g_slist_prepend (list, g1);
-      GTS_OBJECT (g1)->reserved = seed;
-      seeds = g_slist_prepend (seeds, seed);
-    }
-  g_slist_free (seeds);
-  
-  partition_update (list, g);
-
-  while (changed && niter--) {
-    GSList * i;
-
-    changed = FALSE;
-    i = list;
-    while (i) {
-      GtsGraph * g1 = i->data;
-      GtsGNode * seed = GTS_OBJECT (g1)->reserved;
-      GtsGNode * new_seed = graph_new_seed (g1, seed);
-      if (new_seed != seed) {
-	changed = TRUE;
-	GTS_OBJECT (g1)->reserved = new_seed;
-      }
-      i = i->next;
-    }
-
-    if (changed) {
-      i = list;
-      while (i) {
-	GtsGraph * g1 = i->data;
-	GtsGNode * seed = GTS_OBJECT (g1)->reserved;
-
-	gts_object_destroy (GTS_OBJECT (g1));
-	i->data = g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
-	gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
-	GTS_OBJECT (g1)->reserved = seed;
-	i = i->next;
-      }
-      partition_update (list, g);
-      if (step_info)
-	(* step_info) (list, data);
-    }
-  }
-  g_slist_foreach (list, (GFunc) gts_object_reset_reserved, NULL);
-  return list;
-}
-
-/* Graph bisection */
-
-static gdouble node_cost (GtsGNode * n, gpointer * data)
-{
-  GtsGraph * g = data[0];
-  GtsGraph * g1 = data[1];
-  GSList * i = GTS_SLIST_CONTAINER (n)->items;
-  gdouble cost = 0.;
-
-  while (i) {
-    GtsGEdge * e = i->data;
-    GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, e);
-
-    if (gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) {
-      if (gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g1)))
-	cost -= gts_gedge_weight (e);
-      else 
-	cost += gts_gedge_weight (e);
-    }
-    i = i->next;
-  }
-
-  return cost;
-}
-
-static void add_neighbor (GtsGNode * n, GtsEHeap * heap)
-{
-  if (GTS_OBJECT (n)->reserved == n)
-    return;
-  if (GTS_OBJECT (n)->reserved)
-    gts_eheap_remove (heap, GTS_OBJECT (n)->reserved);
-  GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n);
-}
-
-static void add_unused (GtsGNode * n, GtsGraph * g2)
-{
-  if (GTS_OBJECT (n)->reserved)
-    GTS_OBJECT (n)->reserved = NULL;
-  else
-    gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
-}
-
-static gdouble degree_cost (GtsGNode * n, GtsGraph * g)
-{
-  return gts_gnode_degree (n, g); 
-}
-
-static void add_seed (GtsGNode * n, GtsEHeap * heap)
-{
-  gts_eheap_insert (heap, n);
-}
-
-static void boundary_node1 (GtsGNode * n, GtsGraphBisection * bg)
-{
-  GSList * i = GTS_SLIST_CONTAINER (n)->items;
-
-  while (i) {
-    GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-    if (gts_containee_is_contained (GTS_CONTAINEE (n1), 
-				    GTS_CONTAINER (bg->g2))) {
-      g_hash_table_insert (bg->bg1, n, n1);
-      return;
-    }
-    i = i->next;
-  }
-}
-
-static void boundary_node2 (GtsGNode * n, GtsGraphBisection * bg)
-{
-  GSList * i = GTS_SLIST_CONTAINER (n)->items;
-
-  while (i) {
-    GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-    if (gts_containee_is_contained (GTS_CONTAINEE (n1), 
-				    GTS_CONTAINER (bg->g1))) {
-      g_hash_table_insert (bg->bg2, n, n1);
-      return;
-    }
-    i = i->next;
-  }
-}
-
-static void check_bg (GtsGNode * n, gpointer * data)
-{
-  GHashTable * bg = data[0];
-  GtsGraph * g = data[1];
-  gboolean * ok = data[2];
-  guint * nb = data[3];
-  guint nn = gts_gnode_degree (n, g);
-
-  if (nn > 0)
-    (*nb)++;
-  if ((nn > 0 && !g_hash_table_lookup (bg, n)) ||
-      (nn == 0 && g_hash_table_lookup (bg, n))) {
-    g_warning ("nn: %d lookup: %p\n",
-	       nn, g_hash_table_lookup (bg, n));
-    *ok = FALSE;
-  }
-}
-
-/**
- * gts_graph_bisection_check:
- * @bg: a #GtsGraphBisection.
- *
- * Checks that the boundary of @bg is correctly defined (used for
- * debugging purposes).
- *
- * Returns: %TRUE if @bg is ok, %FALSE otherwise.  
- */
-gboolean gts_graph_bisection_check (GtsGraphBisection * bg)
-{
-  gboolean ok = TRUE;
-  guint nb;
-  gpointer data[4];
-
-  g_return_val_if_fail (bg != NULL, FALSE);
-
-  nb = 0;
-  data[0] = bg->bg1;
-  data[1] = bg->g2;
-  data[2] = &ok;
-  data[3] = &nb;
-  gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) check_bg, data);
-  g_return_val_if_fail (g_hash_table_size (bg->bg1) == nb, FALSE);
-
-  nb = 0;
-  data[0] = bg->bg2;
-  data[1] = bg->g1;
-  gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) check_bg, data);
-  g_return_val_if_fail (g_hash_table_size (bg->bg2) == nb, FALSE);
-
-  return ok;
-}
-
-/**
- * gts_graph_ggg_bisection:
- * @g: a #GtsGraph.
- * @ntry: the number of randomly selected initial seeds.
- *
- * An implementation of the "Greedy Graph Growing" algorithm of
- * Karypis and Kumar (1997).  
- *
- * @ntry randomly chosen seeds are used and the best partition is retained.
- *
- * Returns: a new #GtsGraphBisection of @g.
- */
-GtsGraphBisection * gts_graph_ggg_bisection (GtsGraph * g, guint ntry)
-{
-  gfloat size, bestcost = G_MAXFLOAT, smin;
-  GtsGraph * bestg1 = NULL, * bestg2 = NULL;
-  gboolean balanced = FALSE;
-  GtsEHeap * degree_heap;
-  GtsGNode * seed;
-  GtsGraphBisection * bg;
-
-  g_return_val_if_fail (g != NULL, NULL);
-
-  bg = g_malloc (sizeof (GtsGraphBisection));
-  bg->g = g;
-
-  size = gts_graph_weight (g)/2.;
-  smin = 0.9*size;
-
-  degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g);
-  gts_eheap_freeze (degree_heap);
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap);
-  gts_eheap_thaw (degree_heap);
-
-  while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) {
-    GtsGraph * g1, * g2;
-    GtsGNode * n;
-    gdouble cost;
-    gpointer data[2];
-    GtsEHeap * heap;
-  
-    g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
-			g->node_class, g->edge_class);
-    g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
-			g->node_class, g->edge_class);
-    
-    data[0] = g;
-    data[1] = g1;
-    heap = gts_eheap_new ((GtsKeyFunc) node_cost, data);
-
-    gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
-    GTS_OBJECT (seed)->reserved = seed;
-    gts_gnode_foreach_neighbor (seed, g, (GtsFunc) add_neighbor, heap);
-
-    while ((n = gts_eheap_remove_top (heap, &cost)))
-      if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) {
-	gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
-	GTS_OBJECT (n)->reserved = n;
-	gts_gnode_foreach_neighbor (n, g, (GtsFunc) add_neighbor, heap);
-      }
-      else
-	GTS_OBJECT (n)->reserved = NULL;
-    gts_eheap_destroy (heap);
-    
-    gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2);
-
-    cost = gts_graph_edges_cut_weight (g1);
-    if (!bestg1 || 
-	(!balanced && gts_graph_weight (g1) >= smin) ||
-	(cost < bestcost && gts_graph_weight (g1) >= smin)) {
-      if (bestg1)
-	bestcost = cost;
-      if (bestg1)
-	gts_object_destroy (GTS_OBJECT (bestg1));
-      if (bestg2)
-	gts_object_destroy (GTS_OBJECT (bestg2));
-      bestg1 = g1;
-      bestg2 = g2;
-      if (gts_graph_weight (g1) >= smin)
-	balanced = TRUE;
-    }
-    else {
-      gts_object_destroy (GTS_OBJECT (g1));
-      gts_object_destroy (GTS_OBJECT (g2));
-    }
-
-    ntry--;
-  }
-  gts_eheap_destroy (degree_heap);
-
-#ifdef DEBUG
-  fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n",
-	   bestcost, 
-	   gts_graph_weight (bestg1), 
-	   gts_container_size (GTS_CONTAINER (bestg1)),
-	   gts_graph_weight (bestg2), 
-	   gts_container_size (GTS_CONTAINER (bestg2)));
-#endif
-
-  g_assert (bestg1 != NULL);
-  bg->g1 = bestg1;
-  g_assert (bestg2 != NULL);
-  bg->g2 = bestg2;
-  
-  /* boundary nodes */
-  bg->bg1 = g_hash_table_new (NULL, NULL);
-  gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg);
-  bg->bg2 = g_hash_table_new (NULL, NULL);
-  gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg);
-
-  return bg;
-}
-
-/**
- * gts_graph_bfgg_bisection:
- * @g: a #GtsGraph.
- * @ntry: the number of randomly selected initial seeds.
- *
- * An implementation of a "Breadth-First Graph Growing" algorithm.
- *
- * @ntry randomly chosen seeds are used and the best partition is retained.
- *
- * Returns: a new #GtsGraphBisection of @g.
- */
-GtsGraphBisection * gts_graph_bfgg_bisection (GtsGraph * g, guint ntry)
-{
-  gfloat size, bestcost = G_MAXFLOAT, smin;
-  GtsGraph * bestg1 = NULL, * bestg2 = NULL;
-  GtsEHeap * degree_heap;
-  GtsGNode * seed;
-  GtsGraphBisection * bg;
-
-  g_return_val_if_fail (g != NULL, NULL);
-
-  bg = g_malloc (sizeof (GtsGraphBisection));
-  bg->g = g;
-
-  size = gts_graph_weight (g)/2.;
-  smin = 0.9*size;
-
-  degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g);
-  gts_eheap_freeze (degree_heap);
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap);
-  gts_eheap_thaw (degree_heap);
-
-  while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) {
-    GtsGraph * g1, * g2;
-    GtsGNode * n;
-    gdouble cost;
-    GtsGraphTraverse * t = gts_graph_traverse_new (g, seed, 
-						   GTS_BREADTH_FIRST, TRUE);
-    
-    g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
-			g->node_class, g->edge_class);
-    g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
-			g->node_class, g->edge_class);
-
-    while ((n = gts_graph_traverse_next (t)))
-      if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) {
-	gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
-	GTS_OBJECT (n)->reserved = n;
-      }
-    gts_graph_traverse_destroy (t);
-    
-    gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2);
-
-    cost = gts_graph_edges_cut_weight (g1);
-    if (!bestg1 || (cost < bestcost && gts_graph_weight (g1) >= smin)) {
-      if (bestg1)
-	bestcost = cost;
-      if (bestg1)
-	gts_object_destroy (GTS_OBJECT (bestg1));
-      if (bestg2)
-	gts_object_destroy (GTS_OBJECT (bestg2));
-      bestg1 = g1;
-      bestg2 = g2;
-    }
-    else {
-      gts_object_destroy (GTS_OBJECT (g1));
-      gts_object_destroy (GTS_OBJECT (g2));
-    }
-
-    ntry--;
-  }
-  gts_eheap_destroy (degree_heap);
-
-#ifdef DEBUG
-  fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n",
-	   bestcost, 
-	   gts_graph_weight (bestg1), 
-	   gts_container_size (GTS_CONTAINER (bestg1)),
-	   gts_graph_weight (bestg2), 
-	   gts_container_size (GTS_CONTAINER (bestg2)));
-#endif
-
-  bg->g1 = bestg1;
-  bg->g2 = bestg2;
-  
-  /* boundary nodes */
-  bg->bg1 = g_hash_table_new (NULL, NULL);
-  gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg);
-  bg->bg2 = g_hash_table_new (NULL, NULL);
-  gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg);
-
-  return bg;
-}
-
-static gdouble node_move_cost1 (GtsGNode * n, GtsGraphBisection * bg)
-{
-  return gts_gnode_move_cost (n, bg->g1, bg->g2);
-}
-
-static gdouble node_move_cost2 (GtsGNode * n, GtsGraphBisection * bg)
-{
-  return gts_gnode_move_cost (n, bg->g2, bg->g1);
-}
-
-static void build_heap (GtsGNode * n, GtsEHeap * heap)
-{
-  GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n);
-}
-
-/**
- * gts_graph_bisection_kl_refine:
- * @bg: a #GtsGraphBisection.
- * @mmax: the maximum number of unsuccessful successive moves.
- *
- * An implementation of the simplified Kernighan-Lin algorithm for
- * graph bisection refinement as described in Karypis and Kumar
- * (1997).
- *
- * The algorithm stops if @mmax consecutive modes do not lead to a
- * decrease in the number of edges cut. This last @mmax moves are
- * undone.
- *
- * Returns: the decrease in the weight of the edges cut by the bisection.  
- */
-gdouble gts_graph_bisection_kl_refine (GtsGraphBisection * bg,
-				       guint mmax)
-{
-  GtsEHeap * h1, * h2;
-  GtsGNode * n;
-  guint nm = 0, i;
-  GtsGNode ** moves;
-  gdouble bestcost = 0., totalcost = 0., best_balance;
-
-  g_return_val_if_fail (bg != NULL, 0.);
-  g_return_val_if_fail (mmax > 0, 0.);
-
-  h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg);
-  gts_eheap_freeze (h1);
-  gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) build_heap, h1);
-  gts_eheap_thaw (h1);
-
-  h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg);
-  gts_eheap_freeze (h2);
-  gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) build_heap, h2);
-  gts_eheap_thaw (h2);
-
-  moves = g_malloc (sizeof (GtsGNode *)*mmax);
-  best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2));
-
-  do {
-    GtsGraph * g1, * g2;
-    gdouble cost;
-
-    if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) {
-      n = gts_eheap_remove_top (h1, &cost);
-      g1 = bg->g1;
-      g2 = bg->g2;
-    }
-    else {
-      n = gts_eheap_remove_top (h2, &cost);
-      g1 = bg->g2;
-      g2 = bg->g1;
-    }
-    if (n) {
-      GSList * i;
-
-      GTS_OBJECT (n)->reserved = NULL;
-      gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
-      gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
-
-      totalcost += cost;
-      if (totalcost < bestcost) {
-	bestcost = totalcost;
-	nm = 0;
-      }
-      else if (totalcost == bestcost) {
-	gdouble balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2));
-
-	if (balance < best_balance) {
-	  best_balance = balance;
-	  nm = 0;
-	}
-      }	       
-      else
-	moves[nm++] = n;
-
-      i = GTS_SLIST_CONTAINER (n)->items;
-      while (i) {
-	GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-	if (GTS_OBJECT (n1)->reserved && 
-	    gts_containee_is_contained (GTS_CONTAINEE (n1), 
-					GTS_CONTAINER (bg->g))) {
-	  GtsEHeap * h = 
-	    gts_containee_is_contained (GTS_CONTAINEE (n1), 
-					GTS_CONTAINER (bg->g1)) ? h1 : h2;
-	  gts_eheap_remove (h, GTS_OBJECT (n1)->reserved);
-	  GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1);
-	}
-	i = i->next;
-      }
-    }
-  } while (n && nm < mmax);
-
-  gts_eheap_foreach (h1, (GFunc) gts_object_reset_reserved, NULL);
-  gts_eheap_foreach (h2, (GFunc) gts_object_reset_reserved, NULL);
-  gts_eheap_destroy (h1);
-  gts_eheap_destroy (h2);
-
-  /* undo last nm moves */
-  for (i = 0; i < nm; i++) {
-    GtsGNode * n = moves[i];
-    GtsGraph * g1 = 
-      gts_containee_is_contained (GTS_CONTAINEE (n),
-				  GTS_CONTAINER (bg->g1)) ? bg->g1 : bg->g2;
-    GtsGraph * g2 = g1 == bg->g1 ? bg->g2 : bg->g1;
-    
-    gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
-    gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
-  }
-  g_free (moves);
-
-  return bestcost;
-}
-
-static void build_bheap (GtsGNode * n, GtsGNode * n1, GtsEHeap * heap)
-{
-  GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n);
-}
-
-static void update_neighbors (GtsGNode * n, GtsGraphBisection * bg,
-			      GtsEHeap * h1, GtsEHeap * h2)
-{
-  GSList * i;
-
-  i = GTS_SLIST_CONTAINER (n)->items;
-  while (i) {
-    GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-    if (gts_containee_is_contained (GTS_CONTAINEE (n1), 
-				    GTS_CONTAINER (bg->g))) {
-      GtsEHeap * h;
-      GtsGraph /* * g1,*/ * g2;
-      GHashTable * bg1;
-
-      if (gts_containee_is_contained (GTS_CONTAINEE (n1),
-				      GTS_CONTAINER (bg->g1))) {
-	h = h1;
-	//g1 = bg->g1;
-	g2 = bg->g2;
-	bg1 = bg->bg1;
-      }
-      else {
-	h = h2;
-	//g1 = bg->g2;
-	g2 = bg->g1;
-	bg1 = bg->bg2;
-      }
-      g_hash_table_remove (bg1, n1);
-      if (h && GTS_OBJECT (n1)->reserved && GTS_OBJECT (n1)->reserved != n1) {
-	gts_eheap_remove (h, GTS_OBJECT (n1)->reserved);
-	GTS_OBJECT (n1)->reserved = NULL;
-      }
-      if (gts_gnode_degree (n1, g2)) {
-	g_hash_table_insert (bg1, n1, n1);
-	if (h && GTS_OBJECT (n1)->reserved != n1)
-	  GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1);
-      }
-    }
-    i = i->next;
-  }  
-}
-
-/**
- * gts_graph_bisection_bkl_refine:
- * @bg: a #GtsGraphBisection.
- * @mmax: the maximum number of unsuccessful successive moves.
- * @imbalance: the maximum relative imbalance allowed between the
- * weights of both halves of the partition.
- *
- * An implementation of the simplified boundary Kernighan-Lin
- * algorithm for graph bisection refinement as described in Karypis
- * and Kumar (1997).
- *
- * The algorithm stops if @mmax consecutive modes do not lead to a
- * decrease in the number of edges cut. This last @mmax moves are
- * undone.
- *
- * Returns: the decrease in the weight of the edges cut by the bisection.  
- */
-gdouble gts_graph_bisection_bkl_refine (GtsGraphBisection * bg,
-					guint mmax,
-					gfloat imbalance)
-{
-  GtsEHeap * h1, * h2;
-  GtsGNode * n;
-  guint nm = 0, i;
-  GtsGNode ** moves;
-  gdouble bestcost = 0., totalcost = 0., best_balance;
-  gboolean balanced = FALSE;
-
-  g_return_val_if_fail (bg != NULL, 0.);
-  g_return_val_if_fail (mmax > 0, 0.);
-  g_return_val_if_fail (imbalance >= 0. && imbalance <= 1., 0.);
-
-  h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg);
-  gts_eheap_freeze (h1);
-  g_hash_table_foreach (bg->bg1, (GHFunc) build_bheap, h1);
-  gts_eheap_thaw (h1);
-
-  h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg);
-  gts_eheap_freeze (h2);
-  g_hash_table_foreach (bg->bg2, (GHFunc) build_bheap, h2);
-  gts_eheap_thaw (h2);
-
-  moves = g_malloc (sizeof (GtsGNode *)*mmax);
-  imbalance *= gts_graph_weight (bg->g);
-  best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2));
-  if (best_balance <= imbalance)
-    balanced = TRUE;
-
-  do {
-    GtsGraph * g1, * g2;
-    GHashTable * bg1, * bg2;
-    gdouble cost;
-
-    if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) {
-      n = gts_eheap_remove_top (h1, &cost);
-      g1 = bg->g1;
-      g2 = bg->g2;
-      bg1 = bg->bg1;
-      bg2 = bg->bg2;
-    }
-    else {
-      n = gts_eheap_remove_top (h2, &cost);
-      g1 = bg->g2;
-      g2 = bg->g1;
-      bg1 = bg->bg2;
-      bg2 = bg->bg1;
-    }
-    if (n) {
-      gdouble balance;
-	
-      GTS_OBJECT (n)->reserved = n;
-      gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
-      gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
-      g_hash_table_remove (bg1, n);
-      if (gts_gnode_degree (n, g1))
-	g_hash_table_insert (bg2, n, n);
-
-      update_neighbors (n, bg, h1, h2);
-
-      totalcost += cost;
-      balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2));
-      
-      if (!balanced && balance <= imbalance) {
-	bestcost = totalcost;
-	best_balance = balance;
-	balanced = TRUE;
-	nm = 0;
-      }
-      else if (totalcost < bestcost && 
-	       (balance < best_balance || balance <= imbalance)) {
-	bestcost = totalcost;
-	best_balance = balance;
-	nm = 0;
-      }
-      else if (totalcost == bestcost && balance < best_balance) {
-	best_balance = balance;
-	nm = 0;
-      }
-      else
-	moves[nm++] = n;
-    }
-  } while (n && nm < mmax);
-
-  gts_container_foreach (GTS_CONTAINER (bg->g), 
-			 (GtsFunc) gts_object_reset_reserved, NULL);
-  gts_eheap_destroy (h1);
-  gts_eheap_destroy (h2);
-
-  /* undo last nm moves */
-  for (i = 0; i < nm; i++) {
-    GtsGNode * n = moves[i];
-    GtsGraph * g1, * g2;
-    GHashTable * bg1, * bg2;
-
-    if (gts_containee_is_contained (GTS_CONTAINEE (n),
-				    GTS_CONTAINER (bg->g1))) {
-      g1 = bg->g1;
-      g2 = bg->g2;
-      bg1 = bg->bg1;
-      bg2 = bg->bg2;
-    }
-    else {
-      g1 = bg->g2;
-      g2 = bg->g1;
-      bg1 = bg->bg2;
-      bg2 = bg->bg1;
-    }
-    
-    gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
-    gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
-    g_hash_table_remove (bg1, n);
-    if (gts_gnode_degree (n, g1))
-      g_hash_table_insert (bg2, n, n);
-
-    update_neighbors (n, bg, NULL, NULL);
-  }
-  g_free (moves);
-
-  return bestcost;
-}
-
-/* Multilevel partitioning */
-
-static void bisection_children (GtsGNodeSplit * ns, GtsGraphBisection * bg)
-{
-  GtsGraph * g, * g1;
-  GHashTable * bbg;
-  GtsGNode * n1 = GTS_GNODE_SPLIT_N1 (ns);
-  GtsGNode * n2 = GTS_GNODE_SPLIT_N2 (ns);
-
-  if (gts_containee_is_contained (GTS_CONTAINEE (ns->n),
-				  GTS_CONTAINER (bg->g1))) {
-    g = bg->g1;
-    g1 = bg->g2;
-    bbg = bg->bg1;
-  }
-  else {
-    g = bg->g2;
-    g1 = bg->g1;
-    bbg = bg->bg2;
-  }
-
-  gts_allow_floating_gnodes = TRUE;
-  gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n));
-  gts_allow_floating_gnodes = FALSE;
-  gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n1));
-  gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n2));
-
-  if (g_hash_table_lookup (bbg, ns->n)) {
-    g_hash_table_remove (bbg, ns->n);
-    if (gts_gnode_degree (n1, g1) > 0)
-      g_hash_table_insert (bbg, n1, n1);
-    if (gts_gnode_degree (n2, g1) > 0)
-      g_hash_table_insert (bbg, n2, n2);
-  }
-}
-
-/**
- * gts_graph_bisection_new:
- * @wg: a #GtsWGraph.
- * @ntry: the number of tries for the graph growing algorithm.
- * @mmax: the number of unsucessful moves for the refinement algorithm.
- * @nmin: the minimum number of nodes of the coarsest graph.
- * @imbalance: the maximum relative imbalance allowed between the
- * weights of both halves of the partition.
- *
- * An implementation of a multilevel bisection algorithm as presented
- * in Karypis and Kumar (1997). A multilevel hierarchy of graphs is
- * created using the #GtsPGraph object. The bisection of the coarsest
- * graph is created using the gts_graph_ggg_bisection() function. The
- * graph is then uncoarsened using gts_pgraph_down() and at each level
- * the bisection is refined using gts_graph_bisection_bkl_refine().
- *
- * Returns: a new #GtsGraphBisection of @wg.  
- */
-GtsGraphBisection * gts_graph_bisection_new (GtsWGraph * wg,
-					     guint ntry,
-					     guint mmax,
-					     guint nmin,
-					     gfloat imbalance)
-{
-  GtsGraph * g;
-  GtsPGraph * pg;
-  GtsGraphBisection * bg;
-  gdouble cost;
-
-  g_return_val_if_fail (wg != NULL, NULL);
-
-  g = GTS_GRAPH (wg);
-  pg = gts_pgraph_new (gts_pgraph_class (), g, 
-		       gts_gnode_split_class (),
-		       gts_wgnode_class (),
-		       gts_wgedge_class (),
-		       nmin);
-
-  bg = gts_graph_ggg_bisection (g, ntry);
-#ifdef DEBUG
-  fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n",
-	   gts_container_size (GTS_CONTAINER (bg->g1)),
-	   gts_graph_weight (bg->g1),
-	   gts_graph_edges_cut (bg->g1),
-	   gts_graph_edges_cut_weight (bg->g1));
-  g_assert (gts_graph_bisection_check (bg));
-#endif
-  while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) {
-#ifdef DEBUG
-    fprintf (stderr, "  cost: %g\n", cost);
-    g_assert (gts_graph_bisection_check (bg));
-#endif
-  }
-#ifdef DEBUG
-  fprintf (stderr, "after  size: %5d weight: %5g cuts: %5d cweight: %5g\n",
-	   gts_container_size (GTS_CONTAINER (bg->g1)),
-	   gts_graph_weight (bg->g1),
-	   gts_graph_edges_cut (bg->g1),
-	   gts_graph_edges_cut_weight (bg->g1));
-#endif
-  while (gts_pgraph_down (pg, (GtsFunc) bisection_children, bg)) {
-#ifdef DEBUG
-    fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n",
-	     gts_container_size (GTS_CONTAINER (bg->g1)),
-	     gts_graph_weight (bg->g1),
-	     gts_graph_edges_cut (bg->g1),
-	     gts_graph_edges_cut_weight (bg->g1));	   
-#endif
-    while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) {
-#ifdef DEBUG
-      fprintf (stderr, "  cost: %g\n", cost);
-      g_assert (gts_graph_bisection_check (bg));
-#endif
-    }
-#ifdef DEBUG
-    fprintf (stderr, "after  size: %5d weight: %5g cuts: %5d cweight: %5g\n",
-	     gts_container_size (GTS_CONTAINER (bg->g1)),
-	     gts_graph_weight (bg->g1),
-	     gts_graph_edges_cut (bg->g1),
-	     gts_graph_edges_cut_weight (bg->g1));
-#endif
-  }
-  gts_object_destroy (GTS_OBJECT (pg));
-
-  return bg;
-}
-
-/**
- * gts_graph_bisection_destroy:
- * @bg: a #GtsGraphBisection.
- * @destroy_graphs: controls graph destruction.
- *
- * Frees all the memory allocated for @bg. If @destroy_graphs is %TRUE
- * the graphs created by @bg are destroyed.  
- */
-void gts_graph_bisection_destroy (GtsGraphBisection * bg,
-				  gboolean destroy_graphs)
-{
-  g_return_if_fail (bg != NULL);
-
-  g_hash_table_destroy (bg->bg1);
-  g_hash_table_destroy (bg->bg2);
-
-  if (destroy_graphs) {
-    gts_object_destroy (GTS_OBJECT (bg->g1));
-    gts_object_destroy (GTS_OBJECT (bg->g2));
-  }
-
-  g_free (bg);
-}
-
-static void recursive_bisection (GtsWGraph * wg,
-				 guint np,
-				 guint ntry,
-				 guint mmax,
-				 guint nmin,
-				 gfloat imbalance,
-				 GSList ** list)
-{
-  if (np == 0)
-    *list = g_slist_prepend (*list, wg);
-  else {
-    GtsGraphBisection * bg = 
-      gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance);
-    GtsGraph * g1 = bg->g1;
-    GtsGraph * g2 = bg->g2;
-
-    gts_object_destroy (GTS_OBJECT (wg));
-    gts_graph_bisection_destroy (bg, FALSE);
-    recursive_bisection (GTS_WGRAPH (g1), np - 1, ntry, mmax, nmin, imbalance,
-			 list);
-    recursive_bisection (GTS_WGRAPH (g2), np - 1, ntry, mmax, nmin, imbalance,
-			 list);
-  }
-}
-
-/**
- * gts_graph_recursive_bisection:
- * @wg: a #GtsWGraph.
- * @n: the number of bisection levels.
- * @ntry: the number of tries for the graph growing algorithm.
- * @mmax: the number of unsucessful moves for the refinement algorithm.
- * @nmin: the minimum number of nodes of the coarsest graph.
- * @imbalance: the maximum relative imbalance allowed between the
- * weights of both halves of the partition.
- *
- * Calls gts_graph_bisection_new() recursively in order to obtain a
- * 2^@n partition of @wg.
- *
- * Returns: a list of 2^@n new #GtsGraph representing the partition.
- */
-GSList * gts_graph_recursive_bisection (GtsWGraph * wg,
-					guint n,
-					guint ntry,
-					guint mmax,
-					guint nmin,
-					gfloat imbalance)
-{
-  GtsGraphBisection * bg;
-  GtsGraph * g1, * g2;
-  GSList * list = NULL;
-
-  g_return_val_if_fail (wg != NULL, NULL);
-  g_return_val_if_fail (n > 0, NULL);
-  
-  bg = gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance);
-  g1 = bg->g1;
-  g2 = bg->g2;
-  gts_graph_bisection_destroy (bg, FALSE);
-  recursive_bisection (GTS_WGRAPH (g1), n - 1, ntry, mmax, nmin, imbalance, 
-		       &list);
-  recursive_bisection (GTS_WGRAPH (g2), n - 1, ntry, mmax, nmin, imbalance,
-		       &list);
-
-  return list;
-}
diff --git a/src_3rd/gts/pgraph.c b/src_3rd/gts/pgraph.c
deleted file mode 100644
index 6d1f619..0000000
--- a/src_3rd/gts/pgraph.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-/* GtsGNodeSplit */
-
-static void gnode_split_destroy (GtsObject * object)
-{
-  GtsGNodeSplit * ns = GTS_GNODE_SPLIT (object);
-
-  if (gts_container_size (GTS_CONTAINER (ns->n)) == 0) {
-    g_assert (GTS_SLIST_CONTAINEE (ns->n)->containers == NULL);
-    gts_object_destroy (GTS_OBJECT (ns->n));
-  }
-  else {
-    /* GtsGNode * n1 = GTS_GNODE_SPLIT_N1 (ns); */
-    /* GtsGNode * n2 = GTS_GNODE_SPLIT_N2 (ns); */
-
-    g_warning ("Memory deallocation for GtsGNodeSplit not fully implemented yet: memory leak!");
-  }
-
-  (* GTS_OBJECT_CLASS (gts_gnode_split_class ())->parent_class->destroy) 
-    (object);
-}
-
-static void gnode_split_class_init (GtsGNodeSplitClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->destroy = gnode_split_destroy;
-}
-
-static void gnode_split_init (GtsGNodeSplit * ns)
-{
-  ns->n = NULL;
-  ns->n1 = ns->n2 = NULL;
-}
-
-/**
- * gts_gnode_split_class:
- *
- * Returns: the #GtsGNodeSplitClass.
- */
-GtsGNodeSplitClass * gts_gnode_split_class (void)
-{
-  static GtsGNodeSplitClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo gnode_split_info = {
-      "GtsGNodeSplit",
-      sizeof (GtsGNodeSplit),
-      sizeof (GtsGNodeSplitClass),
-      (GtsObjectClassInitFunc) gnode_split_class_init,
-      (GtsObjectInitFunc) gnode_split_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), &gnode_split_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_gnode_split_new:
- * @klass: a #GtsGNodeSplitClass.
- * @n: a #GtsGNode.
- * @n1: a #GtsGNodeSplit or #GtsGNode.
- * @n2: a #GtsGNodeSplit or #GtsGNode.
- *
- * Creates a new #GtsGNodeSplit which would collapse @n1 and @n2 into
- * @n. The collapse itself is not performed.
- *
- * Returns: the new #GtsGNodeSplit.
- */
-GtsGNodeSplit * gts_gnode_split_new (GtsGNodeSplitClass * klass,
-				     GtsGNode * n, 
-				     GtsObject * n1,
-				     GtsObject * n2)
-{
-  GtsGNodeSplit * ns;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (n != NULL, NULL);
-  g_return_val_if_fail (GTS_IS_GNODE_SPLIT (n1) || GTS_IS_GNODE (n1), NULL);
-  g_return_val_if_fail (GTS_IS_GNODE_SPLIT (n2) || GTS_IS_GNODE (n2), NULL);
-
-  ns = GTS_GNODE_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  ns->n = n;
-  ns->n1 = n1;
-  ns->n2 = n2;
-
-  return ns;
-}
-
-static void connect_edge (GtsGEdge * e, gpointer * data)
-{
-  GtsGNode * n = data[0];
-  GtsGNode * n1 = data[1];
-  GtsGNode * n2 = data[2];
-
-  if (GTS_OBJECT (e)->reserved || /* edge is disconnected */
-      gts_gedge_connects (e, n1, n2))
-    return;
-  if (e->n1 == n1 || e->n1 == n2)
-    e->n1 = n;
-  else if (e->n2 == n1 || e->n2 == n2)
-    e->n2 = n;
-  else
-    g_assert_not_reached ();
-  gts_container_add (GTS_CONTAINER (n), GTS_CONTAINEE (e));
-}
-
-/**
- * gts_gnode_split_collapse:
- * @ns: a #GtsGNodeSplit.
- * @g: a #GtsGraph.
- * @klass: a #GtsWGEdgeClass.
- *
- * Collapses the node split @ns. Any new edge created during the
- * process will be of class @klass.  
- */
-void gts_gnode_split_collapse (GtsGNodeSplit * ns,
-			       GtsGraph * g,
-			       GtsWGEdgeClass * klass)
-{
-  GtsGNode * n1, * n2;
-  GSList * i;
-  gpointer data[3];
-
-  g_return_if_fail (ns != NULL);
-  g_return_if_fail (g != NULL);
-  g_return_if_fail (gts_container_size (GTS_CONTAINER (ns->n)) == 0);
-
-  n1 = GTS_GNODE_SPLIT_N1 (ns);
-  n2 = GTS_GNODE_SPLIT_N2 (ns);
-
-  /* look for triangles */
-  i = GTS_SLIST_CONTAINER (n1)->items;
-  while (i) {
-    GtsGEdge * e13 = i->data;
-    GtsGNode * n3 = GTS_GNODE_NEIGHBOR (n1, e13);
-    if (n3 != n2) {
-      GSList * j = GTS_SLIST_CONTAINER (n3)->items;
-      while (j) {
-	GtsGEdge * e32 = j->data;
-	GSList * next = j->next;
-	GtsGNode * n4 = GTS_GNODE_NEIGHBOR (n3, e32);
-	if (n4 == n2) { /* found triangle n1 (e13) n3 (e32) n2 */
-	  gts_wgedge_new (klass, ns->n, n3,
-			  gts_gedge_weight (e13) + gts_gedge_weight (e32));
-	  GTS_OBJECT (e13)->reserved = n3;
-	  GTS_OBJECT (e32)->reserved = n3;
-	  GTS_SLIST_CONTAINER (n3)->items = 
-	    g_slist_remove (GTS_SLIST_CONTAINER (n3)->items, e32);
-	}
-	j = next;
-      }
-      if (GTS_OBJECT (e13)->reserved == n3)
-	GTS_SLIST_CONTAINER (n3)->items = 
-	  g_slist_remove (GTS_SLIST_CONTAINER (n3)->items, e13);
-    }
-    i = i->next;
-  }
-
-  /* connect edges to new node */
-  data[0] = ns->n;
-  data[1] = n1;
-  data[2] = n2;
-  gts_container_foreach (GTS_CONTAINER (n1), (GtsFunc) connect_edge, data);
-  gts_container_foreach (GTS_CONTAINER (n2), (GtsFunc) connect_edge, data);
-
-  gts_allow_floating_gnodes = TRUE;
-  gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (n1));
-  gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (n2));
-  gts_allow_floating_gnodes = FALSE;
-  gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n));
-}
-
-static void restore_edge (GtsGEdge * e, gpointer * data)
-{
-  GtsGNode * n = data[0];
-  GtsGNode * n1 = data[1];
-  GtsGNode * n2 = data[2];
-  GtsGNode * n3 = GTS_OBJECT (e)->reserved;
-
-  if (n3) { /* e is a disconnected edge */
-    GTS_OBJECT (e)->reserved = NULL;
-    gts_container_add (GTS_CONTAINER (n3), GTS_CONTAINEE (e));
-    return;
-  }
-
-  if (gts_gedge_connects (e, n1, n2))
-    return;
-
-  if (e->n1 == n)
-    e->n1 = n1;
-  else if (e->n2 == n)
-    e->n2 = n1;
-  else
-    g_assert_not_reached ();
-  GTS_SLIST_CONTAINER (n)->items = 
-    g_slist_remove (GTS_SLIST_CONTAINER (n)->items, e);
-}
-
-/**
- * gts_gnode_split_expand:
- * @ns: a #GtsGNodeSplit.
- * @g: a #GtsGraph.
- *
- * Expands the node split ns adding the new nodes to @g.
- */
-void gts_gnode_split_expand (GtsGNodeSplit * ns,
-			     GtsGraph * g)
-{
-  GtsGNode * n1, * n2;
-  gpointer data[3];
-  GSList * i;
-
-  g_return_if_fail (ns != NULL);
-  g_return_if_fail (g != NULL);
-  g_return_if_fail (gts_containee_is_contained (GTS_CONTAINEE (ns->n), 
-						GTS_CONTAINER (g)));
-
-  n1 = GTS_GNODE_SPLIT_N1 (ns);
-  n2 = GTS_GNODE_SPLIT_N2 (ns);
-
-  data[0] = ns->n;
-  data[1] = n1;
-  data[2] = n2;
-  gts_container_foreach (GTS_CONTAINER (n1), (GtsFunc) restore_edge, data);
-  data[1] = n2;
-  data[2] = n1;
-  gts_container_foreach (GTS_CONTAINER (n2), (GtsFunc) restore_edge, data);
-
-  i = GTS_SLIST_CONTAINER (ns->n)->items;
-  while (i) {
-    GSList * next = i->next;
-    gts_container_remove (GTS_CONTAINER (ns->n), GTS_CONTAINEE (i->data));
-    i = next;
-  }
-  g_assert (gts_container_size (GTS_CONTAINER (ns->n)) == 0);
-  
-  gts_allow_floating_gnodes = TRUE;
-  gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n));
-  gts_allow_floating_gnodes = FALSE;
-
-  gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n1));
-  gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n2));
-}
-
-/* GtsPGraph */
-
-static void pgraph_destroy (GtsObject * object)
-{
-  GtsPGraph * pg = GTS_PGRAPH (object);
-  guint i;
-
-  for (i = 0; i < pg->split->len; i++)
-    gts_object_destroy (GTS_OBJECT (g_ptr_array_index (pg->split, i)));
-  g_ptr_array_free (pg->split, TRUE);
-  g_array_free (pg->levels, TRUE);
-
-  (* GTS_OBJECT_CLASS (gts_pgraph_class ())->parent_class->destroy) (object);
-}
-
-static void pgraph_class_init (GtsPGraphClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->destroy = pgraph_destroy;
-}
-
-static void pgraph_init (GtsPGraph * pg)
-{
-  pg->g = NULL;
-  pg->split = g_ptr_array_new ();
-  pg->levels = g_array_new (FALSE, FALSE, sizeof (guint));
-  pg->level = 0;
-  pg->split_class = gts_gnode_split_class ();
-  pg->edge_class = gts_wgedge_class ();
-  pg->pos = pg->min = 0;
-}
-
-/**
- * gts_pgraph_class:
- *
- * Returns: the #GtsPGraphClass.
- */
-GtsPGraphClass * gts_pgraph_class (void)
-{
-  static GtsPGraphClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo pgraph_info = {
-      "GtsPGraph",
-      sizeof (GtsPGraph),
-      sizeof (GtsPGraphClass),
-      (GtsObjectClassInitFunc) pgraph_class_init,
-      (GtsObjectInitFunc) pgraph_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), &pgraph_info);
-  }
-
-  return klass;
-}
-
-static void match_neighbor (GtsGNode * n, gpointer * data)
-{
-  if (!GTS_OBJECT (n)->reserved) {
-    GtsGraph * g = data[0];
-    GSList ** list = data[1];
-    GSList * i = GTS_SLIST_CONTAINER (n)->items;
-    gfloat wmax = - G_MAXFLOAT;
-    GtsGEdge * emax = NULL;
-    
-    while (i) {
-      GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
-      if (!GTS_OBJECT (n1)->reserved &&
-	  gts_gedge_weight (i->data) > wmax &&
-	  gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) {
-	emax = i->data;
-	wmax = gts_gedge_weight (emax);
-      }
-      i = i->next;
-    }
-    if (emax) {
-      GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, emax);
-
-      GTS_OBJECT (n1)->reserved = n;
-      GTS_OBJECT (n)->reserved = n1;
-      *list = g_slist_prepend (*list, emax);
-    }
-  }
-}
-
-static GSList * maximal_matching (GtsGraph * g)
-{
-  GSList * list = NULL;
-  gpointer data[2];
-
-  data[0] = g;
-  data[1] = &list;
-  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) match_neighbor, data);
-  gts_container_foreach (GTS_CONTAINER (g), 
-			 (GtsFunc) gts_object_reset_reserved,
-			 NULL);
-
-  return list;
-}
-
-/**
- * gts_pgraph_new:
- * @klass: a #GtsPGraphClass.
- * @g: a #GtsGraph.
- * @split_class: a #GtsGNodeSplitClass.
- * @node_class: a #GtsWGNodeClass.
- * @edge_class: a #GtsWGEdgeClass.
- * @min: the minimum number of nodes.
- *
- * Creates a new multilevel approximation of graph @g. At each level a
- * maximal matching is created using the Heavy Edge Matching (HEM)
- * technique of Karypis and Kumar (1997). The newly created nodes are
- * of type @node_class and their weight is set to the sum of the
- * weights of their children. The newly created edges are of type
- * @edge_class and their weight is set to the sum of the weight of the
- * collapsed edges. The last level is reached when the maximal
- * matching obtained would lead to a graph with less than @min nodes.
- *
- * Returns: the new #GtsPGraph containing the multilevel
- * representation of @g.  
- */
-GtsPGraph * gts_pgraph_new (GtsPGraphClass * klass,
-			    GtsGraph * g,
-			    GtsGNodeSplitClass * split_class,
-			    GtsWGNodeClass * node_class,
-			    GtsWGEdgeClass * edge_class,
-			    guint min)
-{
-  GtsPGraph * pg;
-  GSList * matching;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (g != NULL, NULL);
-  g_return_val_if_fail (split_class != NULL, NULL);
-  g_return_val_if_fail (node_class != NULL, NULL);
-  g_return_val_if_fail (edge_class != NULL, NULL);
-
-  pg = GTS_PGRAPH (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  pg->g = g;
-  pg->split_class = split_class;
-  pg->edge_class = edge_class;
-
-  while (gts_container_size (GTS_CONTAINER (g)) > min &&
-	 (matching = maximal_matching (g))) {
-    GSList * i = matching;
-    guint size = gts_container_size (GTS_CONTAINER (g));
-
-    g_array_append_val (pg->levels, size);
-
-    while (i && gts_container_size (GTS_CONTAINER (g)) > min) {
-      GtsGEdge * e = i->data;
-      GtsGNode * n = GTS_GNODE (gts_wgnode_new (node_class,
-						gts_gnode_weight (e->n1) +
-						gts_gnode_weight (e->n2)));
-      GtsGNodeSplit * ns = gts_gnode_split_new (split_class, n,
-						GTS_OBJECT (e->n1),
-						GTS_OBJECT (e->n2));
-      gts_gnode_split_collapse (ns, g, edge_class);
-      g_ptr_array_add (pg->split, ns);
-      i = i->next;
-    }
-    g_slist_free (matching);
-  }
-
-  pg->pos = pg->split->len;
-  pg->min = gts_container_size (GTS_CONTAINER (g));
-  pg->level = pg->levels->len;
-  
-  return pg;
-}
-
-/**
- * gts_pgraph_add_node:
- * @pg: a #GtsPGraph.
- *
- * Adds one node to the multilevel graph @pg by expanding the next
- * available #GtsGNodeSplit.
- *
- * Returns: the expanded #GtsGNodeSplit or #NULL if all the
- * #GtsGNodeSplit have already been expanded.  
- */
-GtsGNodeSplit * gts_pgraph_add_node (GtsPGraph * pg)
-{ 
-  GtsGNodeSplit * ns;
-
-  g_return_val_if_fail (pg != NULL, NULL);
-
-  if (pg->pos == 0)
-    return NULL;
-
-  ns = g_ptr_array_index (pg->split, --pg->pos);
-  gts_gnode_split_expand (ns, pg->g);
-
-  return ns;
-}
-
-/**
- * gts_pgraph_remove_node:
- * @pg: a #GtsPGraph.
- *
- * Removes one node from the multilevel graph @pg by collapsing the
- * first available #GtsGNodeSplit.
- *
- * Returns: the collapsed #GtsGNodeSplit or %NULL if all the
- * #GtsGNodeSplit have already been collapsed.  
- */
-GtsGNodeSplit * gts_pgraph_remove_node (GtsPGraph * pg)
-{
-  GtsGNodeSplit * ns;
-
-  g_return_val_if_fail (pg != NULL, NULL);
-
-  if (pg->pos == pg->split->len)
-    return NULL;
-
-  ns = g_ptr_array_index (pg->split, pg->pos++);
-  gts_gnode_split_collapse (ns, pg->g, pg->edge_class);
-
-  return ns;
-}
-
-/**
- * gts_pgraph_max_node_number:
- * @pg: a #GtsPGraph.
- *
- * Returns: the maximum number of nodes of @pg i.e. the number of
- * nodes if all the #GtsGNodeSplit were expanded.  
- */
-guint gts_pgraph_max_node_number (GtsPGraph * pg)
-{
-  g_return_val_if_fail (pg != NULL, 0);
-
-  return pg->min + pg->split->len;
-}
-
-/**
- * gts_pgraph_min_node_number:
- * @pg: a #GtsPGraph.
- *
- * Returns: the minimum number of nodes of @pg i.e. the number of
- * nodes if all the #GtsGNodeSplit were collapsed.  
- */
-guint gts_pgraph_min_node_number (GtsPGraph * pg)
-{
-  g_return_val_if_fail (pg != NULL, 0);
-
-  return pg->min;
-}
-
-/**
- * gts_pgraph_set_node_number:
- * @pg: a #GtsPGraph.
- * @n: a number of nodes.
- *
- * Performs the required number of collapses or expansions to set the
- * number of nodes of @pg to @n.
- */
-void gts_pgraph_set_node_number (GtsPGraph * pg, guint n)
-{
-  g_return_if_fail (pg != NULL);
-
-  n = pg->min + pg->split->len - n;
-  while (pg->pos > n && gts_pgraph_add_node (pg))
-    ;
-  while (pg->pos < n && gts_pgraph_remove_node (pg))
-    ;
-}
-
-/**
- * gts_pgraph_get_node_number:
- * @pg: a #GtsPGraph.
- *
- * Returns: the current number of nodes of @pg.
- */
-guint gts_pgraph_get_node_number (GtsPGraph * pg)
-{
-  g_return_val_if_fail (pg != NULL, 0);
-  
-  return pg->min + pg->split->len - pg->pos;
-}
-
-/**
- * gts_pgraph_down:
- * @pg: a #GtsPGraph.
- * @func: a #GtsFunc or %NULL.
- * @data: user data to pass to @func.
- *
- * Performs the required number of expansions to go from the current
- * level to the level immediately below.
- *
- * If @func is not %NULL, it is called after each #GtsGNodeSplit has
- * been expanded.  
- *
- * Returns: %FALSE if it is not possible to go down one level, %TRUE
- * otherwise.  
- */
-gboolean gts_pgraph_down (GtsPGraph * pg,
-			  GtsFunc func,
-			  gpointer data)
-{
-  guint size;
-
-  g_return_val_if_fail (pg != NULL, FALSE);
-
-  if (pg->level == 0)
-    return FALSE;
-
-  size = g_array_index (pg->levels, guint, --(pg->level));
-  while (gts_container_size (GTS_CONTAINER (pg->g)) < size) {
-    GtsGNodeSplit * ns = gts_pgraph_add_node (pg);
-
-    g_assert (ns);
-    if (func)
-      (* func) (ns, data);
-  }
-  return TRUE;
-}
-
diff --git a/src_3rd/gts/point.c b/src_3rd/gts/point.c
deleted file mode 100644
index 42fce69..0000000
--- a/src_3rd/gts/point.c
+++ /dev/null
@@ -1,986 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include "gts.h"
-#include "gts-private.h"
-#include "predicates.h"
-
-static void point_read (GtsObject ** o, GtsFile * f)
-{
-  GtsPoint * p = GTS_POINT (*o);
-
-  if (GTS_POINT_CLASS ((*o)->klass)->binary) {
-    if (gts_file_read (f, &(p->x), sizeof (gdouble), 1) != 1) {
-      gts_file_error (f, "expecting a binary number (x coordinate)");
-      return;
-    }
-    if (gts_file_read (f, &(p->y), sizeof (gdouble), 1) != 1) {
-      gts_file_error (f, "expecting a binary number (y coordinate)");
-      return;
-    }
-    if (gts_file_read (f, &(p->z), sizeof (gdouble), 1) != 1) {
-      gts_file_error (f, "expecting a binary number (z coordinate)");
-      return;
-    }
-  }
-  else {
-    if (f->type != GTS_INT && f->type != GTS_FLOAT) {
-      gts_file_error (f, "expecting a number (x coordinate)");
-      return;
-    }
-    p->x = atof (f->token->str);
-    
-    gts_file_next_token (f);
-    if (f->type != GTS_INT && f->type != GTS_FLOAT) {
-      gts_file_error (f, "expecting a number (y coordinate)");
-      return;
-    }
-    p->y = atof (f->token->str);
-    
-    gts_file_next_token (f);
-    if (f->type != GTS_INT && f->type != GTS_FLOAT) {
-      gts_file_error (f, "expecting a number (z coordinate)");
-      return;
-    }
-    p->z = atof (f->token->str);
-    
-    gts_file_next_token (f);
-  }
-}
-
-static void point_write (GtsObject * o, FILE * fptr)
-{
-  GtsPoint * p = GTS_POINT (o);
-
-  if (GTS_POINT_CLASS ((o)->klass)->binary) {
-    fwrite (&(p->x), sizeof (gdouble), 1, fptr);
-    fwrite (&(p->y), sizeof (gdouble), 1, fptr);
-    fwrite (&(p->z), sizeof (gdouble), 1, fptr);
-  }
-  else
-    fprintf (fptr, "%.10g %.10g %.10g", p->x, p->y, p->z);
-}
-
-static void point_class_init (GtsObjectClass * klass)
-{
-  klass->read = point_read;
-  klass->write = point_write;
-}
-
-/**
- * gts_point_class:
- *
- * Returns: the #GtsPointClass.
- */
-GtsPointClass * gts_point_class (void)
-{
-  static GtsPointClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo point_info = {
-      "GtsPoint",
-      sizeof (GtsPoint),
-      sizeof (GtsPointClass),
-      (GtsObjectClassInitFunc) point_class_init,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), 
-				  &point_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_point_new:
- * @klass: a #GtsPointClass.
- * @x: the x-coordinate.
- * @y: the y-coordinate.
- * @z: the z-coordinate.
- *
- * Returns: a new #GtsPoint.
- */
-GtsPoint * gts_point_new (GtsPointClass * klass,
-			  gdouble x, gdouble y, gdouble z)
-{
-  GtsPoint * p;
-  
-  p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  p->x = x;
-  p->y = y;
-  p->z = z;
-
-  return p;
-}
-
-/**
- * gts_point_set:
- * @p: a #GtsPoint.
- * @x: the x-coordinate.
- * @y: the y-coordinate.
- * @z: the z-coordinate.
- *
- * Sets the coordinates of @p.
- */
-void gts_point_set (GtsPoint * p, gdouble x, gdouble y, gdouble z)
-{
-  g_return_if_fail (p != NULL);
-
-  p->x = x;
-  p->y = y;
-  p->z = z;
-}
-
-/**
- * gts_point_distance:
- * @p1: a #GtsPoint.
- * @p2: another #GtsPoint.
- *
- * Returns: the Euclidean distance between @p1 and @p2.
- */
-gdouble gts_point_distance (GtsPoint * p1, GtsPoint * p2)
-{
-  g_return_val_if_fail (p1 != NULL && p2 != NULL, 0.0);
-  
-  return sqrt ((p1->x - p2->x)*(p1->x - p2->x) + 
-	       (p1->y - p2->y)*(p1->y - p2->y) + 
-	       (p1->z - p2->z)*(p1->z - p2->z));
-}
-
-/**
- * gts_point_distance2:
- * @p1: a #GtsPoint.
- * @p2: another #GtsPoint.
- *
- * Returns: the square of the Euclidean distance between @p1 and @p2.
- */
-gdouble gts_point_distance2 (GtsPoint * p1, GtsPoint * p2)
-{
-  g_return_val_if_fail (p1 != NULL && p2 != NULL, 0.0);
-  
-  return
-    (p1->x - p2->x)*(p1->x - p2->x) +
-    (p1->y - p2->y)*(p1->y - p2->y) + 
-    (p1->z - p2->z)*(p1->z - p2->z);
-}
-
-/**
- * gts_point_orientation_3d:
- * @p1: a #GtsPoint.
- * @p2: a #GtsPoint.
- * @p3: a #GtsPoint.
- * @p4: a #GtsPoint.
- *
- * Checks if @p4 lies above, below or on the plane passing through the
- * points @p1, @p2 and @p3. Below is defined so that @p1, @p2 and @p3
- * appear in counterclockwise order when viewed from above the
- * plane. The returned value is an approximation of six times the
- * signed volume of the tetrahedron defined by the four points. This
- * function uses adaptive floating point arithmetic and is
- * consequently geometrically robust.
- *
- * Returns: a positive value if @p4 lies below, a negative value if
- * @p4 lies above the plane, zero if the four points are coplanar.  
- */
-gdouble gts_point_orientation_3d (GtsPoint * p1,
-				  GtsPoint * p2,
-				  GtsPoint * p3,
-				  GtsPoint * p4)
-{
-  g_return_val_if_fail (p1 != NULL && p2 != NULL && 
-			p3 != NULL && p4 != NULL, 0.0);
-  return orient3d ((gdouble *) &p1->x, 
-		   (gdouble *) &p2->x, 
-		   (gdouble *) &p3->x, 
-		   (gdouble *) &p4->x);
-}
-
-/**
- * gts_point_is_in_triangle:
- * @p: a #GtsPoint.
- * @t: a #GtsTriangle.
- *
- * Tests if the planar projection (x, y) of @p is inside, outside or
- * on the boundary of the planar projection of @t.  This function is
- * geometrically robust.
- * 
- * Returns: %GTS_IN if @p is inside @t, %GTS_ON if @p is on the boundary of
- * @t, %GTS_OUT otherwise.  
- */
-GtsIntersect gts_point_is_in_triangle (GtsPoint * p, GtsTriangle * t)
-{
-  GtsVertex * v1, * v2, * v3;
-  gdouble d1, d2, d3;
-
-  g_return_val_if_fail (p != NULL && t != NULL, FALSE);
-
-  gts_triangle_vertices (t, &v1, &v2, &v3);
-
-  d1 = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p);
-  if (d1 < 0.0)
-    return GTS_OUT;
-  d2 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p);
-  if (d2 < 0.0)
-    return GTS_OUT;
-  d3 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p);
-  if (d3 < 0.0)
-    return GTS_OUT;
-  if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0)
-    return GTS_ON;
-  return GTS_IN;
-}
-
-/**
- * gts_point_in_triangle_circle:
- * @p: a #GtsPoint.
- * @t: a #GtsTriangle.
- *
- * Tests if the planar projection (x, y) of @p is inside or outside
- * the circumcircle of the planar projection of @t. This function is
- * geometrically robust.
- * 
- * Returns: a positive number if @p lies inside,
- * a negative number if @p lies outside and zero if @p lies on 
- * the circumcircle of @t.  
- */
-gdouble gts_point_in_triangle_circle (GtsPoint * p, GtsTriangle * t)
-{
-  GtsPoint * p1, * p2, * p3;
-
-  g_return_val_if_fail (p != NULL && t != NULL, 0.0);
-
-  gts_triangle_vertices (t, 
-			 (GtsVertex **) &p1, 
-			 (GtsVertex **) &p2, 
-			 (GtsVertex **) &p3);
-
-  return incircle ((gdouble *) &p1->x, 
-		   (gdouble *) &p2->x, 
-		   (gdouble *) &p3->x, 
-		   (gdouble *) &p->x);
-}
-
-/**
- * gts_point_in_circle:
- * @p: a #GtsPoint.
- * @p1: a #GtsPoint.
- * @p2: a #GtsPoint.
- * @p3: a #GtsPoint.
- *
- * Tests if the planar projection (x, y) of @p is inside or outside the
- * circle defined by the planar projection of @p1, @p2 and @p3.
- * 
- * Returns: a positive number if @p lies inside,
- * a negative number if @p lies outside and zero if @p lies on 
- * the circle.
- */
-gdouble gts_point_in_circle (GtsPoint * p, 
-			     GtsPoint * p1, GtsPoint * p2, GtsPoint * p3)
-{
-  g_return_val_if_fail (p != NULL && p1 != NULL && p2 != NULL && p3 != NULL, 
-			0.0);
-
-  return incircle ((gdouble *) &p1->x, 
-		   (gdouble *) &p2->x, 
-		   (gdouble *) &p3->x, 
-		   (gdouble *) &p->x);
-}
-
-/**
- * gts_point_in_sphere:
- * @p: a #GtsPoint.
- * @p1: a #GtsPoint.
- * @p2: a #GtsPoint.
- * @p3: a #GtsPoint.
- * @p4: a #GtsPoint.
- *
- * Tests if @p is inside or outside the sphere defined by @p1, @p2,
- * @p3 and @p4.
- * 
- * Returns: a positive number if @p lies inside,
- * a negative number if @p lies outside and zero if @p lies on 
- * the sphere.
- */
-gdouble gts_point_in_sphere (GtsPoint * p, 
-			     GtsPoint * p1, GtsPoint * p2, GtsPoint * p3, GtsPoint * p4)
-{
-  g_return_val_if_fail (p != NULL && p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL, 
-			0.0);
-
-  return insphere ((gdouble *) &p1->x, 
-		   (gdouble *) &p2->x, 
-		   (gdouble *) &p3->x, 
-		   (gdouble *) &p4->x, 
-		   (gdouble *) &p->x);
-}
-
-/**
- * gts_point_segment_distance2:
- * @p: a #GtsPoint.
- * @s: a #GtsSegment.
- *
- * Returns: the square of the minimun Euclidean distance between @p and @s.
- */
-gdouble gts_point_segment_distance2 (GtsPoint * p, GtsSegment * s)
-{
-  gdouble t, ns2, x, y, z;
-  GtsPoint * p1, * p2;
-
-  g_return_val_if_fail (p != NULL, 0.0);
-  g_return_val_if_fail (s != NULL, 0.0);
-
-  p1 = GTS_POINT (s->v1);
-  p2 = GTS_POINT (s->v2);
-  ns2 = gts_point_distance2 (p1, p2);
-  if (ns2 == 0.0)
-    return gts_point_distance2 (p, p1);
-  t = ((p2->x - p1->x)*(p->x - p1->x) + 
-       (p2->y - p1->y)*(p->y - p1->y) +
-       (p2->z - p1->z)*(p->z - p1->z))/ns2;
-  if (t > 1.0)
-    return gts_point_distance2 (p, p2);
-  if (t < 0.0)
-    return gts_point_distance2 (p, p1);
-  x = (1. - t)*p1->x + t*p2->x - p->x;
-  y = (1. - t)*p1->y + t*p2->y - p->y;
-  z = (1. - t)*p1->z + t*p2->z - p->z;
-  return x*x + y*y + z*z;
-}
-
-/**
- * gts_point_segment_distance:
- * @p: a #GtsPoint.
- * @s: a #GtsSegment.
- *
- * Returns: the minimun Euclidean distance between @p and @s.
- */
-gdouble gts_point_segment_distance (GtsPoint * p, GtsSegment * s)
-{
-  g_return_val_if_fail (p != NULL, 0.0);
-  g_return_val_if_fail (s != NULL, 0.0);
-
-  return sqrt (gts_point_segment_distance2 (p, s));
-}
-
-/**
- * gts_point_segment_closest:
- * @p: a #GtsPoint.
- * @s: a #GtsSegment.
- * @closest: a #GtsPoint.
- *
- * Set the coordinates of @closest to the coordinates of the point belonging
- * to @s closest to @p.
- */
-void gts_point_segment_closest (GtsPoint * p, 
-				GtsSegment * s,
-				GtsPoint * closest)
-{
-  gdouble t, ns2;
-  GtsPoint * p1, * p2;
-
-  g_return_if_fail (p != NULL);
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (closest != NULL);
-
-  p1 = GTS_POINT (s->v1);
-  p2 = GTS_POINT (s->v2);
-  ns2 = gts_point_distance2 (p1, p2);
-
-  if (ns2 == 0.0) {
-    gts_point_set (closest, p1->x, p1->y, p1->z);
-    return;
-  }
-
-  t = ((p2->x - p1->x)*(p->x - p1->x) + 
-       (p2->y - p1->y)*(p->y - p1->y) +
-       (p2->z - p1->z)*(p->z - p1->z))/ns2;
-
-  if (t > 1.0)
-    gts_point_set (closest, p2->x, p2->y, p2->z);
-  else if (t < 0.0)
-    gts_point_set (closest, p1->x, p1->y, p1->z);
-  else
-    gts_point_set (closest,
-		   (1. - t)*p1->x + t*p2->x,
-		   (1. - t)*p1->y + t*p2->y,
-		   (1. - t)*p1->z + t*p2->z);
-}
-
-/**
- * gts_point_triangle_distance2:
- * @p: a #GtsPoint.
- * @t: a #GtsTriangle.
- *
- * Returns: the square of the minimun Euclidean distance between @p and @t.
- */
-gdouble gts_point_triangle_distance2 (GtsPoint * p, GtsTriangle * t)
-{
-  GtsPoint * p1, * p2, * p3;
-  GtsEdge * e1, * e2, * e3;
-  GtsVector p1p2, p1p3, pp1;
-  gdouble A, B, C, D, E, det;
-  gdouble t1, t2;
-  gdouble x, y, z;
-
-  g_return_val_if_fail (p != NULL, 0.0);
-  g_return_val_if_fail (t != NULL, 0.0);
-
-  gts_triangle_vertices_edges (t, NULL, 
-			       (GtsVertex **) &p1, 
-			       (GtsVertex **) &p2, 
-			       (GtsVertex **) &p3, 
-			       &e1, &e2, &e3);
-
-  gts_vector_init (p1p2, p1, p2);
-  gts_vector_init (p1p3, p1, p3);
-  gts_vector_init (pp1, p, p1);
-
-  B = gts_vector_scalar (p1p3, p1p2);
-  E = gts_vector_scalar (p1p2, p1p2);
-  C = gts_vector_scalar (p1p3, p1p3);
-  
-  det = B*B - E*C;
-  if (det == 0.) { /* p1p2 and p1p3 are colinear */
-    gdouble d1 = gts_point_segment_distance2 (p, GTS_SEGMENT (e1));
-    gdouble d2 = gts_point_segment_distance2 (p, GTS_SEGMENT (e3));
-    if (d1 < d2)
-      return d1;
-    return d2;
-  }
-
-  A = gts_vector_scalar (p1p3, pp1);
-  D = gts_vector_scalar (p1p2, pp1);
-  
-  t1 = (D*C - A*B)/det;
-  t2 = (A*E - D*B)/det;
-
-  if (t1 < 0.)
-    return gts_point_segment_distance2 (p, GTS_SEGMENT (e3));
-  if (t2 < 0.)
-    return gts_point_segment_distance2 (p, GTS_SEGMENT (e1));
-  if (t1 + t2 > 1.)
-    return gts_point_segment_distance2 (p, GTS_SEGMENT (e2));
-
-  x = pp1[0] + t1*p1p2[0] + t2*p1p3[0];
-  y = pp1[1] + t1*p1p2[1] + t2*p1p3[1];
-  z = pp1[2] + t1*p1p2[2] + t2*p1p3[2];
-
-  return x*x + y*y + z*z;
-}
-
-/**
- * gts_point_triangle_distance:
- * @p: a #GtsPoint.
- * @t: a #GtsTriangle.
- *
- * Returns: the minimun Euclidean distance between @p and @t.
- */
-gdouble gts_point_triangle_distance (GtsPoint * p, GtsTriangle * t)
-{
-  g_return_val_if_fail (p != NULL, 0.0);
-  g_return_val_if_fail (t != NULL, 0.0);
-
-  return sqrt (gts_point_triangle_distance2 (p, t));
-}
-
-/**
- * gts_point_triangle_closest:
- * @p: a #GtsPoint.
- * @t: a #GtsTriangle.
- * @closest: a #GtsPoint.
- *
- * Set the coordinates of @closest to those of the point belonging to @t and 
- * closest to @p.
- */
-void gts_point_triangle_closest (GtsPoint * p, 
-				 GtsTriangle * t, 
-				 GtsPoint * closest)
-{
-  GtsPoint * p1, * p2, * p3;
-  GtsEdge * e1, * e2, * e3;
-  GtsVector p1p2, p1p3, pp1;
-  gdouble A, B, C, D, E, det;
-  gdouble t1, t2;
-
-  g_return_if_fail (p != NULL);
-  g_return_if_fail (t != NULL);
-  g_return_if_fail (closest != NULL);
-
-  gts_triangle_vertices_edges (t, NULL, 
-			       (GtsVertex **) &p1, 
-			       (GtsVertex **) &p2, 
-			       (GtsVertex **) &p3, 
-			       &e1, &e2, &e3);
-
-  gts_vector_init (p1p2, p1, p2);
-  gts_vector_init (p1p3, p1, p3);
-  gts_vector_init (pp1, p, p1);
-
-  B = gts_vector_scalar (p1p3, p1p2);
-  E = gts_vector_scalar (p1p2, p1p2);
-  C = gts_vector_scalar (p1p3, p1p3);
-  
-  det = B*B - E*C;
-  if (det == 0.) { /* p1p2 and p1p3 are colinear */
-    GtsPoint * cp = 
-      GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ())));
-    gts_point_segment_closest (p, GTS_SEGMENT (e1), cp);
-    gts_point_segment_closest (p, GTS_SEGMENT (e3), closest);
-
-    if (gts_point_distance2 (cp, p) < gts_point_distance2 (closest, p))
-      gts_point_set (closest, cp->x, cp->y, cp->z);
-    gts_object_destroy (GTS_OBJECT (cp));
-    return;
-  }
-
-  A = gts_vector_scalar (p1p3, pp1);
-  D = gts_vector_scalar (p1p2, pp1);
-  
-  t1 = (D*C - A*B)/det;
-  t2 = (A*E - D*B)/det;
-
-  if (t1 < 0.)
-    gts_point_segment_closest (p, GTS_SEGMENT (e3), closest);
-  else if (t2 < 0.)
-    gts_point_segment_closest (p, GTS_SEGMENT (e1), closest);
-  else if (t1 + t2 > 1.)
-    gts_point_segment_closest (p, GTS_SEGMENT (e2), closest);
-  else
-    gts_point_set (closest, 
-		   p1->x + t1*p1p2[0] + t2*p1p3[0],
-		   p1->y + t1*p1p2[1] + t2*p1p3[1],
-		   p1->z + t1*p1p2[2] + t2*p1p3[2]);
-}
-
-/**
- * gts_segment_triangle_intersection:
- * @s: a #GtsSegment.
- * @t: a #GtsTriangle.
- * @boundary: if %TRUE, the boundary of @t is taken into account.
- * @klass: a #GtsPointClass to be used for the new point.
- *
- * Checks if @s intersects @t. If this is the case, creates a new
- * point pi intersection of @s with @t.
- *
- * This function is geometrically robust in the sense that it will not
- * return a point if @s and @t do not intersect and will return a
- * point if @s and @t do intersect. However, the point coordinates are
- * subject to round-off errors.
- *
- * Note that this function will not return any point if @s is contained in
- * the plane defined by @t.
- * 
- * Returns: a summit of @t (if @boundary is set to %TRUE), one of the endpoints
- * of @s or a new #GtsPoint, intersection of @s with @t or %NULL if @s 
- * and @t don't intersect.  
- */
-GtsPoint * gts_segment_triangle_intersection (GtsSegment * s,
-					      GtsTriangle * t,
-					      gboolean boundary,
-					      GtsPointClass * klass)
-{
-  GtsPoint * A, * B, * C, * D, * E, * I;
-  gdouble ABCE, ABCD, ADCE, ABDE, BCDE;
-  gdouble c;
-
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (t != NULL, NULL);
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  A = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
-  B = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-  C = GTS_POINT (gts_triangle_vertex (t));
-  D = GTS_POINT (s->v1); 
-  E = GTS_POINT (s->v2);
-
-  ABCE = gts_point_orientation_3d (A, B, C, E);
-  ABCD = gts_point_orientation_3d (A, B, C, D);
-  if (ABCE < 0.0 || ABCD > 0.0) {
-    GtsPoint * tmpp;
-    gdouble tmp;
-    tmpp = E; E = D; D = tmpp;
-    tmp = ABCE; ABCE = ABCD; ABCD = tmp;
-  }
-  if (ABCE < 0.0 || ABCD > 0.0)
-    return NULL;
-  ADCE = gts_point_orientation_3d (A, D, C, E);
-  if ((boundary && ADCE < 0.) || (!boundary && ADCE <= 0.))
-    return NULL;
-  ABDE = gts_point_orientation_3d (A, B, D, E);
-  if ((boundary && ABDE < 0.) || (!boundary && ABDE <= 0.))
-    return NULL;
-  BCDE = gts_point_orientation_3d (B, C, D, E);
-  if ((boundary && BCDE < 0.) || (!boundary && BCDE <= 0.))
-    return NULL;
-  if (ABCE == 0.0) {
-    if (ABCD == 0.0)
-      /* s is contained in the plane defined by t*/
-      return NULL;
-    return E;
-  }
-  if (ABCD == 0.0)
-    return D;
-  if (boundary) { /* corners of @t */
-    if (ABDE == 0.) {
-      if (ADCE == 0.)
-	return A;
-      if (BCDE == 0.)
-	return B;
-    }
-    else if (BCDE == 0. && ADCE == 0.)
-      return C;
-  }
-  c = ABCE/(ABCE - ABCD);
-  I = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  gts_point_set (I,
-		 E->x + c*(D->x - E->x),
-		 E->y + c*(D->y - E->y),
-		 E->z + c*(D->z - E->z));
-  return I;
-}
-
-/**
- * gts_point_transform:
- * @p: a #GtsPoint.
- * @m: the #GtsMatrix representing the transformation to 
- * apply to the coordinates of @p.
- *
- * Transform the coordinates of @p according to @m. (p[] becomes m[][].p[]).
- */
-void gts_point_transform (GtsPoint * p, GtsMatrix * m)
-{
-  gdouble x, y, z;
-  g_return_if_fail (p != NULL && m != NULL);
-  x = m[0][0]*p->x + m[0][1]*p->y + m[0][2]*p->z + m[0][3];
-  y = m[1][0]*p->x + m[1][1]*p->y + m[1][2]*p->z + m[1][3];
-  z = m[2][0]*p->x + m[2][1]*p->y + m[2][2]*p->z + m[2][3];
-  p->x = x; p->y = y; p->z = z;
-}
-
-/**
- * gts_point_orientation:
- * @p1: a #GtsPoint.
- * @p2: a #GtsPoint.
- * @p3: a #GtsPoint.
- *
- * Checks for orientation of the projection of three points on the
- * (x,y) plane. The result is also an approximation of twice the
- * signed area of the triangle defined by the three points. This
- * function uses adaptive floating point arithmetic and is
- * consequently geometrically robust.
- *
- * Returns: a positive value if @p1, @p2 and @p3 appear in
- * counterclockwise order, a negative value if they appear in
- * clockwise order and zero if they are colinear.  
- */
-gdouble gts_point_orientation (GtsPoint * p1, GtsPoint * p2, GtsPoint * p3)
-{
-  g_return_val_if_fail (p1 != NULL && p2 != NULL && p3 != NULL, 0.0);
-
-  return orient2d ((gdouble *) &p1->x, 
-		   (gdouble *) &p2->x, 
-		   (gdouble *) &p3->x);
-}
-
-static gboolean ray_intersects_triangle (GtsPoint * D, GtsPoint * E,
-					 GtsTriangle * t)
-{
-  GtsPoint * A, * B, * C;
-  gint ABCE, ABCD, ADCE, ABDE, BCDE;
-
-  gts_triangle_vertices (t, (GtsVertex **) &A, 
-			 (GtsVertex **) &B, 
-			 (GtsVertex **) &C);
-
-  ABCE = gts_point_orientation_3d_sos (A, B, C, E);
-  ABCD = gts_point_orientation_3d_sos (A, B, C, D);
-  if (ABCE < 0 || ABCD > 0) {
-    GtsPoint * tmpp;
-    gint tmp;
-
-    tmpp = E; E = D; D = tmpp;
-    tmp = ABCE; ABCE = ABCD; ABCD = tmp;
-  }
-  if (ABCE < 0 || ABCD > 0)
-    return FALSE;
-  ADCE = gts_point_orientation_3d_sos (A, D, C, E);
-  if (ADCE < 0)
-    return FALSE;
-  ABDE = gts_point_orientation_3d_sos (A, B, D, E);
-  if (ABDE < 0)
-    return FALSE;
-  BCDE = gts_point_orientation_3d_sos (B, C, D, E);
-  if (BCDE < 0)
-    return FALSE;
-  return TRUE;
-}
-
-/** 
- * gts_point_is_inside_surface: 
- * @p: a #GtsPoint.  
- * @tree: a bounding box tree of the faces of a closed, orientable
- * surface (see gts_bb_tree_surface()).
- * @is_open: %TRUE if the surface defined by @tree is "open" i.e. its volume 
- * is negative, %FALSE otherwise.
- *
- * Returns: %TRUE if @p is inside the surface defined by @tree, %FALSE
- * otherwise.  
- */
-gboolean gts_point_is_inside_surface (GtsPoint * p, 
-				      GNode * tree,
-				      gboolean is_open)
-{
-  GSList * list, * i;
-  guint nc = 0;
-  GtsPoint * p1;
-  GtsBBox * bb;
-
-  g_return_val_if_fail (p != NULL, FALSE);
-  g_return_val_if_fail (tree != NULL, FALSE);
-
-  bb = tree->data;
-  p1 = gts_point_new (gts_point_class (), bb->x2 + fabs (bb->x2)/10., p->y, p->z);
-  i = list = gts_bb_tree_stabbed (tree, p);
-  while (i) {
-    GtsTriangle * t = GTS_TRIANGLE (GTS_BBOX (i->data)->bounded);
-
-    if (ray_intersects_triangle (p, p1, t))
-      nc++;
-    i = i->next;
-  }
-  g_slist_free (list);
-  gts_object_destroy (GTS_OBJECT (p1));
-
-  return is_open ? (nc % 2 == 0) : (nc % 2 != 0);
-}
-
-#define SIGN(x) ((x) > 0. ? 1 : -1)
-#define ORIENT1D(a,b) ((a) > (b) ? 1 : (a) < (b) ? -1 : 0)
-
-static gint sortp (gpointer * p, guint n)
-{
-  gint sign = 1;
-  guint i, j;
-
-  for (i = 0; i < n - 1; i++)
-    for (j = 0; j < n - 1 - i; j++)
-      if (GPOINTER_TO_UINT (p[j+1]) < GPOINTER_TO_UINT (p[j])) {
-	gpointer tmp = p[j];
-
-	p[j] = p[j+1];
-	p[j+1] = tmp;
-	sign = - sign;
-      }
-  return sign;
-}
-
-/**
- * gts_point_orientation_3d_sos:
- * @p1: a #GtsPoint.
- * @p2: a #GtsPoint.
- * @p3: a #GtsPoint.
- * @p4: a #GtsPoint.
- *
- * Checks if @p4 lies above or below the plane passing through the
- * points @p1, @p2 and @p3. Below is defined so that @p1, @p2 and @p3
- * appear in counterclockwise order when viewed from above the
- * plane. This function uses adaptive floating point arithmetic and is
- * consequently geometrically robust.
- *
- * Simulation of Simplicity (SoS) is used to break ties when the
- * orientation is degenerate (i.e. @p4 lies on the plane defined by
- * @p1, @p2 and @p3).
- *
- * Returns: +1 if @p4 lies below, -1 if @p4 lies above the plane.  
- */
-gint gts_point_orientation_3d_sos (GtsPoint * p1,
-				   GtsPoint * p2,
-				   GtsPoint * p3,
-				   GtsPoint * p4)
-{
-  gdouble o;
-
-  g_return_val_if_fail (p1 != NULL && p2 != NULL && 
-			p3 != NULL && p4 != NULL, 0);
-
-  o = orient3d ((gdouble *) &p1->x, 
-		(gdouble *) &p2->x, 
-		(gdouble *) &p3->x, 
-		(gdouble *) &p4->x);
-  if (o != 0.)
-    return SIGN (o);
-  else {
-    GtsPoint * p[4];
-    gdouble a[2], b[2], c[2];
-    gint sign;
-
-    p[0] = p1; p[1] = p2; p[2] = p3; p[3] = p4;
-    sign = sortp ((gpointer *) p, 4);
-    
-    /* epsilon^1/8 */
-    a[0] = p[1]->x; a[1] = p[1]->y;
-    b[0] = p[2]->x; b[1] = p[2]->y;
-    c[0] = p[3]->x; c[1] = p[3]->y;
-    o = orient2d (a, b, c);
-    if (o != 0.)
-      return SIGN (o)*sign;
-    
-    /* epsilon^1/4 */
-    a[0] = p[1]->x; a[1] = p[1]->z;
-    b[0] = p[2]->x; b[1] = p[2]->z;
-    c[0] = p[3]->x; c[1] = p[3]->z;
-    o = orient2d (a, b, c);
-    if (o != 0.)
-      return - SIGN (o)*sign;
-    
-    /* epsilon^1/2 */
-    a[0] = p[1]->y; a[1] = p[1]->z;
-    b[0] = p[2]->y; b[1] = p[2]->z;
-    c[0] = p[3]->y; c[1] = p[3]->z;
-    o = orient2d (a, b, c);
-    if (o != 0.)
-      return SIGN (o)*sign;
-    
-    /* epsilon */
-    a[0] = p[0]->x; a[1] = p[0]->y;
-    b[0] = p[2]->x; b[1] = p[2]->y;
-    c[0] = p[3]->x; c[1] = p[3]->y;
-    o = orient2d (a, b, c);
-    if (o != 0.)
-      return - SIGN (o)*sign;
-    
-    /* epsilon^5/4 */
-    o = ORIENT1D (p[2]->x, p[3]->x);
-    if (o != 0.)
-      return SIGN (o)*sign;
-    
-    /* epsilon^3/2 */
-    o = ORIENT1D (p[2]->y, p[3]->y);
-    if (o != 0.)
-      return - SIGN (o)*sign;
-    
-    /* epsilon^2 */
-    a[0] = p[0]->x; a[1] = p[0]->z;
-    b[0] = p[2]->x; b[1] = p[2]->z;
-    c[0] = p[3]->x; c[1] = p[3]->z;
-    o = orient2d (a, b, c);
-    if (o != 0.)
-      return SIGN (o)*sign;
-
-    /* epsilon^5/2 */
-    o = ORIENT1D (p[2]->z, p[3]->z);
-    if (o != 0.)
-      return SIGN (o)*sign;
-    
-    /* epsilon^4 */
-    a[0] = p[0]->y; a[1] = p[0]->z;
-    b[0] = p[2]->y; b[1] = p[2]->z;
-    c[0] = p[3]->y; c[1] = p[3]->z;
-    o = orient2d (a, b, c);
-    if (o != 0.)
-      return - SIGN (o)*sign;
-
-    /* epsilon^8 */
-    a[0] = p[0]->x; a[1] = p[0]->y;
-    b[0] = p[1]->x; b[1] = p[1]->y;
-    c[0] = p[3]->x; c[1] = p[3]->y;
-    o = orient2d (a, b, c);
-    if (o != 0.)
-      return SIGN (o)*sign;
-
-    /* epsilon^33/4 */
-    o = ORIENT1D (p[1]->x, p[3]->x);
-    if (o != 0.)
-      return - SIGN (o)*sign;
-    
-    /* epsilon^17/2 */
-    o = ORIENT1D (p[1]->y, p[3]->y);
-    if (o != 0.)
-      return SIGN (o)*sign;
-    
-    /* epsilon^10 */
-    o = ORIENT1D (p[0]->x, p[3]->x);
-    if (o != 0.)
-      return SIGN (o)*sign;
-    
-    /* epsilon^21/2 */
-    return sign;
-  }
-}
-
-/**
- * gts_point_orientation_sos:
- * @p1: a #GtsPoint.
- * @p2: a #GtsPoint.
- * @p3: a #GtsPoint.
- *
- * Checks for orientation of the projection of three points on the
- * (x,y) plane.
- *
- * Simulation of Simplicity (SoS) is used to break ties when the
- * orientation is degenerate (i.e. @p3 lies on the line defined by
- * @p1 and @p2).
- *
- * Returns: a positive value if @p1, @p2 and @p3 appear in
- * counterclockwise order or a negative value if they appear in
- * clockwise order.  
- */
-gint gts_point_orientation_sos (GtsPoint * p1,
-				GtsPoint * p2,
-				GtsPoint * p3)
-{
-  gdouble o;
-
-  g_return_val_if_fail (p1 != NULL && p2 != NULL && p3 != NULL, 0);
-
-  o = orient2d ((gdouble *) &p1->x, 
-		(gdouble *) &p2->x, 
-		(gdouble *) &p3->x);
-  if (o != 0.)
-    return SIGN (o);
-  else {
-    GtsPoint * p[3];
-    gint sign;
-
-    p[0] = p1; p[1] = p2; p[2] = p3;
-    sign = sortp ((gpointer *) p, 3);
-    
-    /* epsilon^1/4 */
-    o = ORIENT1D (p[1]->x, p[2]->x);
-    if (o != 0.)
-      return - SIGN (o)*sign;
-    
-    /* epsilon^1/2 */
-    o = ORIENT1D (p[1]->y, p[2]->y);
-    if (o != 0.)
-      return SIGN (o)*sign;
-    
-    /* epsilon */
-    o = ORIENT1D (p[0]->x, p[2]->x);
-    if (o != 0.)
-      return SIGN (o)*sign;
-    
-    /* epsilon^3/2 */
-    return sign;
-  }
-}
diff --git a/src_3rd/gts/predicates.c b/src_3rd/gts/predicates.c
deleted file mode 100644
index 7b7fcf2..0000000
--- a/src_3rd/gts/predicates.c
+++ /dev/null
@@ -1,2742 +0,0 @@
-/*****************************************************************************/
-/*                                                                           */
-/*  Routines for Arbitrary Precision Floating-point Arithmetic               */
-/*  and Fast Robust Geometric Predicates                                     */
-/*  (predicates.c)                                                           */
-/*                                                                           */
-/*  May 18, 1996                                                             */
-/*                                                                           */
-/*  Placed in the public domain by                                           */
-/*  Jonathan Richard Shewchuk                                                */
-/*  School of Computer Science                                               */
-/*  Carnegie Mellon University                                               */
-/*  5000 Forbes Avenue                                                       */
-/*  Pittsburgh, Pennsylvania  15213-3891                                     */
-/*  jrs at cs.cmu.edu                                                           */
-/*                                                                           */
-/*  This file contains C implementation of algorithms for exact addition     */
-/*    and multiplication of floating-point numbers, and predicates for       */
-/*    robustly performing the orientation and incircle tests used in         */
-/*    computational geometry.  The algorithms and underlying theory are      */
-/*    described in Jonathan Richard Shewchuk.  "Adaptive Precision Floating- */
-/*    Point Arithmetic and Fast Robust Geometric Predicates."  Technical     */
-/*    Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon      */
-/*    University, Pittsburgh, Pennsylvania, May 1996.  (Submitted to         */
-/*    Discrete & Computational Geometry.)                                    */
-/*                                                                           */
-/*  This file, the paper listed above, and other information are available   */
-/*    from the Web page http://www.cs.cmu.edu/~quake/robust.html .           */
-/*                                                                           */
-/*****************************************************************************/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  Using this code:                                                         */
-/*                                                                           */
-/*  First, read the short or long version of the paper (from the Web page    */
-/*    above).                                                                */
-/*                                                                           */
-/*  Be sure to call exactinit() once, before calling any of the arithmetic   */
-/*    functions or geometric predicates.  Also be sure to turn on the        */
-/*    optimizer when compiling this file.                                    */
-/*                                                                           */
-/*                                                                           */
-/*  Several geometric predicates are defined.  Their parameters are all      */
-/*    points.  Each point is an array of two or three floating-point         */
-/*    numbers.  The geometric predicates, described in the papers, are       */
-/*                                                                           */
-/*    orient2d(pa, pb, pc)                                                   */
-/*    orient2dfast(pa, pb, pc)                                               */
-/*    orient3d(pa, pb, pc, pd)                                               */
-/*    orient3dfast(pa, pb, pc, pd)                                           */
-/*    incircle(pa, pb, pc, pd)                                               */
-/*    incirclefast(pa, pb, pc, pd)                                           */
-/*    insphere(pa, pb, pc, pd, pe)                                           */
-/*    inspherefast(pa, pb, pc, pd, pe)                                       */
-/*                                                                           */
-/*  Those with suffix "fast" are approximate, non-robust versions.  Those    */
-/*    without the suffix are adaptive precision, robust versions.  There     */
-/*    are also versions with the suffices "exact" and "slow", which are      */
-/*    non-adaptive, exact arithmetic versions, which I use only for timings  */
-/*    in my arithmetic papers.                                               */
-/*                                                                           */
-/*                                                                           */
-/*  An expansion is represented by an array of floating-point numbers,       */
-/*    sorted from smallest to largest magnitude (possibly with interspersed  */
-/*    zeros).  The length of each expansion is stored as a separate integer, */
-/*    and each arithmetic function returns an integer which is the length    */
-/*    of the expansion it created.                                           */
-/*                                                                           */
-/*  Several arithmetic functions are defined.  Their parameters are          */
-/*                                                                           */
-/*    e, f           Input expansions                                        */
-/*    elen, flen     Lengths of input expansions (must be >= 1)              */
-/*    h              Output expansion                                        */
-/*    b              Input scalar                                            */
-/*                                                                           */
-/*  The arithmetic functions are                                             */
-/*                                                                           */
-/*    grow_expansion(elen, e, b, h)                                          */
-/*    grow_expansion_zeroelim(elen, e, b, h)                                 */
-/*    expansion_sum(elen, e, flen, f, h)                                     */
-/*    expansion_sum_zeroelim1(elen, e, flen, f, h)                           */
-/*    expansion_sum_zeroelim2(elen, e, flen, f, h)                           */
-/*    fast_expansion_sum(elen, e, flen, f, h)                                */
-/*    fast_expansion_sum_zeroelim(elen, e, flen, f, h)                       */
-/*    linear_expansion_sum(elen, e, flen, f, h)                              */
-/*    linear_expansion_sum_zeroelim(elen, e, flen, f, h)                     */
-/*    scale_expansion(elen, e, b, h)                                         */
-/*    scale_expansion_zeroelim(elen, e, b, h)                                */
-/*    compress(elen, e, h)                                                   */
-/*                                                                           */
-/*  All of these are described in the long version of the paper; some are    */
-/*    described in the short version.  All return an integer that is the     */
-/*    length of h.  Those with suffix _zeroelim perform zero elimination,    */
-/*    and are recommended over their counterparts.  The procedure            */
-/*    fast_expansion_sum_zeroelim() (or linear_expansion_sum_zeroelim() on   */
-/*    processors that do not use the round-to-even tiebreaking rule) is      */
-/*    recommended over expansion_sum_zeroelim().  Each procedure has a       */
-/*    little note next to it (in the code below) that tells you whether or   */
-/*    not the output expansion may be the same array as one of the input     */
-/*    expansions.                                                            */
-/*                                                                           */
-/*                                                                           */
-/*  If you look around below, you'll also find macros for a bunch of         */
-/*    simple unrolled arithmetic operations, and procedures for printing     */
-/*    expansions (commented out because they don't work with all C           */
-/*    compilers) and for generating random floating-point numbers whose      */
-/*    significand bits are all random.  Most of the macros have undocumented */
-/*    requirements that certain of their parameters should not be the same   */
-/*    variable; for safety, better to make sure all the parameters are       */
-/*    distinct variables.  Feel free to send email to jrs at cs.cmu.edu if you  */
-/*    have questions.                                                        */
-/*                                                                           */
-/*****************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include "predicates.h"
-
-/* Use header file generated automatically by predicates_init. */
-//#define USE_PREDICATES_INIT
-
-#ifdef USE_PREDICATES_INIT
-#include "predicates_init.h"
-#endif /* USE_PREDICATES_INIT */
-
-/* FPU control. We MUST have only double precision (not extended precision) */
-#include "rounding.h"
-
-/* On some machines, the exact arithmetic routines might be defeated by the  */
-/*   use of internal extended precision floating-point registers.  Sometimes */
-/*   this problem can be fixed by defining certain values to be volatile,    */
-/*   thus forcing them to be stored to memory and rounded off.  This isn't   */
-/*   a great solution, though, as it slows the arithmetic down.              */
-/*                                                                           */
-/* To try this out, write "#define INEXACT volatile" below.  Normally,       */
-/*   however, INEXACT should be defined to be nothing.  ("#define INEXACT".) */
-
-#define INEXACT                          /* Nothing */
-/* #define INEXACT volatile */
-
-#define REAL double                      /* float or double */
-#define REALPRINT doubleprint
-#define REALRAND doublerand
-#define NARROWRAND narrowdoublerand
-#define UNIFORMRAND uniformdoublerand
-
-/* Which of the following two methods of finding the absolute values is      */
-/*   fastest is compiler-dependent.  A few compilers can inline and optimize */
-/*   the fabs() call; but most will incur the overhead of a function call,   */
-/*   which is disastrously slow.  A faster way on IEEE machines might be to  */
-/*   mask the appropriate bit, but that's difficult to do in C.              */
-
-#define Absolute(a)  ((a) >= 0.0 ? (a) : -(a))
-/* #define Absolute(a)  fabs(a) */
-
-/* Many of the operations are broken up into two pieces, a main part that    */
-/*   performs an approximate operation, and a "tail" that computes the       */
-/*   roundoff error of that operation.                                       */
-/*                                                                           */
-/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(),    */
-/*   Split(), and Two_Product() are all implemented as described in the      */
-/*   reference.  Each of these macros requires certain variables to be       */
-/*   defined in the calling routine.  The variables `bvirt', `c', `abig',    */
-/*   `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because   */
-/*   they store the result of an operation that may incur roundoff error.    */
-/*   The input parameter `x' (or the highest numbered `x_' parameter) must   */
-/*   also be declared `INEXACT'.                                             */
-
-#define Fast_Two_Sum_Tail(a, b, x, y) \
-  bvirt = x - a; \
-  y = b - bvirt
-
-#define Fast_Two_Sum(a, b, x, y) \
-  x = (REAL) (a + b); \
-  Fast_Two_Sum_Tail(a, b, x, y)
-
-#define Fast_Two_Diff_Tail(a, b, x, y) \
-  bvirt = a - x; \
-  y = bvirt - b
-
-#define Fast_Two_Diff(a, b, x, y) \
-  x = (REAL) (a - b); \
-  Fast_Two_Diff_Tail(a, b, x, y)
-
-#define Two_Sum_Tail(a, b, x, y) \
-  bvirt = (REAL) (x - a); \
-  avirt = x - bvirt; \
-  bround = b - bvirt; \
-  around = a - avirt; \
-  y = around + bround
-
-#define Two_Sum(a, b, x, y) \
-  x = (REAL) (a + b); \
-  Two_Sum_Tail(a, b, x, y)
-
-#define Two_Diff_Tail(a, b, x, y) \
-  bvirt = (REAL) (a - x); \
-  avirt = x + bvirt; \
-  bround = bvirt - b; \
-  around = a - avirt; \
-  y = around + bround
-
-#define Two_Diff(a, b, x, y) \
-  x = (REAL) (a - b); \
-  Two_Diff_Tail(a, b, x, y)
-
-#define Split(a, ahi, alo) \
-  c = (REAL) (splitter * a); \
-  abig = (REAL) (c - a); \
-  ahi = c - abig; \
-  alo = a - ahi
-
-#define Two_Product_Tail(a, b, x, y) \
-  Split(a, ahi, alo); \
-  Split(b, bhi, blo); \
-  err1 = x - (ahi * bhi); \
-  err2 = err1 - (alo * bhi); \
-  err3 = err2 - (ahi * blo); \
-  y = (alo * blo) - err3
-
-#define Two_Product(a, b, x, y) \
-  x = (REAL) (a * b); \
-  Two_Product_Tail(a, b, x, y)
-
-/* Two_Product_Presplit() is Two_Product() where one of the inputs has       */
-/*   already been split.  Avoids redundant splitting.                        */
-
-#define Two_Product_Presplit(a, b, bhi, blo, x, y) \
-  x = (REAL) (a * b); \
-  Split(a, ahi, alo); \
-  err1 = x - (ahi * bhi); \
-  err2 = err1 - (alo * bhi); \
-  err3 = err2 - (ahi * blo); \
-  y = (alo * blo) - err3
-
-/* Two_Product_2Presplit() is Two_Product() where both of the inputs have    */
-/*   already been split.  Avoids redundant splitting.                        */
-
-#define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \
-  x = (REAL) (a * b); \
-  err1 = x - (ahi * bhi); \
-  err2 = err1 - (alo * bhi); \
-  err3 = err2 - (ahi * blo); \
-  y = (alo * blo) - err3
-
-/* Square() can be done more quickly than Two_Product().                     */
-
-#define Square_Tail(a, x, y) \
-  Split(a, ahi, alo); \
-  err1 = x - (ahi * ahi); \
-  err3 = err1 - ((ahi + ahi) * alo); \
-  y = (alo * alo) - err3
-
-#define Square(a, x, y) \
-  x = (REAL) (a * a); \
-  Square_Tail(a, x, y)
-
-/* Macros for summing expansions of various fixed lengths.  These are all    */
-/*   unrolled versions of Expansion_Sum().                                   */
-
-#define Two_One_Sum(a1, a0, b, x2, x1, x0) \
-  Two_Sum(a0, b , _i, x0); \
-  Two_Sum(a1, _i, x2, x1)
-
-#define Two_One_Diff(a1, a0, b, x2, x1, x0) \
-  Two_Diff(a0, b , _i, x0); \
-  Two_Sum( a1, _i, x2, x1)
-
-#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \
-  Two_One_Sum(a1, a0, b0, _j, _0, x0); \
-  Two_One_Sum(_j, _0, b1, x3, x2, x1)
-
-#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \
-  Two_One_Diff(a1, a0, b0, _j, _0, x0); \
-  Two_One_Diff(_j, _0, b1, x3, x2, x1)
-
-#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \
-  Two_One_Sum(a1, a0, b , _j, x1, x0); \
-  Two_One_Sum(a3, a2, _j, x4, x3, x2)
-
-#define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \
-  Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \
-  Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1)
-
-#define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \
-                      x1, x0) \
-  Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \
-  Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2)
-
-#define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \
-                      x3, x2, x1, x0) \
-  Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \
-  Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4)
-
-#define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \
-                      x6, x5, x4, x3, x2, x1, x0) \
-  Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \
-                _1, _0, x0); \
-  Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \
-                x3, x2, x1)
-
-#define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \
-                       x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \
-  Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \
-                _2, _1, _0, x1, x0); \
-  Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \
-                x7, x6, x5, x4, x3, x2)
-
-/* Macros for multiplying expansions of various fixed lengths.               */
-
-#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \
-  Split(b, bhi, blo); \
-  Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \
-  Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \
-  Two_Sum(_i, _0, _k, x1); \
-  Fast_Two_Sum(_j, _k, x3, x2)
-
-#define Four_One_Product(a3, a2, a1, a0, b, x7, x6, x5, x4, x3, x2, x1, x0) \
-  Split(b, bhi, blo); \
-  Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \
-  Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \
-  Two_Sum(_i, _0, _k, x1); \
-  Fast_Two_Sum(_j, _k, _i, x2); \
-  Two_Product_Presplit(a2, b, bhi, blo, _j, _0); \
-  Two_Sum(_i, _0, _k, x3); \
-  Fast_Two_Sum(_j, _k, _i, x4); \
-  Two_Product_Presplit(a3, b, bhi, blo, _j, _0); \
-  Two_Sum(_i, _0, _k, x5); \
-  Fast_Two_Sum(_j, _k, x7, x6)
-
-#define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \
-  Split(a0, a0hi, a0lo); \
-  Split(b0, bhi, blo); \
-  Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \
-  Split(a1, a1hi, a1lo); \
-  Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \
-  Two_Sum(_i, _0, _k, _1); \
-  Fast_Two_Sum(_j, _k, _l, _2); \
-  Split(b1, bhi, blo); \
-  Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \
-  Two_Sum(_1, _0, _k, x1); \
-  Two_Sum(_2, _k, _j, _1); \
-  Two_Sum(_l, _j, _m, _2); \
-  Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \
-  Two_Sum(_i, _0, _n, _0); \
-  Two_Sum(_1, _0, _i, x2); \
-  Two_Sum(_2, _i, _k, _1); \
-  Two_Sum(_m, _k, _l, _2); \
-  Two_Sum(_j, _n, _k, _0); \
-  Two_Sum(_1, _0, _j, x3); \
-  Two_Sum(_2, _j, _i, _1); \
-  Two_Sum(_l, _i, _m, _2); \
-  Two_Sum(_1, _k, _i, x4); \
-  Two_Sum(_2, _i, _k, x5); \
-  Two_Sum(_m, _k, x7, x6)
-
-/* An expansion of length two can be squared more quickly than finding the   */
-/*   product of two different expansions of length two, and the result is    */
-/*   guaranteed to have no more than six (rather than eight) components.     */
-
-#define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \
-  Square(a0, _j, x0); \
-  _0 = a0 + a0; \
-  Two_Product(a1, _0, _k, _1); \
-  Two_One_Sum(_k, _1, _j, _l, _2, x1); \
-  Square(a1, _j, _1); \
-  Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2)
-
-#ifndef USE_PREDICATES_INIT
-
-static REAL splitter;     /* = 2^ceiling(p / 2) + 1.  Used to split floats in half. */
-/* A set of coefficients used to calculate maximum roundoff errors.          */
-static REAL resulterrbound;
-static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC;
-static REAL o3derrboundA, o3derrboundB, o3derrboundC;
-static REAL iccerrboundA, iccerrboundB, iccerrboundC;
-static REAL isperrboundA, isperrboundB, isperrboundC;
-
-void 
-gts_predicates_init()
-{
-  double half = 0.5;
-  double check = 1.0, lastcheck;
-  int every_other = 1;
-  /* epsilon = 2^(-p).  Used to estimate roundoff errors. */
-  double epsilon = 1.0;   
-
-  FPU_ROUND_DOUBLE;
-
-  splitter = 1.;
-
-  /* Repeatedly divide `epsilon' by two until it is too small to add to   */
-  /* one without causing roundoff.  (Also check if the sum is equal to    */
-  /* the previous sum, for machines that round up instead of using exact  */
-  /* rounding.  Not that this library will work on such machines anyway). */
-  do {
-    lastcheck = check;
-    epsilon *= half;
-    if (every_other) {
-      splitter *= 2.0;
-    }
-    every_other = !every_other;
-    check = 1.0 + epsilon;
-  } while ((check != 1.0) && (check != lastcheck));
-  splitter += 1.0;
-  /* Error bounds for orientation and incircle tests. */
-  resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
-  ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon;
-  ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon;
-  ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon;
-  o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon;
-  o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon;
-  o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon;
-  iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon;
-  iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon;
-  iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon;
-  isperrboundA = (16.0 + 224.0 * epsilon) * epsilon;
-  isperrboundB = (5.0 + 72.0 * epsilon) * epsilon;
-  isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon;
-
-
-  FPU_RESTORE;
-}
-
-#endif /* USE_PREDICATES_INIT */
-
-/*****************************************************************************/
-/*                                                                           */
-/*  doubleprint()   Print the bit representation of a double.                */
-/*                                                                           */
-/*  Useful for debugging exact arithmetic routines.                          */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-void doubleprint(number)
-double number;
-{
-  unsigned long long no;
-  unsigned long long sign, expo;
-  int exponent;
-  int i, bottomi;
-
-  no = *(unsigned long long *) &number;
-  sign = no & 0x8000000000000000ll;
-  expo = (no >> 52) & 0x7ffll;
-  exponent = (int) expo;
-  exponent = exponent - 1023;
-  if (sign) {
-    printf("-");
-  } else {
-    printf(" ");
-  }
-  if (exponent == -1023) {
-    printf(
-      "0.0000000000000000000000000000000000000000000000000000_     (   )");
-  } else {
-    printf("1.");
-    bottomi = -1;
-    for (i = 0; i < 52; i++) {
-      if (no & 0x0008000000000000ll) {
-        printf("1");
-        bottomi = i;
-      } else {
-        printf("0");
-      }
-      no <<= 1;
-    }
-    printf("_%d  (%d)", exponent, exponent - 1 - bottomi);
-  }
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  floatprint()   Print the bit representation of a float.                  */
-/*                                                                           */
-/*  Useful for debugging exact arithmetic routines.                          */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-void floatprint(number)
-float number;
-{
-  unsigned no;
-  unsigned sign, expo;
-  int exponent;
-  int i, bottomi;
-
-  no = *(unsigned *) &number;
-  sign = no & 0x80000000;
-  expo = (no >> 23) & 0xff;
-  exponent = (int) expo;
-  exponent = exponent - 127;
-  if (sign) {
-    printf("-");
-  } else {
-    printf(" ");
-  }
-  if (exponent == -127) {
-    printf("0.00000000000000000000000_     (   )");
-  } else {
-    printf("1.");
-    bottomi = -1;
-    for (i = 0; i < 23; i++) {
-      if (no & 0x00400000) {
-        printf("1");
-        bottomi = i;
-      } else {
-        printf("0");
-      }
-      no <<= 1;
-    }
-    printf("_%3d  (%3d)", exponent, exponent - 1 - bottomi);
-  }
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  expansion_print()   Print the bit representation of an expansion.        */
-/*                                                                           */
-/*  Useful for debugging exact arithmetic routines.                          */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-void expansion_print(elen, e)
-int elen;
-REAL *e;
-{
-  int i;
-
-  for (i = elen - 1; i >= 0; i--) {
-    REALPRINT(e[i]);
-    if (i > 0) {
-      printf(" +\n");
-    } else {
-      printf("\n");
-    }
-  }
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  doublerand()   Generate a double with random 53-bit significand and a    */
-/*                 random exponent in [0, 511].                              */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-static double doublerand()
-{
-  double result;
-  double expo;
-  long a, b, c;
-  long i;
-
-  a = random();
-  b = random();
-  c = random();
-  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
-  for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) {
-    if (c & i) {
-      result *= expo;
-    }
-  }
-  return result;
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  narrowdoublerand()   Generate a double with random 53-bit significand    */
-/*                       and a random exponent in [0, 7].                    */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-static double narrowdoublerand()
-{
-  double result;
-  double expo;
-  long a, b, c;
-  long i;
-
-  a = random();
-  b = random();
-  c = random();
-  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
-  for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) {
-    if (c & i) {
-      result *= expo;
-    }
-  }
-  return result;
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  uniformdoublerand()   Generate a double with random 53-bit significand.  */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-static double uniformdoublerand()
-{
-  double result;
-  long a, b;
-
-  a = random();
-  b = random();
-  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
-  return result;
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  floatrand()   Generate a float with random 24-bit significand and a      */
-/*                random exponent in [0, 63].                                */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-static float floatrand()
-{
-  float result;
-  float expo;
-  long a, c;
-  long i;
-
-  a = random();
-  c = random();
-  result = (float) ((a - 1073741824) >> 6);
-  for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) {
-    if (c & i) {
-      result *= expo;
-    }
-  }
-  return result;
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  narrowfloatrand()   Generate a float with random 24-bit significand and  */
-/*                      a random exponent in [0, 7].                         */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-static float narrowfloatrand()
-{
-  float result;
-  float expo;
-  long a, c;
-  long i;
-
-  a = random();
-  c = random();
-  result = (float) ((a - 1073741824) >> 6);
-  for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) {
-    if (c & i) {
-      result *= expo;
-    }
-  }
-  return result;
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  uniformfloatrand()   Generate a float with random 24-bit significand.    */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-static float uniformfloatrand()
-{
-  float result;
-  long a;
-
-  a = random();
-  result = (float) ((a - 1073741824) >> 6);
-  return result;
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  fast_expansion_sum_zeroelim()   Sum two expansions, eliminating zero     */
-/*                                  components from the output expansion.    */
-/*                                                                           */
-/*  Sets h = e + f.  See the long version of my paper for details.           */
-/*                                                                           */
-/*  If round-to-even is used (as with IEEE 754), maintains the strongly      */
-/*  nonoverlapping property.  (That is, if e is strongly nonoverlapping, h   */
-/*  will be also.)  Does NOT maintain the nonoverlapping or nonadjacent      */
-/*  properties.                                                              */
-/*                                                                           */
-/*****************************************************************************/
-
-static int fast_expansion_sum_zeroelim(int elen, REAL *e, 
-				       int flen, REAL *f, REAL *h)
-     /* h cannot be e or f. */
-{
-  REAL Q;
-  INEXACT REAL Qnew;
-  INEXACT REAL hh;
-  INEXACT REAL bvirt;
-  REAL avirt, bround, around;
-  int eindex, findex, hindex;
-  REAL enow, fnow;
-
-  enow = e[0];
-  fnow = f[0];
-  eindex = findex = 0;
-  if ((fnow > enow) == (fnow > -enow)) {
-    Q = enow;
-    enow = e[++eindex];
-  } else {
-    Q = fnow;
-    fnow = f[++findex];
-  }
-  hindex = 0;
-  if ((eindex < elen) && (findex < flen)) {
-    if ((fnow > enow) == (fnow > -enow)) {
-      Fast_Two_Sum(enow, Q, Qnew, hh);
-      enow = e[++eindex];
-    } else {
-      Fast_Two_Sum(fnow, Q, Qnew, hh);
-      fnow = f[++findex];
-    }
-    Q = Qnew;
-    if (hh != 0.0) {
-      h[hindex++] = hh;
-    }
-    while ((eindex < elen) && (findex < flen)) {
-      if ((fnow > enow) == (fnow > -enow)) {
-        Two_Sum(Q, enow, Qnew, hh);
-        enow = e[++eindex];
-      } else {
-        Two_Sum(Q, fnow, Qnew, hh);
-        fnow = f[++findex];
-      }
-      Q = Qnew;
-      if (hh != 0.0) {
-        h[hindex++] = hh;
-      }
-    }
-  }
-  while (eindex < elen) {
-    Two_Sum(Q, enow, Qnew, hh);
-    enow = e[++eindex];
-    Q = Qnew;
-    if (hh != 0.0) {
-      h[hindex++] = hh;
-    }
-  }
-  while (findex < flen) {
-    Two_Sum(Q, fnow, Qnew, hh);
-    fnow = f[++findex];
-    Q = Qnew;
-    if (hh != 0.0) {
-      h[hindex++] = hh;
-    }
-  }
-  if ((Q != 0.0) || (hindex == 0)) {
-    h[hindex++] = Q;
-  }
-  return hindex;
-}
-
-/*****************************************************************************/
-/*                                                                           */
-/*  scale_expansion_zeroelim()   Multiply an expansion by a scalar,          */
-/*                               eliminating zero components from the        */
-/*                               output expansion.                           */
-/*                                                                           */
-/*  Sets h = be.  See either version of my paper for details.                */
-/*                                                                           */
-/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
-/*  with IEEE 754), maintains the strongly nonoverlapping and nonadjacent    */
-/*  properties as well.  (That is, if e has one of these properties, so      */
-/*  will h.)                                                                 */
-/*                                                                           */
-/*****************************************************************************/
-
-static int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h)
-     /* e and h cannot be the same. */
-{
-  INEXACT REAL Q, sum;
-  REAL hh;
-  INEXACT REAL product1;
-  REAL product0;
-  int eindex, hindex;
-  REAL enow;
-  INEXACT REAL bvirt;
-  REAL avirt, bround, around;
-  INEXACT REAL c;
-  INEXACT REAL abig;
-  REAL ahi, alo, bhi, blo;
-  REAL err1, err2, err3;
-
-  Split(b, bhi, blo);
-  Two_Product_Presplit(e[0], b, bhi, blo, Q, hh);
-  hindex = 0;
-  if (hh != 0) {
-    h[hindex++] = hh;
-  }
-  for (eindex = 1; eindex < elen; eindex++) {
-    enow = e[eindex];
-    Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
-    Two_Sum(Q, product0, sum, hh);
-    if (hh != 0) {
-      h[hindex++] = hh;
-    }
-    Fast_Two_Sum(product1, sum, Q, hh);
-    if (hh != 0) {
-      h[hindex++] = hh;
-    }
-  }
-  if ((Q != 0.0) || (hindex == 0)) {
-    h[hindex++] = Q;
-  }
-  return hindex;
-}
-
-/*****************************************************************************/
-/*                                                                           */
-/*  estimate()   Produce a one-word estimate of an expansion's value.        */
-/*                                                                           */
-/*  See either version of my paper for details.                              */
-/*                                                                           */
-/*****************************************************************************/
-
-static REAL estimate(int elen, REAL *e)
-{
-  REAL Q;
-  int eindex;
-
-  Q = e[0];
-  for (eindex = 1; eindex < elen; eindex++) {
-    Q += e[eindex];
-  }
-  return Q;
-}
-
-/*****************************************************************************/
-/*                                                                           */
-/*  orient2dfast()   Approximate 2D orientation test.  Nonrobust.            */
-/*  orient2dexact()   Exact 2D orientation test.  Robust.                    */
-/*  orient2dslow()   Another exact 2D orientation test.  Robust.             */
-/*  orient2d()   Adaptive exact 2D orientation test.  Robust.                */
-/*                                                                           */
-/*               Return a positive value if the points pa, pb, and pc occur  */
-/*               in counterclockwise order; a negative value if they occur   */
-/*               in clockwise order; and zero if they are collinear.  The    */
-/*               result is also a rough approximation of twice the signed    */
-/*               area of the triangle defined by the three points.           */
-/*                                                                           */
-/*  Only the first and last routine should be used; the middle two are for   */
-/*  timings.                                                                 */
-/*                                                                           */
-/*  The last three use exact arithmetic to ensure a correct answer.  The     */
-/*  result returned is the determinant of a matrix.  In orient2d() only,     */
-/*  this determinant is computed adaptively, in the sense that exact         */
-/*  arithmetic is used only to the degree it is needed to ensure that the    */
-/*  returned value has the correct sign.  Hence, orient2d() is usually quite */
-/*  fast, but will run more slowly when the input points are collinear or    */
-/*  nearly so.                                                               */
-/*                                                                           */
-/*****************************************************************************/
-
-static REAL orient2dadapt(REAL *pa, REAL *pb, REAL *pc, REAL detsum)
-{
-  INEXACT REAL acx, acy, bcx, bcy;
-  REAL acxtail, acytail, bcxtail, bcytail;
-  INEXACT REAL detleft, detright;
-  REAL detlefttail, detrighttail;
-  REAL det, errbound;
-  REAL B[4], C1[8], C2[12], D[16];
-  INEXACT REAL B3;
-  int C1length, C2length, Dlength;
-  REAL u[4];
-  INEXACT REAL u3;
-  INEXACT REAL s1, t1;
-  REAL s0, t0;
-
-  INEXACT REAL bvirt;
-  REAL avirt, bround, around;
-  INEXACT REAL c;
-  INEXACT REAL abig;
-  REAL ahi, alo, bhi, blo;
-  REAL err1, err2, err3;
-  INEXACT REAL _i, _j;
-  REAL _0;
-
-  acx = (REAL) (pa[0] - pc[0]);
-  bcx = (REAL) (pb[0] - pc[0]);
-  acy = (REAL) (pa[1] - pc[1]);
-  bcy = (REAL) (pb[1] - pc[1]);
-
-  Two_Product(acx, bcy, detleft, detlefttail);
-  Two_Product(acy, bcx, detright, detrighttail);
-
-  Two_Two_Diff(detleft, detlefttail, detright, detrighttail,
-               B3, B[2], B[1], B[0]);
-  B[3] = B3;
-
-  det = estimate(4, B);
-  errbound = ccwerrboundB * detsum;
-  if ((det >= errbound) || (-det >= errbound)) {
-    return det;
-  }
-
-  Two_Diff_Tail(pa[0], pc[0], acx, acxtail);
-  Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail);
-  Two_Diff_Tail(pa[1], pc[1], acy, acytail);
-  Two_Diff_Tail(pb[1], pc[1], bcy, bcytail);
-
-  if ((acxtail == 0.0) && (acytail == 0.0)
-      && (bcxtail == 0.0) && (bcytail == 0.0)) {
-    return det;
-  }
-
-  errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det);
-  det += (acx * bcytail + bcy * acxtail)
-       - (acy * bcxtail + bcx * acytail);
-  if ((det >= errbound) || (-det >= errbound)) {
-    return det;
-  }
-
-  Two_Product(acxtail, bcy, s1, s0);
-  Two_Product(acytail, bcx, t1, t0);
-  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
-  u[3] = u3;
-  C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1);
-
-  Two_Product(acx, bcytail, s1, s0);
-  Two_Product(acy, bcxtail, t1, t0);
-  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
-  u[3] = u3;
-  C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2);
-
-  Two_Product(acxtail, bcytail, s1, s0);
-  Two_Product(acytail, bcxtail, t1, t0);
-  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
-  u[3] = u3;
-  Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D);
-
-  return(D[Dlength - 1]);
-}
-
-REAL orient2d(pa, pb, pc)
-REAL *pa;
-REAL *pb;
-REAL *pc;
-{
-  REAL detleft, detright, det;
-  REAL detsum, errbound;
-  REAL orient;
-
-  FPU_ROUND_DOUBLE;
-
-  detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]);
-  detright = (pa[1] - pc[1]) * (pb[0] - pc[0]);
-  det = detleft - detright;
-
-  if (detleft > 0.0) {
-    if (detright <= 0.0) {
-      FPU_RESTORE;
-      return det;
-    } else {
-      detsum = detleft + detright;
-    }
-  } else if (detleft < 0.0) {
-    if (detright >= 0.0) {
-      FPU_RESTORE;
-      return det;
-    } else {
-      detsum = -detleft - detright;
-    }
-  } else {
-    FPU_RESTORE;
-    return det;
-  }
-
-  errbound = ccwerrboundA * detsum;
-  if ((det >= errbound) || (-det >= errbound)) {
-    FPU_RESTORE;
-    return det;
-  }
-
-  orient = orient2dadapt(pa, pb, pc, detsum);
-  FPU_RESTORE;
-  return orient;
-}
-
-/*****************************************************************************/
-/*                                                                           */
-/*  orient3dfast()   Approximate 3D orientation test.  Nonrobust.            */
-/*  orient3dexact()   Exact 3D orientation test.  Robust.                    */
-/*  orient3dslow()   Another exact 3D orientation test.  Robust.             */
-/*  orient3d()   Adaptive exact 3D orientation test.  Robust.                */
-/*                                                                           */
-/*               Return a positive value if the point pd lies below the      */
-/*               plane passing through pa, pb, and pc; "below" is defined so */
-/*               that pa, pb, and pc appear in counterclockwise order when   */
-/*               viewed from above the plane.  Returns a negative value if   */
-/*               pd lies above the plane.  Returns zero if the points are    */
-/*               coplanar.  The result is also a rough approximation of six  */
-/*               times the signed volume of the tetrahedron defined by the   */
-/*               four points.                                                */
-/*                                                                           */
-/*  Only the first and last routine should be used; the middle two are for   */
-/*  timings.                                                                 */
-/*                                                                           */
-/*  The last three use exact arithmetic to ensure a correct answer.  The     */
-/*  result returned is the determinant of a matrix.  In orient3d() only,     */
-/*  this determinant is computed adaptively, in the sense that exact         */
-/*  arithmetic is used only to the degree it is needed to ensure that the    */
-/*  returned value has the correct sign.  Hence, orient3d() is usually quite */
-/*  fast, but will run more slowly when the input points are coplanar or     */
-/*  nearly so.                                                               */
-/*                                                                           */
-/*****************************************************************************/
-
-static REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, 
-			  REAL permanent)
-{
-  INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
-  REAL det, errbound;
-
-  INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
-  REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
-  REAL bc[4], ca[4], ab[4];
-  INEXACT REAL bc3, ca3, ab3;
-  REAL adet[8], bdet[8], cdet[8];
-  int alen, blen, clen;
-  REAL abdet[16];
-  int ablen;
-  REAL *finnow, *finother, *finswap;
-  REAL fin1[192], fin2[192];
-  int finlength;
-
-  REAL adxtail, bdxtail, cdxtail;
-  REAL adytail, bdytail, cdytail;
-  REAL adztail, bdztail, cdztail;
-  INEXACT REAL at_blarge, at_clarge;
-  INEXACT REAL bt_clarge, bt_alarge;
-  INEXACT REAL ct_alarge, ct_blarge;
-  REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4];
-  int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen;
-  INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1;
-  INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1;
-  REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0;
-  REAL adxt_cdy0, adxt_bdy0, bdxt_ady0;
-  INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1;
-  INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1;
-  REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0;
-  REAL adyt_cdx0, adyt_bdx0, bdyt_adx0;
-  REAL bct[8], cat[8], abt[8];
-  int bctlen, catlen, abtlen;
-  INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1;
-  INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1;
-  REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0;
-  REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0;
-  REAL u[4], v[12], w[16];
-  INEXACT REAL u3;
-  int vlength, wlength;
-  REAL negate;
-
-  INEXACT REAL bvirt;
-  REAL avirt, bround, around;
-  INEXACT REAL c;
-  INEXACT REAL abig;
-  REAL ahi, alo, bhi, blo;
-  REAL err1, err2, err3;
-  INEXACT REAL _i, _j, _k;
-  REAL _0;
-
-  adx = (REAL) (pa[0] - pd[0]);
-  bdx = (REAL) (pb[0] - pd[0]);
-  cdx = (REAL) (pc[0] - pd[0]);
-  ady = (REAL) (pa[1] - pd[1]);
-  bdy = (REAL) (pb[1] - pd[1]);
-  cdy = (REAL) (pc[1] - pd[1]);
-  adz = (REAL) (pa[2] - pd[2]);
-  bdz = (REAL) (pb[2] - pd[2]);
-  cdz = (REAL) (pc[2] - pd[2]);
-
-  Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
-  Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
-  Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
-  bc[3] = bc3;
-  alen = scale_expansion_zeroelim(4, bc, adz, adet);
-
-  Two_Product(cdx, ady, cdxady1, cdxady0);
-  Two_Product(adx, cdy, adxcdy1, adxcdy0);
-  Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
-  ca[3] = ca3;
-  blen = scale_expansion_zeroelim(4, ca, bdz, bdet);
-
-  Two_Product(adx, bdy, adxbdy1, adxbdy0);
-  Two_Product(bdx, ady, bdxady1, bdxady0);
-  Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
-  ab[3] = ab3;
-  clen = scale_expansion_zeroelim(4, ab, cdz, cdet);
-
-  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
-  finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
-
-  det = estimate(finlength, fin1);
-  errbound = o3derrboundB * permanent;
-  if ((det >= errbound) || (-det >= errbound)) {
-    return det;
-  }
-
-  Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
-  Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
-  Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
-  Two_Diff_Tail(pa[1], pd[1], ady, adytail);
-  Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
-  Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
-  Two_Diff_Tail(pa[2], pd[2], adz, adztail);
-  Two_Diff_Tail(pb[2], pd[2], bdz, bdztail);
-  Two_Diff_Tail(pc[2], pd[2], cdz, cdztail);
-
-  if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0)
-      && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)
-      && (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) {
-    return det;
-  }
-
-  errbound = o3derrboundC * permanent + resulterrbound * Absolute(det);
-  det += (adz * ((bdx * cdytail + cdy * bdxtail)
-                 - (bdy * cdxtail + cdx * bdytail))
-          + adztail * (bdx * cdy - bdy * cdx))
-       + (bdz * ((cdx * adytail + ady * cdxtail)
-                 - (cdy * adxtail + adx * cdytail))
-          + bdztail * (cdx * ady - cdy * adx))
-       + (cdz * ((adx * bdytail + bdy * adxtail)
-                 - (ady * bdxtail + bdx * adytail))
-          + cdztail * (adx * bdy - ady * bdx));
-  if ((det >= errbound) || (-det >= errbound)) {
-    return det;
-  }
-
-  finnow = fin1;
-  finother = fin2;
-
-  if (adxtail == 0.0) {
-    if (adytail == 0.0) {
-      at_b[0] = 0.0;
-      at_blen = 1;
-      at_c[0] = 0.0;
-      at_clen = 1;
-    } else {
-      negate = -adytail;
-      Two_Product(negate, bdx, at_blarge, at_b[0]);
-      at_b[1] = at_blarge;
-      at_blen = 2;
-      Two_Product(adytail, cdx, at_clarge, at_c[0]);
-      at_c[1] = at_clarge;
-      at_clen = 2;
-    }
-  } else {
-    if (adytail == 0.0) {
-      Two_Product(adxtail, bdy, at_blarge, at_b[0]);
-      at_b[1] = at_blarge;
-      at_blen = 2;
-      negate = -adxtail;
-      Two_Product(negate, cdy, at_clarge, at_c[0]);
-      at_c[1] = at_clarge;
-      at_clen = 2;
-    } else {
-      Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0);
-      Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0);
-      Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0,
-                   at_blarge, at_b[2], at_b[1], at_b[0]);
-      at_b[3] = at_blarge;
-      at_blen = 4;
-      Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0);
-      Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0);
-      Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0,
-                   at_clarge, at_c[2], at_c[1], at_c[0]);
-      at_c[3] = at_clarge;
-      at_clen = 4;
-    }
-  }
-  if (bdxtail == 0.0) {
-    if (bdytail == 0.0) {
-      bt_c[0] = 0.0;
-      bt_clen = 1;
-      bt_a[0] = 0.0;
-      bt_alen = 1;
-    } else {
-      negate = -bdytail;
-      Two_Product(negate, cdx, bt_clarge, bt_c[0]);
-      bt_c[1] = bt_clarge;
-      bt_clen = 2;
-      Two_Product(bdytail, adx, bt_alarge, bt_a[0]);
-      bt_a[1] = bt_alarge;
-      bt_alen = 2;
-    }
-  } else {
-    if (bdytail == 0.0) {
-      Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]);
-      bt_c[1] = bt_clarge;
-      bt_clen = 2;
-      negate = -bdxtail;
-      Two_Product(negate, ady, bt_alarge, bt_a[0]);
-      bt_a[1] = bt_alarge;
-      bt_alen = 2;
-    } else {
-      Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0);
-      Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0);
-      Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0,
-                   bt_clarge, bt_c[2], bt_c[1], bt_c[0]);
-      bt_c[3] = bt_clarge;
-      bt_clen = 4;
-      Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0);
-      Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0);
-      Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0,
-                  bt_alarge, bt_a[2], bt_a[1], bt_a[0]);
-      bt_a[3] = bt_alarge;
-      bt_alen = 4;
-    }
-  }
-  if (cdxtail == 0.0) {
-    if (cdytail == 0.0) {
-      ct_a[0] = 0.0;
-      ct_alen = 1;
-      ct_b[0] = 0.0;
-      ct_blen = 1;
-    } else {
-      negate = -cdytail;
-      Two_Product(negate, adx, ct_alarge, ct_a[0]);
-      ct_a[1] = ct_alarge;
-      ct_alen = 2;
-      Two_Product(cdytail, bdx, ct_blarge, ct_b[0]);
-      ct_b[1] = ct_blarge;
-      ct_blen = 2;
-    }
-  } else {
-    if (cdytail == 0.0) {
-      Two_Product(cdxtail, ady, ct_alarge, ct_a[0]);
-      ct_a[1] = ct_alarge;
-      ct_alen = 2;
-      negate = -cdxtail;
-      Two_Product(negate, bdy, ct_blarge, ct_b[0]);
-      ct_b[1] = ct_blarge;
-      ct_blen = 2;
-    } else {
-      Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0);
-      Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0);
-      Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0,
-                   ct_alarge, ct_a[2], ct_a[1], ct_a[0]);
-      ct_a[3] = ct_alarge;
-      ct_alen = 4;
-      Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0);
-      Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0);
-      Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0,
-                   ct_blarge, ct_b[2], ct_b[1], ct_b[0]);
-      ct_b[3] = ct_blarge;
-      ct_blen = 4;
-    }
-  }
-
-  bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct);
-  wlength = scale_expansion_zeroelim(bctlen, bct, adz, w);
-  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
-                                          finother);
-  finswap = finnow; finnow = finother; finother = finswap;
-
-  catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat);
-  wlength = scale_expansion_zeroelim(catlen, cat, bdz, w);
-  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
-                                          finother);
-  finswap = finnow; finnow = finother; finother = finswap;
-
-  abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt);
-  wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w);
-  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
-                                          finother);
-  finswap = finnow; finnow = finother; finother = finswap;
-
-  if (adztail != 0.0) {
-    vlength = scale_expansion_zeroelim(4, bc, adztail, v);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
-                                            finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (bdztail != 0.0) {
-    vlength = scale_expansion_zeroelim(4, ca, bdztail, v);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
-                                            finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (cdztail != 0.0) {
-    vlength = scale_expansion_zeroelim(4, ab, cdztail, v);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
-                                            finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-
-  if (adxtail != 0.0) {
-    if (bdytail != 0.0) {
-      Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0);
-      Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                              finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (cdztail != 0.0) {
-        Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]);
-        u[3] = u3;
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                                finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-    }
-    if (cdytail != 0.0) {
-      negate = -adxtail;
-      Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0);
-      Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                              finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (bdztail != 0.0) {
-        Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]);
-        u[3] = u3;
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                                finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-    }
-  }
-  if (bdxtail != 0.0) {
-    if (cdytail != 0.0) {
-      Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0);
-      Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                              finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (adztail != 0.0) {
-        Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]);
-        u[3] = u3;
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                                finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-    }
-    if (adytail != 0.0) {
-      negate = -bdxtail;
-      Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0);
-      Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                              finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (cdztail != 0.0) {
-        Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]);
-        u[3] = u3;
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                                finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-    }
-  }
-  if (cdxtail != 0.0) {
-    if (adytail != 0.0) {
-      Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0);
-      Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                              finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (bdztail != 0.0) {
-        Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]);
-        u[3] = u3;
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                                finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-    }
-    if (bdytail != 0.0) {
-      negate = -cdxtail;
-      Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0);
-      Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                              finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (adztail != 0.0) {
-        Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]);
-        u[3] = u3;
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
-                                                finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-    }
-  }
-
-  if (adztail != 0.0) {
-    wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
-                                            finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (bdztail != 0.0) {
-    wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
-                                            finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (cdztail != 0.0) {
-    wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
-                                            finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-
-  return finnow[finlength - 1];
-}
-
-REAL orient3d(pa, pb, pc, pd)
-REAL *pa;
-REAL *pb;
-REAL *pc;
-REAL *pd;
-{
-  REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
-  REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
-  REAL det;
-  REAL permanent, errbound;
-  REAL orient;
-
-  FPU_ROUND_DOUBLE;
-
-  adx = pa[0] - pd[0];
-  bdx = pb[0] - pd[0];
-  cdx = pc[0] - pd[0];
-  ady = pa[1] - pd[1];
-  bdy = pb[1] - pd[1];
-  cdy = pc[1] - pd[1];
-  adz = pa[2] - pd[2];
-  bdz = pb[2] - pd[2];
-  cdz = pc[2] - pd[2];
-
-  bdxcdy = bdx * cdy;
-  cdxbdy = cdx * bdy;
-
-  cdxady = cdx * ady;
-  adxcdy = adx * cdy;
-
-  adxbdy = adx * bdy;
-  bdxady = bdx * ady;
-
-  det = adz * (bdxcdy - cdxbdy) 
-      + bdz * (cdxady - adxcdy)
-      + cdz * (adxbdy - bdxady);
-
-  permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz)
-            + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz)
-            + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz);
-  errbound = o3derrboundA * permanent;
-  if ((det > errbound) || (-det > errbound)) {
-    FPU_RESTORE;
-    return det;
-  }
-
-  orient = orient3dadapt(pa, pb, pc, pd, permanent);
-  FPU_RESTORE;
-  return orient;
-}
-
-/*****************************************************************************/
-/*                                                                           */
-/*  incirclefast()   Approximate 2D incircle test.  Nonrobust.               */
-/*  incircleexact()   Exact 2D incircle test.  Robust.                       */
-/*  incircleslow()   Another exact 2D incircle test.  Robust.                */
-/*  incircle()   Adaptive exact 2D incircle test.  Robust.                   */
-/*                                                                           */
-/*               Return a positive value if the point pd lies inside the     */
-/*               circle passing through pa, pb, and pc; a negative value if  */
-/*               it lies outside; and zero if the four points are cocircular.*/
-/*               The points pa, pb, and pc must be in counterclockwise       */
-/*               order, or the sign of the result will be reversed.          */
-/*                                                                           */
-/*  Only the first and last routine should be used; the middle two are for   */
-/*  timings.                                                                 */
-/*                                                                           */
-/*  The last three use exact arithmetic to ensure a correct answer.  The     */
-/*  result returned is the determinant of a matrix.  In incircle() only,     */
-/*  this determinant is computed adaptively, in the sense that exact         */
-/*  arithmetic is used only to the degree it is needed to ensure that the    */
-/*  returned value has the correct sign.  Hence, incircle() is usually quite */
-/*  fast, but will run more slowly when the input points are cocircular or   */
-/*  nearly so.                                                               */
-/*                                                                           */
-/*****************************************************************************/
-
-static REAL incircleadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, 
-			  REAL permanent)
-{
-  INEXACT REAL adx, bdx, cdx, ady, bdy, cdy;
-  REAL det, errbound;
-
-  INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
-  REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
-  REAL bc[4], ca[4], ab[4];
-  INEXACT REAL bc3, ca3, ab3;
-  REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32];
-  int axbclen, axxbclen, aybclen, ayybclen, alen;
-  REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32];
-  int bxcalen, bxxcalen, bycalen, byycalen, blen;
-  REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32];
-  int cxablen, cxxablen, cyablen, cyyablen, clen;
-  REAL abdet[64];
-  int ablen;
-  REAL fin1[1152], fin2[1152];
-  REAL *finnow, *finother, *finswap;
-  int finlength;
-
-  REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail;
-  INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1;
-  REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0;
-  REAL aa[4], bb[4], cc[4];
-  INEXACT REAL aa3, bb3, cc3;
-  INEXACT REAL ti1, tj1;
-  REAL ti0, tj0;
-  REAL u[4], v[4];
-  INEXACT REAL u3, v3;
-  REAL temp8[8], temp16a[16], temp16b[16], temp16c[16];
-  REAL temp32a[32], temp32b[32], temp48[48], temp64[64];
-  int temp8len, temp16alen, temp16blen, temp16clen;
-  int temp32alen, temp32blen, temp48len, temp64len;
-  REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8];
-  int axtbblen, axtcclen, aytbblen, aytcclen;
-  REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8];
-  int bxtaalen, bxtcclen, bytaalen, bytcclen;
-  REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8];
-  int cxtaalen, cxtbblen, cytaalen, cytbblen;
-  REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8];
-  int axtbclen = 0, aytbclen = 0;
-  int bxtcalen = 0, bytcalen = 0;
-  int cxtablen = 0, cytablen = 0;
-  REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16];
-  int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen;
-  REAL axtbctt[8], aytbctt[8], bxtcatt[8];
-  REAL bytcatt[8], cxtabtt[8], cytabtt[8];
-  int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen;
-  REAL abt[8], bct[8], cat[8];
-  int abtlen, bctlen, catlen;
-  REAL abtt[4], bctt[4], catt[4];
-  int abttlen, bcttlen, cattlen;
-  INEXACT REAL abtt3, bctt3, catt3;
-  REAL negate;
-
-  INEXACT REAL bvirt;
-  REAL avirt, bround, around;
-  INEXACT REAL c;
-  INEXACT REAL abig;
-  REAL ahi, alo, bhi, blo;
-  REAL err1, err2, err3;
-  INEXACT REAL _i, _j;
-  REAL _0;
-
-  adx = (REAL) (pa[0] - pd[0]);
-  bdx = (REAL) (pb[0] - pd[0]);
-  cdx = (REAL) (pc[0] - pd[0]);
-  ady = (REAL) (pa[1] - pd[1]);
-  bdy = (REAL) (pb[1] - pd[1]);
-  cdy = (REAL) (pc[1] - pd[1]);
-
-  Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
-  Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
-  Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
-  bc[3] = bc3;
-  axbclen = scale_expansion_zeroelim(4, bc, adx, axbc);
-  axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc);
-  aybclen = scale_expansion_zeroelim(4, bc, ady, aybc);
-  ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc);
-  alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet);
-
-  Two_Product(cdx, ady, cdxady1, cdxady0);
-  Two_Product(adx, cdy, adxcdy1, adxcdy0);
-  Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
-  ca[3] = ca3;
-  bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca);
-  bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca);
-  bycalen = scale_expansion_zeroelim(4, ca, bdy, byca);
-  byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca);
-  blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet);
-
-  Two_Product(adx, bdy, adxbdy1, adxbdy0);
-  Two_Product(bdx, ady, bdxady1, bdxady0);
-  Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
-  ab[3] = ab3;
-  cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab);
-  cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab);
-  cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab);
-  cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab);
-  clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet);
-
-  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
-  finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
-
-  det = estimate(finlength, fin1);
-  errbound = iccerrboundB * permanent;
-  if ((det >= errbound) || (-det >= errbound)) {
-    return det;
-  }
-
-  Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
-  Two_Diff_Tail(pa[1], pd[1], ady, adytail);
-  Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
-  Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
-  Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
-  Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
-  if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0)
-      && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) {
-    return det;
-  }
-
-  errbound = iccerrboundC * permanent + resulterrbound * Absolute(det);
-  det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail)
-                                     - (bdy * cdxtail + cdx * bdytail))
-          + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx))
-       + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail)
-                                     - (cdy * adxtail + adx * cdytail))
-          + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx))
-       + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail)
-                                     - (ady * bdxtail + bdx * adytail))
-          + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx));
-  if ((det >= errbound) || (-det >= errbound)) {
-    return det;
-  }
-
-  finnow = fin1;
-  finother = fin2;
-
-  if ((bdxtail != 0.0) || (bdytail != 0.0)
-      || (cdxtail != 0.0) || (cdytail != 0.0)) {
-    Square(adx, adxadx1, adxadx0);
-    Square(ady, adyady1, adyady0);
-    Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]);
-    aa[3] = aa3;
-  }
-  if ((cdxtail != 0.0) || (cdytail != 0.0)
-      || (adxtail != 0.0) || (adytail != 0.0)) {
-    Square(bdx, bdxbdx1, bdxbdx0);
-    Square(bdy, bdybdy1, bdybdy0);
-    Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]);
-    bb[3] = bb3;
-  }
-  if ((adxtail != 0.0) || (adytail != 0.0)
-      || (bdxtail != 0.0) || (bdytail != 0.0)) {
-    Square(cdx, cdxcdx1, cdxcdx0);
-    Square(cdy, cdycdy1, cdycdy0);
-    Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]);
-    cc[3] = cc3;
-  }
-
-  if (adxtail != 0.0) {
-    axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc);
-    temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx,
-                                          temp16a);
-
-    axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc);
-    temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b);
-
-    axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb);
-    temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c);
-
-    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                            temp16blen, temp16b, temp32a);
-    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
-                                            temp32alen, temp32a, temp48);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                            temp48, finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (adytail != 0.0) {
-    aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc);
-    temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady,
-                                          temp16a);
-
-    aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb);
-    temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b);
-
-    aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc);
-    temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c);
-
-    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                            temp16blen, temp16b, temp32a);
-    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
-                                            temp32alen, temp32a, temp48);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                            temp48, finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (bdxtail != 0.0) {
-    bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca);
-    temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx,
-                                          temp16a);
-
-    bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa);
-    temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b);
-
-    bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc);
-    temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c);
-
-    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                            temp16blen, temp16b, temp32a);
-    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
-                                            temp32alen, temp32a, temp48);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                            temp48, finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (bdytail != 0.0) {
-    bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca);
-    temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy,
-                                          temp16a);
-
-    bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc);
-    temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b);
-
-    bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa);
-    temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c);
-
-    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                            temp16blen, temp16b, temp32a);
-    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
-                                            temp32alen, temp32a, temp48);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                            temp48, finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (cdxtail != 0.0) {
-    cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab);
-    temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx,
-                                          temp16a);
-
-    cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb);
-    temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b);
-
-    cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa);
-    temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c);
-
-    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                            temp16blen, temp16b, temp32a);
-    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
-                                            temp32alen, temp32a, temp48);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                            temp48, finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-  if (cdytail != 0.0) {
-    cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab);
-    temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy,
-                                          temp16a);
-
-    cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa);
-    temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b);
-
-    cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb);
-    temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c);
-
-    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                            temp16blen, temp16b, temp32a);
-    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
-                                            temp32alen, temp32a, temp48);
-    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                            temp48, finother);
-    finswap = finnow; finnow = finother; finother = finswap;
-  }
-
-  if ((adxtail != 0.0) || (adytail != 0.0)) {
-    if ((bdxtail != 0.0) || (bdytail != 0.0)
-        || (cdxtail != 0.0) || (cdytail != 0.0)) {
-      Two_Product(bdxtail, cdy, ti1, ti0);
-      Two_Product(bdx, cdytail, tj1, tj0);
-      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      negate = -bdy;
-      Two_Product(cdxtail, negate, ti1, ti0);
-      negate = -bdytail;
-      Two_Product(cdx, negate, tj1, tj0);
-      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
-      v[3] = v3;
-      bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct);
-
-      Two_Product(bdxtail, cdytail, ti1, ti0);
-      Two_Product(cdxtail, bdytail, tj1, tj0);
-      Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]);
-      bctt[3] = bctt3;
-      bcttlen = 4;
-    } else {
-      bct[0] = 0.0;
-      bctlen = 1;
-      bctt[0] = 0.0;
-      bcttlen = 1;
-    }
-
-    if (adxtail != 0.0) {
-      temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a);
-      axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct);
-      temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx,
-                                            temp32a);
-      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp32alen, temp32a, temp48);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                              temp48, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (bdytail != 0.0) {
-        temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8);
-        temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail,
-                                              temp16a);
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
-                                                temp16a, finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-      if (cdytail != 0.0) {
-        temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8);
-        temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail,
-                                              temp16a);
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
-                                                temp16a, finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-
-      temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail,
-                                            temp32a);
-      axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt);
-      temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx,
-                                            temp16a);
-      temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail,
-                                            temp16b);
-      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp16blen, temp16b, temp32b);
-      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
-                                              temp32blen, temp32b, temp64);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
-                                              temp64, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-    }
-    if (adytail != 0.0) {
-      temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a);
-      aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct);
-      temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady,
-                                            temp32a);
-      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp32alen, temp32a, temp48);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                              temp48, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-
-
-      temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail,
-                                            temp32a);
-      aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt);
-      temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady,
-                                            temp16a);
-      temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail,
-                                            temp16b);
-      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp16blen, temp16b, temp32b);
-      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
-                                              temp32blen, temp32b, temp64);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
-                                              temp64, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-    }
-  }
-  if ((bdxtail != 0.0) || (bdytail != 0.0)) {
-    if ((cdxtail != 0.0) || (cdytail != 0.0)
-        || (adxtail != 0.0) || (adytail != 0.0)) {
-      Two_Product(cdxtail, ady, ti1, ti0);
-      Two_Product(cdx, adytail, tj1, tj0);
-      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      negate = -cdy;
-      Two_Product(adxtail, negate, ti1, ti0);
-      negate = -cdytail;
-      Two_Product(adx, negate, tj1, tj0);
-      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
-      v[3] = v3;
-      catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat);
-
-      Two_Product(cdxtail, adytail, ti1, ti0);
-      Two_Product(adxtail, cdytail, tj1, tj0);
-      Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]);
-      catt[3] = catt3;
-      cattlen = 4;
-    } else {
-      cat[0] = 0.0;
-      catlen = 1;
-      catt[0] = 0.0;
-      cattlen = 1;
-    }
-
-    if (bdxtail != 0.0) {
-      temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a);
-      bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat);
-      temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx,
-                                            temp32a);
-      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp32alen, temp32a, temp48);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                              temp48, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (cdytail != 0.0) {
-        temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8);
-        temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail,
-                                              temp16a);
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
-                                                temp16a, finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-      if (adytail != 0.0) {
-        temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8);
-        temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail,
-                                              temp16a);
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
-                                                temp16a, finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-
-      temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail,
-                                            temp32a);
-      bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt);
-      temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx,
-                                            temp16a);
-      temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail,
-                                            temp16b);
-      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp16blen, temp16b, temp32b);
-      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
-                                              temp32blen, temp32b, temp64);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
-                                              temp64, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-    }
-    if (bdytail != 0.0) {
-      temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a);
-      bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat);
-      temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy,
-                                            temp32a);
-      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp32alen, temp32a, temp48);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                              temp48, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-
-
-      temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail,
-                                            temp32a);
-      bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt);
-      temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy,
-                                            temp16a);
-      temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail,
-                                            temp16b);
-      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp16blen, temp16b, temp32b);
-      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
-                                              temp32blen, temp32b, temp64);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
-                                              temp64, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-    }
-  }
-  if ((cdxtail != 0.0) || (cdytail != 0.0)) {
-    if ((adxtail != 0.0) || (adytail != 0.0)
-        || (bdxtail != 0.0) || (bdytail != 0.0)) {
-      Two_Product(adxtail, bdy, ti1, ti0);
-      Two_Product(adx, bdytail, tj1, tj0);
-      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
-      u[3] = u3;
-      negate = -ady;
-      Two_Product(bdxtail, negate, ti1, ti0);
-      negate = -adytail;
-      Two_Product(bdx, negate, tj1, tj0);
-      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
-      v[3] = v3;
-      abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt);
-
-      Two_Product(adxtail, bdytail, ti1, ti0);
-      Two_Product(bdxtail, adytail, tj1, tj0);
-      Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]);
-      abtt[3] = abtt3;
-      abttlen = 4;
-    } else {
-      abt[0] = 0.0;
-      abtlen = 1;
-      abtt[0] = 0.0;
-      abttlen = 1;
-    }
-
-    if (cdxtail != 0.0) {
-      temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a);
-      cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt);
-      temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx,
-                                            temp32a);
-      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp32alen, temp32a, temp48);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                              temp48, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-      if (adytail != 0.0) {
-        temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8);
-        temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail,
-                                              temp16a);
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
-                                                temp16a, finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-      if (bdytail != 0.0) {
-        temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8);
-        temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail,
-                                              temp16a);
-        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
-                                                temp16a, finother);
-        finswap = finnow; finnow = finother; finother = finswap;
-      }
-
-      temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail,
-                                            temp32a);
-      cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt);
-      temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx,
-                                            temp16a);
-      temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail,
-                                            temp16b);
-      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp16blen, temp16b, temp32b);
-      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
-                                              temp32blen, temp32b, temp64);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
-                                              temp64, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-    }
-    if (cdytail != 0.0) {
-      temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a);
-      cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt);
-      temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy,
-                                            temp32a);
-      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp32alen, temp32a, temp48);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
-                                              temp48, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-
-
-      temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail,
-                                            temp32a);
-      cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt);
-      temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy,
-                                            temp16a);
-      temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail,
-                                            temp16b);
-      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
-                                              temp16blen, temp16b, temp32b);
-      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
-                                              temp32blen, temp32b, temp64);
-      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
-                                              temp64, finother);
-      finswap = finnow; finnow = finother; finother = finswap;
-    }
-  }
-
-  return finnow[finlength - 1];
-}
-
-REAL incircle(pa, pb, pc, pd)
-REAL *pa;
-REAL *pb;
-REAL *pc;
-REAL *pd;
-{
-  REAL adx, bdx, cdx, ady, bdy, cdy;
-  REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
-  REAL alift, blift, clift;
-  REAL det;
-  REAL permanent, errbound;
-  REAL inc;
-
-  FPU_ROUND_DOUBLE;
-  
-  adx = pa[0] - pd[0];
-  bdx = pb[0] - pd[0];
-  cdx = pc[0] - pd[0];
-  ady = pa[1] - pd[1];
-  bdy = pb[1] - pd[1];
-  cdy = pc[1] - pd[1];
-
-  bdxcdy = bdx * cdy;
-  cdxbdy = cdx * bdy;
-  alift = adx * adx + ady * ady;
-
-  cdxady = cdx * ady;
-  adxcdy = adx * cdy;
-  blift = bdx * bdx + bdy * bdy;
-
-  adxbdy = adx * bdy;
-  bdxady = bdx * ady;
-  clift = cdx * cdx + cdy * cdy;
-
-  det = alift * (bdxcdy - cdxbdy)
-      + blift * (cdxady - adxcdy)
-      + clift * (adxbdy - bdxady);
-
-  permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift
-            + (Absolute(cdxady) + Absolute(adxcdy)) * blift
-            + (Absolute(adxbdy) + Absolute(bdxady)) * clift;
-  errbound = iccerrboundA * permanent;
-  if ((det > errbound) || (-det > errbound)) {
-    FPU_RESTORE;
-    return det;
-  }
-
-  inc = incircleadapt(pa, pb, pc, pd, permanent);
-  FPU_RESTORE;
-  return inc;
-}
-
-/*****************************************************************************/
-/*                                                                           */
-/*  inspherefast()   Approximate 3D insphere test.  Nonrobust.               */
-/*  insphereexact()   Exact 3D insphere test.  Robust.                       */
-/*  insphereslow()   Another exact 3D insphere test.  Robust.                */
-/*  insphere()   Adaptive exact 3D insphere test.  Robust.                   */
-/*                                                                           */
-/*               Return a positive value if the point pe lies inside the     */
-/*               sphere passing through pa, pb, pc, and pd; a negative value */
-/*               if it lies outside; and zero if the five points are         */
-/*               cospherical.  The points pa, pb, pc, and pd must be ordered */
-/*               so that they have a positive orientation (as defined by     */
-/*               orient3d()), or the sign of the result will be reversed.    */
-/*                                                                           */
-/*  Only the first and last routine should be used; the middle two are for   */
-/*  timings.                                                                 */
-/*                                                                           */
-/*  The last three use exact arithmetic to ensure a correct answer.  The     */
-/*  result returned is the determinant of a matrix.  In insphere() only,     */
-/*  this determinant is computed adaptively, in the sense that exact         */
-/*  arithmetic is used only to the degree it is needed to ensure that the    */
-/*  returned value has the correct sign.  Hence, insphere() is usually quite */
-/*  fast, but will run more slowly when the input points are cospherical or  */
-/*  nearly so.                                                               */
-/*                                                                           */
-/*****************************************************************************/
-
-static REAL insphereexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
-{
-  INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1;
-  INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1;
-  INEXACT REAL axcy1, bxdy1, cxey1, dxay1, exby1;
-  INEXACT REAL cxay1, dxby1, excy1, axdy1, bxey1;
-  REAL axby0, bxcy0, cxdy0, dxey0, exay0;
-  REAL bxay0, cxby0, dxcy0, exdy0, axey0;
-  REAL axcy0, bxdy0, cxey0, dxay0, exby0;
-  REAL cxay0, dxby0, excy0, axdy0, bxey0;
-  REAL ab[4], bc[4], cd[4], de[4], ea[4];
-  REAL ac[4], bd[4], ce[4], da[4], eb[4];
-  REAL temp8a[8], temp8b[8], temp16[16];
-  int temp8alen, temp8blen, temp16len;
-  REAL abc[24], bcd[24], cde[24], dea[24], eab[24];
-  REAL abd[24], bce[24], cda[24], deb[24], eac[24];
-  int abclen, bcdlen, cdelen, dealen, eablen;
-  int abdlen, bcelen, cdalen, deblen, eaclen;
-  REAL temp48a[48], temp48b[48];
-  int temp48alen, temp48blen;
-  REAL abcd[96], bcde[96], cdea[96], deab[96], eabc[96];
-  int abcdlen, bcdelen, cdealen, deablen, eabclen;
-  REAL temp192[192];
-  REAL det384x[384], det384y[384], det384z[384];
-  int xlen, ylen, zlen;
-  REAL detxy[768];
-  int xylen;
-  REAL adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152];
-  int alen, blen, clen, dlen, elen;
-  REAL abdet[2304], cddet[2304], cdedet[3456];
-  int ablen, cdlen;
-  REAL deter[5760];
-  int deterlen;
-  int i;
-
-  INEXACT REAL bvirt;
-  REAL avirt, bround, around;
-  INEXACT REAL c;
-  INEXACT REAL abig;
-  REAL ahi, alo, bhi, blo;
-  REAL err1, err2, err3;
-  INEXACT REAL _i, _j;
-  REAL _0;
-
-  Two_Product(pa[0], pb[1], axby1, axby0);
-  Two_Product(pb[0], pa[1], bxay1, bxay0);
-  Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]);
-
-  Two_Product(pb[0], pc[1], bxcy1, bxcy0);
-  Two_Product(pc[0], pb[1], cxby1, cxby0);
-  Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]);
-
-  Two_Product(pc[0], pd[1], cxdy1, cxdy0);
-  Two_Product(pd[0], pc[1], dxcy1, dxcy0);
-  Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]);
-
-  Two_Product(pd[0], pe[1], dxey1, dxey0);
-  Two_Product(pe[0], pd[1], exdy1, exdy0);
-  Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]);
-
-  Two_Product(pe[0], pa[1], exay1, exay0);
-  Two_Product(pa[0], pe[1], axey1, axey0);
-  Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]);
-
-  Two_Product(pa[0], pc[1], axcy1, axcy0);
-  Two_Product(pc[0], pa[1], cxay1, cxay0);
-  Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]);
-
-  Two_Product(pb[0], pd[1], bxdy1, bxdy0);
-  Two_Product(pd[0], pb[1], dxby1, dxby0);
-  Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]);
-
-  Two_Product(pc[0], pe[1], cxey1, cxey0);
-  Two_Product(pe[0], pc[1], excy1, excy0);
-  Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]);
-
-  Two_Product(pd[0], pa[1], dxay1, dxay0);
-  Two_Product(pa[0], pd[1], axdy1, axdy0);
-  Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]);
-
-  Two_Product(pe[0], pb[1], exby1, exby0);
-  Two_Product(pb[0], pe[1], bxey1, bxey0);
-  Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]);
-
-  temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a);
-  abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       abc);
-
-  temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a);
-  bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       bcd);
-
-  temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a);
-  cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       cde);
-
-  temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a);
-  dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       dea);
-
-  temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a);
-  eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       eab);
-
-  temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a);
-  abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       abd);
-
-  temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a);
-  bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       bce);
-
-  temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a);
-  cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       cda);
-
-  temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a);
-  deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       deb);
-
-  temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a);
-  temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
-                                          temp16);
-  temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a);
-  eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
-                                       eac);
-
-  temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a);
-  temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b);
-  for (i = 0; i < temp48blen; i++) {
-    temp48b[i] = -temp48b[i];
-  }
-  bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
-                                        temp48blen, temp48b, bcde);
-  xlen = scale_expansion_zeroelim(bcdelen, bcde, pa[0], temp192);
-  xlen = scale_expansion_zeroelim(xlen, temp192, pa[0], det384x);
-  ylen = scale_expansion_zeroelim(bcdelen, bcde, pa[1], temp192);
-  ylen = scale_expansion_zeroelim(ylen, temp192, pa[1], det384y);
-  zlen = scale_expansion_zeroelim(bcdelen, bcde, pa[2], temp192);
-  zlen = scale_expansion_zeroelim(zlen, temp192, pa[2], det384z);
-  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
-  alen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, adet);
-
-  temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a);
-  temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b);
-  for (i = 0; i < temp48blen; i++) {
-    temp48b[i] = -temp48b[i];
-  }
-  cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
-                                        temp48blen, temp48b, cdea);
-  xlen = scale_expansion_zeroelim(cdealen, cdea, pb[0], temp192);
-  xlen = scale_expansion_zeroelim(xlen, temp192, pb[0], det384x);
-  ylen = scale_expansion_zeroelim(cdealen, cdea, pb[1], temp192);
-  ylen = scale_expansion_zeroelim(ylen, temp192, pb[1], det384y);
-  zlen = scale_expansion_zeroelim(cdealen, cdea, pb[2], temp192);
-  zlen = scale_expansion_zeroelim(zlen, temp192, pb[2], det384z);
-  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
-  blen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, bdet);
-
-  temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a);
-  temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b);
-  for (i = 0; i < temp48blen; i++) {
-    temp48b[i] = -temp48b[i];
-  }
-  deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
-                                        temp48blen, temp48b, deab);
-  xlen = scale_expansion_zeroelim(deablen, deab, pc[0], temp192);
-  xlen = scale_expansion_zeroelim(xlen, temp192, pc[0], det384x);
-  ylen = scale_expansion_zeroelim(deablen, deab, pc[1], temp192);
-  ylen = scale_expansion_zeroelim(ylen, temp192, pc[1], det384y);
-  zlen = scale_expansion_zeroelim(deablen, deab, pc[2], temp192);
-  zlen = scale_expansion_zeroelim(zlen, temp192, pc[2], det384z);
-  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
-  clen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, cdet);
-
-  temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a);
-  temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b);
-  for (i = 0; i < temp48blen; i++) {
-    temp48b[i] = -temp48b[i];
-  }
-  eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
-                                        temp48blen, temp48b, eabc);
-  xlen = scale_expansion_zeroelim(eabclen, eabc, pd[0], temp192);
-  xlen = scale_expansion_zeroelim(xlen, temp192, pd[0], det384x);
-  ylen = scale_expansion_zeroelim(eabclen, eabc, pd[1], temp192);
-  ylen = scale_expansion_zeroelim(ylen, temp192, pd[1], det384y);
-  zlen = scale_expansion_zeroelim(eabclen, eabc, pd[2], temp192);
-  zlen = scale_expansion_zeroelim(zlen, temp192, pd[2], det384z);
-  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
-  dlen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, ddet);
-
-  temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a);
-  temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b);
-  for (i = 0; i < temp48blen; i++) {
-    temp48b[i] = -temp48b[i];
-  }
-  abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
-                                        temp48blen, temp48b, abcd);
-  xlen = scale_expansion_zeroelim(abcdlen, abcd, pe[0], temp192);
-  xlen = scale_expansion_zeroelim(xlen, temp192, pe[0], det384x);
-  ylen = scale_expansion_zeroelim(abcdlen, abcd, pe[1], temp192);
-  ylen = scale_expansion_zeroelim(ylen, temp192, pe[1], det384y);
-  zlen = scale_expansion_zeroelim(abcdlen, abcd, pe[2], temp192);
-  zlen = scale_expansion_zeroelim(zlen, temp192, pe[2], det384z);
-  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
-  elen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, edet);
-
-  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
-  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
-  cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet);
-  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter);
-
-  return deter[deterlen - 1];
-}
-
-static REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, 
-			  REAL permanent)
-{
-  INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez;
-  REAL det, errbound;
-
-  INEXACT REAL aexbey1, bexaey1, bexcey1, cexbey1;
-  INEXACT REAL cexdey1, dexcey1, dexaey1, aexdey1;
-  INEXACT REAL aexcey1, cexaey1, bexdey1, dexbey1;
-  REAL aexbey0, bexaey0, bexcey0, cexbey0;
-  REAL cexdey0, dexcey0, dexaey0, aexdey0;
-  REAL aexcey0, cexaey0, bexdey0, dexbey0;
-  REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4];
-  INEXACT REAL ab3, bc3, cd3, da3, ac3, bd3;
-  REAL abeps, bceps, cdeps, daeps, aceps, bdeps;
-  REAL temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48];
-  int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len;
-  REAL xdet[96], ydet[96], zdet[96], xydet[192];
-  int xlen, ylen, zlen, xylen;
-  REAL adet[288], bdet[288], cdet[288], ddet[288];
-  int alen, blen, clen, dlen;
-  REAL abdet[576], cddet[576];
-  int ablen, cdlen;
-  REAL fin1[1152];
-  int finlength;
-
-  REAL aextail, bextail, cextail, dextail;
-  REAL aeytail, beytail, ceytail, deytail;
-  REAL aeztail, beztail, ceztail, deztail;
-
-  INEXACT REAL bvirt;
-  REAL avirt, bround, around;
-  INEXACT REAL c;
-  INEXACT REAL abig;
-  REAL ahi, alo, bhi, blo;
-  REAL err1, err2, err3;
-  INEXACT REAL _i, _j;
-  REAL _0;
-
-  aex = (REAL) (pa[0] - pe[0]);
-  bex = (REAL) (pb[0] - pe[0]);
-  cex = (REAL) (pc[0] - pe[0]);
-  dex = (REAL) (pd[0] - pe[0]);
-  aey = (REAL) (pa[1] - pe[1]);
-  bey = (REAL) (pb[1] - pe[1]);
-  cey = (REAL) (pc[1] - pe[1]);
-  dey = (REAL) (pd[1] - pe[1]);
-  aez = (REAL) (pa[2] - pe[2]);
-  bez = (REAL) (pb[2] - pe[2]);
-  cez = (REAL) (pc[2] - pe[2]);
-  dez = (REAL) (pd[2] - pe[2]);
-
-  Two_Product(aex, bey, aexbey1, aexbey0);
-  Two_Product(bex, aey, bexaey1, bexaey0);
-  Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]);
-  ab[3] = ab3;
-
-  Two_Product(bex, cey, bexcey1, bexcey0);
-  Two_Product(cex, bey, cexbey1, cexbey0);
-  Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]);
-  bc[3] = bc3;
-
-  Two_Product(cex, dey, cexdey1, cexdey0);
-  Two_Product(dex, cey, dexcey1, dexcey0);
-  Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]);
-  cd[3] = cd3;
-
-  Two_Product(dex, aey, dexaey1, dexaey0);
-  Two_Product(aex, dey, aexdey1, aexdey0);
-  Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]);
-  da[3] = da3;
-
-  Two_Product(aex, cey, aexcey1, aexcey0);
-  Two_Product(cex, aey, cexaey1, cexaey0);
-  Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]);
-  ac[3] = ac3;
-
-  Two_Product(bex, dey, bexdey1, bexdey0);
-  Two_Product(dex, bey, dexbey1, dexbey0);
-  Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]);
-  bd[3] = bd3;
-
-  temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a);
-  temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b);
-  temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
-                                          temp8blen, temp8b, temp16);
-  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
-                                          temp16len, temp16, temp24);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, aex, temp48);
-  xlen = scale_expansion_zeroelim(temp48len, temp48, -aex, xdet);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, aey, temp48);
-  ylen = scale_expansion_zeroelim(temp48len, temp48, -aey, ydet);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, aez, temp48);
-  zlen = scale_expansion_zeroelim(temp48len, temp48, -aez, zdet);
-  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
-  alen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, adet);
-
-  temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a);
-  temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b);
-  temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
-                                          temp8blen, temp8b, temp16);
-  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
-                                          temp16len, temp16, temp24);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, bex, temp48);
-  xlen = scale_expansion_zeroelim(temp48len, temp48, bex, xdet);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, bey, temp48);
-  ylen = scale_expansion_zeroelim(temp48len, temp48, bey, ydet);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, bez, temp48);
-  zlen = scale_expansion_zeroelim(temp48len, temp48, bez, zdet);
-  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
-  blen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, bdet);
-
-  temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a);
-  temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b);
-  temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
-                                          temp8blen, temp8b, temp16);
-  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
-                                          temp16len, temp16, temp24);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, cex, temp48);
-  xlen = scale_expansion_zeroelim(temp48len, temp48, -cex, xdet);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, cey, temp48);
-  ylen = scale_expansion_zeroelim(temp48len, temp48, -cey, ydet);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, cez, temp48);
-  zlen = scale_expansion_zeroelim(temp48len, temp48, -cez, zdet);
-  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
-  clen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, cdet);
-
-  temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a);
-  temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b);
-  temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c);
-  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
-                                          temp8blen, temp8b, temp16);
-  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
-                                          temp16len, temp16, temp24);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, dex, temp48);
-  xlen = scale_expansion_zeroelim(temp48len, temp48, dex, xdet);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, dey, temp48);
-  ylen = scale_expansion_zeroelim(temp48len, temp48, dey, ydet);
-  temp48len = scale_expansion_zeroelim(temp24len, temp24, dez, temp48);
-  zlen = scale_expansion_zeroelim(temp48len, temp48, dez, zdet);
-  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
-  dlen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, ddet);
-
-  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
-  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
-  finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1);
-
-  det = estimate(finlength, fin1);
-  errbound = isperrboundB * permanent;
-  if ((det >= errbound) || (-det >= errbound)) {
-    return det;
-  }
-
-  Two_Diff_Tail(pa[0], pe[0], aex, aextail);
-  Two_Diff_Tail(pa[1], pe[1], aey, aeytail);
-  Two_Diff_Tail(pa[2], pe[2], aez, aeztail);
-  Two_Diff_Tail(pb[0], pe[0], bex, bextail);
-  Two_Diff_Tail(pb[1], pe[1], bey, beytail);
-  Two_Diff_Tail(pb[2], pe[2], bez, beztail);
-  Two_Diff_Tail(pc[0], pe[0], cex, cextail);
-  Two_Diff_Tail(pc[1], pe[1], cey, ceytail);
-  Two_Diff_Tail(pc[2], pe[2], cez, ceztail);
-  Two_Diff_Tail(pd[0], pe[0], dex, dextail);
-  Two_Diff_Tail(pd[1], pe[1], dey, deytail);
-  Two_Diff_Tail(pd[2], pe[2], dez, deztail);
-  if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0)
-      && (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0)
-      && (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0)
-      && (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)) {
-    return det;
-  }
-
-  errbound = isperrboundC * permanent + resulterrbound * Absolute(det);
-  abeps = (aex * beytail + bey * aextail)
-        - (aey * bextail + bex * aeytail);
-  bceps = (bex * ceytail + cey * bextail)
-        - (bey * cextail + cex * beytail);
-  cdeps = (cex * deytail + dey * cextail)
-        - (cey * dextail + dex * ceytail);
-  daeps = (dex * aeytail + aey * dextail)
-        - (dey * aextail + aex * deytail);
-  aceps = (aex * ceytail + cey * aextail)
-        - (aey * cextail + cex * aeytail);
-  bdeps = (bex * deytail + dey * bextail)
-        - (bey * dextail + dex * beytail);
-  det += (((bex * bex + bey * bey + bez * bez)
-           * ((cez * daeps + dez * aceps + aez * cdeps)
-              + (ceztail * da3 + deztail * ac3 + aeztail * cd3))
-           + (dex * dex + dey * dey + dez * dez)
-           * ((aez * bceps - bez * aceps + cez * abeps)
-              + (aeztail * bc3 - beztail * ac3 + ceztail * ab3)))
-          - ((aex * aex + aey * aey + aez * aez)
-           * ((bez * cdeps - cez * bdeps + dez * bceps)
-              + (beztail * cd3 - ceztail * bd3 + deztail * bc3))
-           + (cex * cex + cey * cey + cez * cez)
-           * ((dez * abeps + aez * bdeps + bez * daeps)
-              + (deztail * ab3 + aeztail * bd3 + beztail * da3))))
-       + 2.0 * (((bex * bextail + bey * beytail + bez * beztail)
-                 * (cez * da3 + dez * ac3 + aez * cd3)
-                 + (dex * dextail + dey * deytail + dez * deztail)
-                 * (aez * bc3 - bez * ac3 + cez * ab3))
-                - ((aex * aextail + aey * aeytail + aez * aeztail)
-                 * (bez * cd3 - cez * bd3 + dez * bc3)
-                 + (cex * cextail + cey * ceytail + cez * ceztail)
-                 * (dez * ab3 + aez * bd3 + bez * da3)));
-  if ((det >= errbound) || (-det >= errbound)) {
-    return det;
-  }
-
-  return insphereexact(pa, pb, pc, pd, pe);
-}
-
-REAL insphere(pa, pb, pc, pd, pe)
-REAL *pa;
-REAL *pb;
-REAL *pc;
-REAL *pd;
-REAL *pe;
-{
-  REAL aex, bex, cex, dex;
-  REAL aey, bey, cey, dey;
-  REAL aez, bez, cez, dez;
-  REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey;
-  REAL aexcey, cexaey, bexdey, dexbey;
-  REAL alift, blift, clift, dlift;
-  REAL ab, bc, cd, da, ac, bd;
-  REAL abc, bcd, cda, dab;
-  REAL aezplus, bezplus, cezplus, dezplus;
-  REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
-  REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
-  REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
-  REAL det;
-  REAL permanent, errbound;
-  REAL ins;
-
-  FPU_ROUND_DOUBLE;
-
-  aex = pa[0] - pe[0];
-  bex = pb[0] - pe[0];
-  cex = pc[0] - pe[0];
-  dex = pd[0] - pe[0];
-  aey = pa[1] - pe[1];
-  bey = pb[1] - pe[1];
-  cey = pc[1] - pe[1];
-  dey = pd[1] - pe[1];
-  aez = pa[2] - pe[2];
-  bez = pb[2] - pe[2];
-  cez = pc[2] - pe[2];
-  dez = pd[2] - pe[2];
-
-  aexbey = aex * bey;
-  bexaey = bex * aey;
-  ab = aexbey - bexaey;
-  bexcey = bex * cey;
-  cexbey = cex * bey;
-  bc = bexcey - cexbey;
-  cexdey = cex * dey;
-  dexcey = dex * cey;
-  cd = cexdey - dexcey;
-  dexaey = dex * aey;
-  aexdey = aex * dey;
-  da = dexaey - aexdey;
-
-  aexcey = aex * cey;
-  cexaey = cex * aey;
-  ac = aexcey - cexaey;
-  bexdey = bex * dey;
-  dexbey = dex * bey;
-  bd = bexdey - dexbey;
-
-  abc = aez * bc - bez * ac + cez * ab;
-  bcd = bez * cd - cez * bd + dez * bc;
-  cda = cez * da + dez * ac + aez * cd;
-  dab = dez * ab + aez * bd + bez * da;
-
-  alift = aex * aex + aey * aey + aez * aez;
-  blift = bex * bex + bey * bey + bez * bez;
-  clift = cex * cex + cey * cey + cez * cez;
-  dlift = dex * dex + dey * dey + dez * dez;
-
-  det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd);
-
-  aezplus = Absolute(aez);
-  bezplus = Absolute(bez);
-  cezplus = Absolute(cez);
-  dezplus = Absolute(dez);
-  aexbeyplus = Absolute(aexbey);
-  bexaeyplus = Absolute(bexaey);
-  bexceyplus = Absolute(bexcey);
-  cexbeyplus = Absolute(cexbey);
-  cexdeyplus = Absolute(cexdey);
-  dexceyplus = Absolute(dexcey);
-  dexaeyplus = Absolute(dexaey);
-  aexdeyplus = Absolute(aexdey);
-  aexceyplus = Absolute(aexcey);
-  cexaeyplus = Absolute(cexaey);
-  bexdeyplus = Absolute(bexdey);
-  dexbeyplus = Absolute(dexbey);
-  permanent = ((cexdeyplus + dexceyplus) * bezplus
-               + (dexbeyplus + bexdeyplus) * cezplus
-               + (bexceyplus + cexbeyplus) * dezplus)
-            * alift
-            + ((dexaeyplus + aexdeyplus) * cezplus
-               + (aexceyplus + cexaeyplus) * dezplus
-               + (cexdeyplus + dexceyplus) * aezplus)
-            * blift
-            + ((aexbeyplus + bexaeyplus) * dezplus
-               + (bexdeyplus + dexbeyplus) * aezplus
-               + (dexaeyplus + aexdeyplus) * bezplus)
-            * clift
-            + ((bexceyplus + cexbeyplus) * aezplus
-               + (cexaeyplus + aexceyplus) * bezplus
-               + (aexbeyplus + bexaeyplus) * cezplus)
-            * dlift;
-  errbound = isperrboundA * permanent;
-  if ((det > errbound) || (-det > errbound)) {
-    FPU_RESTORE;
-    return det;
-  }
-
-  ins = insphereadapt(pa, pb, pc, pd, pe, permanent);
-  FPU_RESTORE;
-  return ins;
-}
diff --git a/src_3rd/gts/predicates.h b/src_3rd/gts/predicates.h
deleted file mode 100644
index 8b026ed..0000000
--- a/src_3rd/gts/predicates.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-/* Header file for robust predicates by Jonathan Richard Shewchuk */
-
-#ifndef __PREDICATES_H__
-#define __PREDICATES_H__
-
-double orient2d            (double * pa,
-			    double * pb,
-			    double * pc);
-double orient3d            (double * pa,
-			    double * pb,
-			    double * pc,
-			    double * pd);
-double incircle            (double * pa,
-			    double * pb,
-			    double * pc,
-			    double * pd);
-double insphere            (double * pa,
-			    double * pb,
-			    double * pc,
-			    double * pd,
-			    double * pe);
-
-#endif /* __PREDICATES_H__ */
diff --git a/src_3rd/gts/psurface.c b/src_3rd/gts/psurface.c
deleted file mode 100644
index 6db3ae2..0000000
--- a/src_3rd/gts/psurface.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <math.h>
-#include "gts.h"
-
-#define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\
-                                   gts_eheap_insert (h, e))
-#define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\
-				  GTS_OBJECT (e)->reserved = NULL)
-
-static void psurface_destroy (GtsObject * object)
-{
-  GtsPSurface * ps = GTS_PSURFACE (object);
-  guint i;
-
-  if (!GTS_PSURFACE_IS_CLOSED (ps))
-    gts_psurface_close (ps);
-
-  for (i = 0; i < ps->split->len; i++)
-    if (g_ptr_array_index (ps->split, i))
-      gts_object_destroy (GTS_OBJECT (g_ptr_array_index (ps->split, i)));
-  g_ptr_array_free (ps->split, TRUE);
-
-  (* GTS_OBJECT_CLASS (gts_psurface_class ())->parent_class->destroy) (object);
-}
-
-static void psurface_class_init (GtsObjectClass * klass)
-{
-  klass->destroy = psurface_destroy;
-}
-
-static void psurface_init (GtsPSurface * psurface)
-{
-  psurface->s = NULL;
-  psurface->split = g_ptr_array_new ();
-  psurface->split_class = gts_split_class ();
-  psurface->pos = psurface->min = 0;
-  psurface->vertices = psurface->faces = NULL;
-}
-
-/**
- * gts_psurface_class:
- * 
- * Returns: the #GtsPSurfaceClass.
- */
-GtsPSurfaceClass * gts_psurface_class (void)
-{
-  static GtsPSurfaceClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo psurface_info = {
-      "GtsPSurface",
-      sizeof (GtsPSurface),
-      sizeof (GtsPSurfaceClass),
-      (GtsObjectClassInitFunc) psurface_class_init,
-      (GtsObjectInitFunc) psurface_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), 
-				  &psurface_info);
-  }
-
-  return klass;
-}
-
-static GtsVertex * edge_collapse (GtsPSurface * ps,
-				  GtsEdge * e,
-				  GtsEHeap * heap,
-				  GtsCoarsenFunc coarsen_func,
-				  gpointer coarsen_data,
-				  gdouble maxcosine2)
-{
-  GtsVertex  * v1 = GTS_SEGMENT (e)->v1, * v2 = GTS_SEGMENT (e)->v2, * mid;
-  GtsSplit * vs;
-  GtsObject * o1, * o2;
-
-  /* if the edge is degenerate (i.e. v1 == v2), destroy and return */
-  if (v1 == v2) {
-    gts_object_destroy (GTS_OBJECT (e));
-    return NULL;
-  }
-
-  if (!gts_edge_collapse_is_valid (e) ||
-      /* check that a non-manifold edge is not a contact edge */
-      (g_slist_length (e->triangles) > 2 && gts_edge_is_contact (e) > 1)) {
-    GTS_OBJECT (e)->reserved = 
-      gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE);
-    return NULL;
-  }
-
-  mid = (*coarsen_func) (e, ps->s->vertex_class, coarsen_data);
-
-  if (gts_edge_collapse_creates_fold (e, mid, maxcosine2)) {
-    GTS_OBJECT (e)->reserved = 
-      gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE);
-    gts_object_destroy (GTS_OBJECT (mid));
-    return NULL;
-  }
-
-  if (GTS_OBJECT (v1)->reserved)
-    o1 = GTS_OBJECT (v1)->reserved;
-  else
-    o1 = GTS_OBJECT (v1);
-  if (GTS_OBJECT (v2)->reserved)
-    o2 = GTS_OBJECT (v2)->reserved;
-  else
-    o2 = GTS_OBJECT (v2);
-  vs = gts_split_new (ps->split_class, mid, o1, o2);
-  gts_split_collapse (vs, ps->s->edge_class, heap);
-  GTS_OBJECT (vs->v)->reserved = vs;
-  g_ptr_array_add (ps->split, vs);
-
-  return mid;
-}
-
-static void update_2nd_closest_neighbors (GtsVertex * v, GtsEHeap * heap)
-{
-  GSList * i = v->segments;
-  GSList * list = NULL;
-  
-  while (i) {
-    GtsSegment * s = i->data;
-    if (GTS_IS_EDGE (s)) {
-      GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1;
-      GSList * j = v1->segments;
-      while (j) {
-	GtsSegment * s1 = j->data;
-	if (GTS_IS_EDGE (s1) && !g_slist_find (list, s1))
-	  list = g_slist_prepend (list, s1);
-	j = j->next;
-      }
-    }
-    i = i->next;
-  }
-
-  i = list;
-  while (i) {
-    GtsEdge * e = i->data;
-    if (GTS_OBJECT (e)->reserved)
-      HEAP_REMOVE_OBJECT (heap, e);
-    HEAP_INSERT_OBJECT (heap, e);
-    i = i->next;
-  }
-
-  g_slist_free (list);
-}
-
-static gdouble edge_length2 (GtsEdge * e)
-{
-  return gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), 
-			      GTS_POINT (GTS_SEGMENT (e)->v2));
-}
-
-static void create_heap_coarsen (GtsEdge * e, GtsEHeap * heap)
-{
-  HEAP_INSERT_OBJECT (heap, e);
-}
-
-/* #define DEBUG_FOLD */
-/* #define DEBUG_CONTACT_VERTEX */
-
-#ifdef DEBUG_FOLD
-static void check_fold (GtsTriangle * t, gdouble * maxcosine2)
-{
-  GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3;
-
-  
-  if (gts_triangles_are_folded (e1->triangles, 
-				GTS_SEGMENT (e1)->v1,
-				GTS_SEGMENT (e1)->v2,
-				*maxcosine2) ||
-      gts_triangles_are_folded (e2->triangles, 
-				GTS_SEGMENT (e2)->v1,
-				GTS_SEGMENT (e2)->v2,
-				*maxcosine2) ||
-      gts_triangles_are_folded (e3->triangles, 
-				GTS_SEGMENT (e3)->v1,
-				GTS_SEGMENT (e3)->v2,
-				*maxcosine2)) {
-    fprintf (stderr, "triangle %p:(%p,%p,%p) is folded\n", t, e1, e2, e3);
-    g_assert_not_reached ();
-  }
-}
-#endif
-
-/**
- * gts_psurface_new:
- * @klass: a #GtsPSurfaceClass.
- * @surface: a #GtsSurface.
- * @split_class: a #GtsSplitClass to use for the new progressive surface.
- * @cost_func: cost function for the edge collapse algorithm.
- * @cost_data: data to pass to @cost_func.
- * @coarsen_func: the function returning the vertex replacement for the edge 
- * collapse.
- * @coarsen_data: data to pass to @coarsen_func.
- * @stop_func: the function to call to decide whether to stop the coarsening
- * process.
- * @stop_data: data to pass to @stop_func.
- * @minangle: the minimum angle allowable between two neighboring triangles. 
- * This is used to avoid introducing folds in the mesh during simplification.
- *
- * This function works in exactly the same way as the
- * gts_surface_coarsen() function, except that the history of edge
- * collapse is saved in an array of #GtsSplit objects. This allows for
- * dynamic continuous multiresolution control of the input @surface.
- *
- * Returns: a new progressive surface.
- */
-GtsPSurface * gts_psurface_new (GtsPSurfaceClass * klass,
-				GtsSurface * surface,
-				GtsSplitClass * split_class,
-				GtsKeyFunc cost_func,
-				gpointer cost_data,
-				GtsCoarsenFunc coarsen_func,
-				gpointer coarsen_data,
-				GtsStopFunc stop_func,
-				gpointer stop_data,
-				gdouble minangle)
-{
-  GtsPSurface * psurface;
-  GtsEHeap * heap;
-  GtsEdge * e;
-  gdouble top_cost, maxcosine2;
-  guint i;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (surface != NULL, NULL);
-  g_return_val_if_fail (split_class != NULL, NULL);
-  g_return_val_if_fail (stop_func != NULL, NULL);
-
-  psurface = GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  psurface->s = surface;
-  psurface->split_class = split_class;
-
-  if (cost_func == NULL)
-    cost_func = (GtsKeyFunc) edge_length2;
-  if (coarsen_func == NULL)
-    coarsen_func = (GtsCoarsenFunc) gts_segment_midvertex;
-
-  heap = gts_eheap_new (cost_func, cost_data);
-  maxcosine2 = cos (minangle); maxcosine2 *= maxcosine2;
-
-  gts_eheap_freeze (heap);
-  gts_surface_foreach_edge (surface, (GtsFunc) create_heap_coarsen, heap);
-  gts_eheap_thaw (heap);
-  /* we want to control edge destruction manually */
-  gts_allow_floating_edges = TRUE;
-  while ((e = gts_eheap_remove_top (heap, &top_cost)) &&
-	 (top_cost < G_MAXDOUBLE) &&
-	 !(*stop_func) (top_cost, gts_eheap_size (heap) - 
-			gts_edge_face_number (e, surface), stop_data)) {
-    GtsVertex * v = edge_collapse (psurface, e, heap, 
-				   coarsen_func, coarsen_data, maxcosine2);
-    if (v != NULL) {
-      update_2nd_closest_neighbors (v, heap);
-#ifdef DEBUG_FOLD
-      {
-	GSList * triangles = gts_vertex_triangles (v, NULL), * i;
-	fprintf (stderr, "\n---- Check for folds ----\n%p: ", v);
-	i = triangles;
-	while (i) {
-	  GtsTriangle * t = i->data;
-	  fprintf (stderr, "%p:(%p,%p,%p) ", t, t->e1, t->e2, t->e3);
-	  i = i->next;
-	}
-	fprintf (stderr, "\n");
-	g_slist_free (triangles);
-	gts_surface_foreach_face (surface, (GtsFunc) check_fold, &maxcosine2);
-      }
-#endif
-#ifdef DEBUG_CONTACT_VERTEX
-      if (gts_vertex_is_contact (v, FALSE) != 1) {
-	FILE * fptr = fopen ("after", "wt");
-	GSList * triangles = gts_vertex_triangles (v, NULL), * i;
-
-	fprintf (stderr, "collapse of %p created a contact vertex\n", e);
-		 
-	fprintf (fptr, 
-		 "(geometry \"sphere\" { = SPHERE 0.1 0. 0. 0. })\n"
-		 "(normalization \"sphere\" none)\n");
-	i = triangles;
-	while (i) {
-	  gts_write_triangle (i->data, GTS_POINT (v), fptr);
-	  i = i->next;
-	}
-	g_assert_not_reached ();
-      }
-#endif
-    }
-  }
-  gts_allow_floating_edges = FALSE;
-
-  /* set reserved field of remaining edges back to NULL */
-  if (e) GTS_OBJECT (e)->reserved = NULL;
-  gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL);
-
-  gts_eheap_destroy (heap);
-
-  psurface->pos = psurface->split->len;
-  psurface->min = gts_surface_vertex_number (psurface->s);
-
-  /* set reserved field of vertices (used to build the hierarchy) 
-     back to NULL */
-  for (i = 0; i < psurface->split->len; i++) {
-    GtsSplit * vs = g_ptr_array_index (psurface->split, i);
-    gts_object_reset_reserved (GTS_OBJECT (vs->v));
-  }
-
-  return psurface;
-}
-
-/**
- * gts_psurface_add_vertex:
- * @ps: a #GtsPSurface.
- *
- * Adds a vertex to the progressive surface @ps by expanding the next
- * available #GtsSplit.
- *
- * Returns: the expanded #GtsSplit or %NULL if all the #GtsSplit have already
- * been expanded.
- */
-GtsSplit * gts_psurface_add_vertex (GtsPSurface * ps) 
-{ 
-  GtsSplit * vs;
-
-  g_return_val_if_fail (ps != NULL, NULL);
-  g_return_val_if_fail (GTS_PSURFACE_IS_CLOSED (ps), NULL);
-
-  if (ps->pos == 0)
-    return NULL;
-
-  vs = g_ptr_array_index (ps->split, --ps->pos);
-  gts_split_expand (vs, ps->s, ps->s->edge_class);
-
-  return vs;
-}
-
-/**
- * gts_psurface_remove_vertex:
- * @ps: a #GtsPSurface.
- *
- * Removes one vertex from the progressive surface @ps by collapsing the first
- * available #GtsSplit.
- *
- * Returns: the collapsed #GtsSplit or %NULL if all the #GtsSplit have already
- * been collapsed.
- */
-GtsSplit * gts_psurface_remove_vertex (GtsPSurface * ps)
-{
-  GtsSplit * vs;
-
-  g_return_val_if_fail (ps != NULL, NULL);
-  g_return_val_if_fail (GTS_PSURFACE_IS_CLOSED (ps), NULL);
-
-  if (ps->pos == ps->split->len)
-    return NULL;
-
-  vs = g_ptr_array_index (ps->split, ps->pos++);
-  gts_split_collapse (vs, ps->s->edge_class, NULL);
-
-  return vs;
-}
-
-/**
- * gts_psurface_max_vertex_number:
- * @ps: a #GtsPSurface.
- *
- * Returns: the maximum number of vertices of @ps i.e. the number of vertices
- * if all the #GtsSplit were expanded.
- */
-guint gts_psurface_max_vertex_number (GtsPSurface * ps)
-{
-  g_return_val_if_fail (ps != NULL, 0);
-
-  return ps->min + ps->split->len;
-}
-
-/**
- * gts_psurface_min_vertex_number:
- * @ps: a #GtsPSurface.
- *
- * Returns: the minimum number of vertices of @ps i.e. the number of vertices
- * if all the #GtsSplit were collapsed.
- */
-guint gts_psurface_min_vertex_number (GtsPSurface * ps)
-{
-  g_return_val_if_fail (ps != NULL, 0);
-
-  return ps->min;
-}
-
-/**
- * gts_psurface_set_vertex_number:
- * @ps: a #GtsPSurface.
- * @n: a number of vertices.
- *
- * Performs the required number of collapses or expansions to set the number
- * of vertices of @ps to @n.
- */
-void gts_psurface_set_vertex_number (GtsPSurface * ps, guint n)
-{
-  g_return_if_fail (ps != NULL);
-  g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps));
-
-  n = ps->min + ps->split->len - n;
-  while (ps->pos > n && gts_psurface_add_vertex (ps))
-    ;
-  while (ps->pos < n && gts_psurface_remove_vertex (ps))
-    ;
-}
-
-/**
- * gts_psurface_get_vertex_number:
- * @ps: a #GtsPSurface.
- *
- * Returns: the current number of vertices of @ps.
- */
-guint gts_psurface_get_vertex_number (GtsPSurface * ps)
-{
-  g_return_val_if_fail (ps != NULL, 0);
-  
-  if (!GTS_PSURFACE_IS_CLOSED (ps))
-    return ps->min + ps->pos;
-  else
-    return ps->min + ps->split->len - ps->pos;
-}
-
-/**
- * gts_psurface_foreach_vertex:
- * @ps: a #GtsPSurface.
- * @func: a function to call for each vertex of @ps.
- * @data: data to be passed to @func.
- *
- * Calls @func for each (potential) vertex of @ps, whether actually used
- * or not. The vertices are called in the order they were created during the
- * edge collapse operation.
- */
-void gts_psurface_foreach_vertex (GtsPSurface * ps, 
-				  GtsFunc func, 
-				  gpointer data)
-{
-  guint i;
-
-  g_return_if_fail (ps != NULL);
-  g_return_if_fail (func != NULL);
-  g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps));
-  
-  for (i = 0; i < ps->split->len; i++) {
-    GtsSplit * vs = g_ptr_array_index (ps->split, i);
-    (*func) (vs->v, data);
-  }
-}
diff --git a/src_3rd/gts/refine.c b/src_3rd/gts/refine.c
deleted file mode 100644
index 293eb11..0000000
--- a/src_3rd/gts/refine.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include "gts.h"
-
-/**
- * gts_vertex_encroaches_edge:
- * @v: a #GtsVertex.
- * @e: a #GtsEdge.
- *
- * Returns: %TRUE if @v is strictly contained in the diametral circle of @e,
- * %FALSE otherwise.
- */
-gboolean gts_vertex_encroaches_edge (GtsVertex * v, GtsEdge * e)
-{
-  GtsPoint * p, * p1, * p2;
-
-  g_return_val_if_fail (v != NULL, FALSE);
-  g_return_val_if_fail (e != NULL, FALSE);
-
-  p = GTS_POINT (v);
-  p1 = GTS_POINT (GTS_SEGMENT (e)->v1);
-  p2 = GTS_POINT (GTS_SEGMENT (e)->v2);
-
-  if ((p1->x - p->x)*(p2->x - p->x) + (p1->y - p->y)*(p2->y - p->y) < 0.0)
-    return TRUE;
-  return FALSE;
-}
-
-/**
- * gts_edge_is_encroached:
- * @e: a #GtsEdge.
- * @s: a #GtsSurface describing a (constrained) Delaunay triangulation.
- * @encroaches: a #GtsEncroachFunc.
- * @data: user data to be passed to @encroaches.
- *
- * Returns: a #GtsVertex belonging to @s and encroaching upon @e
- * (as defined by @encroaches) or %NULL if there is none.  
- */
-GtsVertex * gts_edge_is_encroached (GtsEdge * e,
-				    GtsSurface * s,
-				    GtsEncroachFunc encroaches,
-				    gpointer data)
-{
-  GSList * i;
-
-  g_return_val_if_fail (e != NULL, NULL);
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (encroaches != NULL, NULL);
-
-  i = e->triangles;
-  while (i) {
-    GtsFace * f = i->data;
-    if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) {
-      GtsVertex * v = gts_triangle_vertex_opposite (GTS_TRIANGLE (f), e);
-      if ((* encroaches) (v, e, s, data))
-	return v;
-    }
-    i = i->next;
-  }
-
-  return NULL;
-}
-
-#define ALREADY_ENCROACHED(c) (GTS_OBJECT (c)->reserved)
-
-static void vertex_encroaches (GtsVertex * v,
-			       GtsSurface * surface,
-			       GtsFifo * encroached,
-			       GtsEncroachFunc encroaches,
-			       gpointer data)
-{
-  GSList * triangles, * i;
-
-  g_return_if_fail (v != NULL);
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (encroached != NULL);
-  g_return_if_fail (encroaches != NULL);
-
-  i = triangles = gts_vertex_triangles (v, NULL);
-  while (i) {
-    GtsFace * f = i->data;
-    if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, surface)) {
-      GtsEdge * e = gts_triangle_edge_opposite (i->data, v);
-      if (!ALREADY_ENCROACHED (e) && 
-	  GTS_IS_CONSTRAINT (e) &&
-	  (* encroaches) (v, e, surface, data)) {
-	gts_fifo_push (encroached, e);
-	ALREADY_ENCROACHED (e) = encroached;
-      }
-    }
-    i = i->next;
-  }
-  g_slist_free (triangles);
-}
-
-static void make_encroached_fifo (GtsEdge * e, gpointer * datas)
-{
-  GtsFifo * fifo = datas[0];
-  GtsSurface * s = datas[1];
-  GtsEncroachFunc encroaches = (GtsEncroachFunc) datas[2];
-  gpointer data = datas[3];
-
-  if (GTS_IS_CONSTRAINT (e) && 
-      gts_edge_is_encroached (e, s, encroaches, data)) {
-    gts_fifo_push (fifo, e);
-    ALREADY_ENCROACHED (e) = fifo;
-  }
-}
-
-#define SQUARE_ROOT_TWO 1.41421356237309504880168872420969807856967187
-#define DISTANCE_2D(v1, v2) (sqrt ((GTS_POINT (v2)->x - GTS_POINT (v1)->x)*\
-                                   (GTS_POINT (v2)->x - GTS_POINT (v1)->x) +\
-                                   (GTS_POINT (v2)->y - GTS_POINT (v1)->y)*\
-                                   (GTS_POINT (v2)->y - GTS_POINT (v1)->y)))
-
-/* finds where to split the given edge to avoid infinite cycles. (see
-   Shewchuk's thesis for details */
-static GtsVertex * split_edge (GtsEdge * e,
-			       GtsSurface * surface)
-{
-  GSList * i = e->triangles;
-  GtsEdge * c = NULL;
-
-  /* look for constraints touching e */
-  while (i && !c) {
-    GtsTriangle * t = i->data;
-    if (GTS_IS_FACE (t) && 
-	gts_face_has_parent_surface (GTS_FACE (t), surface)) {
-      GtsEdge * e1, * e2;
-      if (t->e1 == e) { e1 = t->e2; e2 = t->e3; }
-      else if (t->e2 == e) { e1 = t->e1; e2 = t->e3; }
-      else { e1 = t->e1; e2 = t->e2; }
-      if (GTS_IS_CONSTRAINT (e1) && !GTS_IS_CONSTRAINT (e2))
-	c = e1;
-      else if (GTS_IS_CONSTRAINT (e2) && !GTS_IS_CONSTRAINT (e1))
-	c = e2;
-    }
-    i = i->next;
-  }
-  if (c) {
-    /* use power of two concentric shells */
-    GtsVertex * v1 = GTS_SEGMENT (e)->v1;
-    GtsVertex * v2 = GTS_SEGMENT (e)->v2;
-    gdouble l = DISTANCE_2D (v1, v2);
-    gdouble nearestpower = 1., split;
-
-    while (l > SQUARE_ROOT_TWO*nearestpower)
-      nearestpower *= 2.;
-    while (l < SQUARE_ROOT_TWO*nearestpower/2.)
-      nearestpower /= 2.;
-    split = nearestpower/l/2.;
-
-    if (GTS_SEGMENT (c)->v1 == v2 || GTS_SEGMENT (c)->v2 == v2)
-      split = 1. - split;
-    return gts_vertex_new (surface->vertex_class,
-			   (1. - split)*GTS_POINT (v1)->x +
-			   split*GTS_POINT (v2)->x,
-			   (1. - split)*GTS_POINT (v1)->y +
-			   split*GTS_POINT (v2)->y,
-			   (1. - split)*GTS_POINT (v1)->z +
-			   split*GTS_POINT (v2)->z);
-  }
-  else
-    return gts_segment_midvertex (GTS_SEGMENT (e), surface->vertex_class);
-}
-
-static gint split_encroached (GtsSurface * surface, 
-			      GtsFifo * encroached,
-			      gint steiner_max,
-			      GtsEncroachFunc encroaches,
-			      gpointer data)
-{
-  GtsSegment * s;
-
-  while (steiner_max-- != 0 && (s = gts_fifo_pop (encroached))) {
-    GtsVertex * v = split_edge (GTS_EDGE (s), surface);
-    GtsFace * boundary = gts_edge_is_boundary (GTS_EDGE (s), surface);
-    GtsFace * f = boundary;
-#if 1
-    GtsEdge * e1 = GTS_EDGE (gts_object_clone (GTS_OBJECT (s)));
-    GtsEdge * e2 = GTS_EDGE (gts_object_clone (GTS_OBJECT (s)));
-
-    GTS_SEGMENT (e1)->v1 = s->v1;
-    s->v1->segments = g_slist_prepend (s->v1->segments, e1);
-    GTS_SEGMENT (e1)->v2 = v;
-    v->segments = g_slist_prepend (v->segments, e1);
-
-    GTS_SEGMENT (e2)->v1 = v;
-    v->segments = g_slist_prepend (v->segments, e2);
-    GTS_SEGMENT (e2)->v2 = s->v2;
-    s->v2->segments = g_slist_prepend (s->v2->segments, e2);
-#else
-    GtsEdge * e1 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (s)->klass),
-				 s->v1, v);
-    GtsEdge * e2 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (s)->klass),
-				 v, s->v2);
-#endif
-
-    GTS_OBJECT (s)->klass = GTS_OBJECT_CLASS (surface->edge_class);
-
-    if (f == NULL)
-      g_assert ((f = gts_edge_has_parent_surface (GTS_EDGE (s), surface)));
-    g_assert (gts_delaunay_add_vertex_to_face (surface, v, f) == NULL);
-
-    if (boundary)
-      gts_object_destroy (GTS_OBJECT (s));
-
-    vertex_encroaches (v, surface, encroached, encroaches, data);
-
-    if (gts_edge_is_encroached (e1, surface, encroaches, data)) {
-      gts_fifo_push (encroached, e1);
-      ALREADY_ENCROACHED (e1) = encroached;
-    }
-    if (gts_edge_is_encroached (e2, surface, encroaches, data)) {
-      gts_fifo_push (encroached, e2);
-      ALREADY_ENCROACHED (e2) = encroached;
-    }
-  }
-
-  return steiner_max;
-}
-
-/**
- * gts_delaunay_conform:
- * @surface: a #GtsSurface describing a constrained Delaunay triangulation.
- * @steiner_max: maximum number of Steiner points.
- * @encroaches: a #GtsEncroachFunc.
- * @data: user-data to pass to @encroaches.
- *
- * Recursively split constraints of @surface which are encroached by
- * vertices of @surface (see Shewchuk 96 for details). The split
- * constraints are destroyed and replaced by a set of new constraints
- * of the same class. If gts_vertex_encroaches_edge() is used for
- * @encroaches, the resulting surface will be Delaunay conforming.
- *
- * If @steiner_max is positive or nul, the recursive splitting
- * procedure will stop when this maximum number of Steiner points is
- * reached. In that case the resulting surface will not necessarily be
- * Delaunay conforming.
- *
- * Returns: the number of remaining encroached edges. If @steiner_max
- * is set to a negative value and gts_vertex_encroaches_edge() is used
- * for @encroaches this should always be zero. 
- */
-guint gts_delaunay_conform (GtsSurface * surface,
-			    gint steiner_max,
-			    GtsEncroachFunc encroaches,
-			    gpointer data)
-{
-  GtsFifo * encroached;
-  gpointer datas[4];
-  guint encroached_number;
-
-  g_return_val_if_fail (surface != NULL, 0);
-  g_return_val_if_fail (surface != NULL, 0);
-  g_return_val_if_fail (encroaches != NULL, 0);
-
-  datas[0] = encroached = gts_fifo_new ();
-  datas[1] = surface;
-  datas[2] = encroaches;
-  datas[3] = data;
-  gts_surface_foreach_edge (surface, (GtsFunc) make_encroached_fifo, datas);
-
-  split_encroached (surface, 
-		    encroached, 
-		    steiner_max,
-		    encroaches, data);
-  gts_fifo_foreach (encroached, (GtsFunc) gts_object_reset_reserved, NULL);
-  encroached_number = gts_fifo_size (encroached);
-  gts_fifo_destroy (encroached);
-  return encroached_number;
-}
-
-#define EHEAP_PAIR(f) (GTS_OBJECT (f)->reserved)
-
-static void heap_surface_add_face (GtsSurface * s, GtsFace * f)
-{
-  GtsEHeap * heap = GTS_OBJECT (s)->reserved;
-  gdouble key = gts_eheap_key (heap, f);
-
-  if (key != 0.)
-    EHEAP_PAIR (f) = gts_eheap_insert_with_key (heap, f, key);
-  
-  if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->add_face)
-    (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->add_face) 
-      (s, f);
-}
-
-static void heap_surface_remove_face (GtsSurface * s, GtsFace * f)
-{
-  GtsEHeap * heap = GTS_OBJECT (s)->reserved;
-
-  if (EHEAP_PAIR (f))
-    gts_eheap_remove (heap, EHEAP_PAIR (f));
-
-  if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->remove_face)
-    (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->remove_face) 
-      (s, f);
-}
-
-static void heap_surface_class_init (GtsSurfaceClass * klass)
-{
-  klass->add_face = heap_surface_add_face;
-  klass->remove_face = heap_surface_remove_face;
-}
-
-static GtsObjectClass * heap_surface_class_new (GtsObjectClass * parent_class)
-{
-  GtsObjectClassInfo heap_surface_info;
-
-  heap_surface_info = parent_class->info;
-  heap_surface_info.class_init_func = (GtsObjectClassInitFunc)
-    heap_surface_class_init;
-  return gts_object_class_new (parent_class,
-			       &heap_surface_info);
-}
-
-static void make_face_heap (GtsFace * f, GtsEHeap * heap)
-{
-  gdouble key = gts_eheap_key (heap, f);
-
-  if (key != 0.)
-    EHEAP_PAIR (f) = gts_eheap_insert_with_key (heap, f, key);
-}
-
-/**
- * gts_delaunay_refine:
- * @surface: a #GtsSurface describing a conforming Delaunay triangulation.
- * @steiner_max: maximum number of Steiner points.
- * @encroaches: a #GtsEncroachFunc.
- * @encroach_data: user-data to pass to @encroaches.
- * @cost: a #GtsKeyFunc used to sort the faces during refinement.
- * @cost_data: user-data to pass to @cost.
- *
- * An implementation of the refinement algorithm described in Ruppert
- * (1995) and Shewchuk (1996).
- * 
- * Returns: the number of unrefined faces of @surface left. Should be zero
- * if @steiner_max is set to a negative value.
- */
-guint gts_delaunay_refine (GtsSurface * surface,
-			   gint steiner_max,
-			   GtsEncroachFunc encroaches,
-			   gpointer encroach_data,
-			   GtsKeyFunc cost,
-			   gpointer cost_data)
-{
-  GtsObjectClass * heap_surface_class;
-  GtsObjectClass * original_class;
-  GtsEHeap * heap;
-  GtsFifo * encroached;
-  GtsFace * f;
-  guint unrefined_number;
-
-  g_return_val_if_fail (surface != NULL, 0);
-  g_return_val_if_fail (encroaches != NULL, 0);
-  g_return_val_if_fail (cost != NULL, 0);
-
-  original_class = GTS_OBJECT (surface)->klass;
-  heap_surface_class = heap_surface_class_new (original_class);
-  GTS_OBJECT (surface)->klass = heap_surface_class;
-
-  heap = gts_eheap_new (cost, cost_data);
-  gts_surface_foreach_face (surface, (GtsFunc) make_face_heap, heap);
-  encroached = gts_fifo_new ();
-  
-  GTS_OBJECT (surface)->reserved = heap;
-
-  while (steiner_max-- != 0 && (f = gts_eheap_remove_top (heap, NULL))) {
-    GtsVertex * c = 
-      GTS_VERTEX (gts_triangle_circumcircle_center (GTS_TRIANGLE (f),
-		  GTS_POINT_CLASS (surface->vertex_class)));
-    EHEAP_PAIR (f) = NULL;
-    g_assert (c != NULL);
-    g_assert (gts_delaunay_add_vertex (surface, c, f) == NULL);
-
-    vertex_encroaches (c, surface, encroached, encroaches, encroach_data);
-    if (!gts_fifo_is_empty (encroached)) {
-      gts_delaunay_remove_vertex (surface, c);
-      steiner_max = split_encroached (surface, 
-				      encroached, 
-				      steiner_max, 
-				      encroaches, 
-				      encroach_data);
-    }
-  }
-
-  unrefined_number = gts_eheap_size (heap);
-  gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL);
-  gts_eheap_destroy (heap);
-
-  gts_fifo_foreach (encroached, (GtsFunc) gts_object_reset_reserved, NULL);
-  gts_fifo_destroy (encroached);
-
-  GTS_OBJECT (surface)->klass = original_class;
-  GTS_OBJECT (surface)->reserved = NULL;
-  g_free (heap_surface_class);
-
-  return unrefined_number;
-}
diff --git a/src_3rd/gts/rounding.h b/src_3rd/gts/rounding.h
deleted file mode 100644
index 053b32f..0000000
--- a/src_3rd/gts/rounding.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#ifdef HAVE_FPU_CONTROL_H
-#  include <fpu_control.h>
-#  ifdef _FPU_EXTENDED
-#   if !defined(__alpha__) || !defined(__GLIBC__)
-#    if defined(__arm__)
-     static fpu_control_t fpu_round_double = _FPU_DEFAULT;
-#    else
-     static fpu_control_t fpu_round_double =
-       (_FPU_DEFAULT & ~ _FPU_EXTENDED)|_FPU_DOUBLE;
-#    endif
-     static fpu_control_t fpu_init;
-#    define FPU_ROUND_DOUBLE  { _FPU_GETCW(fpu_init);\
-                                _FPU_SETCW(fpu_round_double); }
-#    define FPU_RESTORE       {_FPU_SETCW(fpu_init);}
-#   else /* __alpha__ && __GLIBC__ */
-#    define FPU_ROUND_DOUBLE
-#    define FPU_RESTORE
-#   endif /* __alpha__ && __GLIBC__ */
-#  else /* not FPU_EXTENDED */
-#    define FPU_ROUND_DOUBLE
-#    define FPU_RESTORE
-#  endif /* not FPU_EXTENDED */
-#else /* not HAVE_FPU_CONTROL_H */
-#  ifdef __FreeBSD__
-#    include <floatingpoint.h>
-#    define FPU_ROUND_DOUBLE  (fpsetprec(FP_PD))
-#    define FPU_RESTORE       (fpsetprec(FP_PE))
-#  else /* not __FreeBSD__ */
-#    ifdef WIN32
-#      ifdef _MSC_VER
-#        include <float.h>
-         static unsigned int fpu_init;
-#        define FPU_ROUND_DOUBLE (fpu_init = _controlfp (0, 0),\
-                                 _controlfp (_PC_53, MCW_PC))
-#        define FPU_RESTORE      (_controlfp (fpu_init, 0xfffff))
-#      elif __MINGW32__
-#        include <float.h>
-         static unsigned int fpu_init;
-#        define FPU_ROUND_DOUBLE (fpu_init = _controlfp (0, 0),\
-                                  _controlfp (_PC_53, _MCW_PC))
-#        define FPU_RESTORE      (_controlfp (fpu_init, 0xfffff))
-#      else /* not _MSC_VER or __MINGW32__ */
-#        error "You need MSVC or MinGW for the Win32 version"
-#      endif /*  not _MSC_VER or __MINGW32__ */
-#    else /* not WIN32 */
-#      ifdef __CYGWIN__
-         typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__)));
-         static fpu_control_t fpu_round_double = 0x027f;
-         static fpu_control_t fpu_init;
-#        define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw))
-#        define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw))
-#        define FPU_ROUND_DOUBLE  { _FPU_GETCW(fpu_init);\
-                                    _FPU_SETCW(fpu_round_double); }
-#        define FPU_RESTORE       { _FPU_SETCW(fpu_init);}
-#      else /* not __CYGWIN__ */
-#        ifdef CPP_HAS_WARNING
-#          warning "Unknown CPU: assuming default double precision rounding"
-#        endif /* CPP_HAS_WARNING */
-#        define FPU_ROUND_DOUBLE
-#        define FPU_RESTORE
-#      endif /* not __CYGWIN__ */
-#    endif /* not WIN32 */
-#  endif /* not __FreeBSD__ */
-#endif /* not HAVE_FPU_CONTROL_H */
diff --git a/src_3rd/gts/segment.c b/src_3rd/gts/segment.c
deleted file mode 100644
index 58a0540..0000000
--- a/src_3rd/gts/segment.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-static void segment_destroy (GtsObject * object)
-{
-  GtsSegment * segment = GTS_SEGMENT (object);
-  GtsVertex * v1 = segment->v1;
-  GtsVertex * v2 = segment->v2;
-
-  v1->segments = g_slist_remove (v1->segments, segment);
-  if (!GTS_OBJECT_DESTROYED (v1) &&
-      !gts_allow_floating_vertices && v1->segments == NULL)
-    gts_object_destroy (GTS_OBJECT (v1));
-
-  v2->segments = g_slist_remove (v2->segments, segment);
-  if (!GTS_OBJECT_DESTROYED (v2) &&
-      !gts_allow_floating_vertices && v2->segments == NULL)
-    gts_object_destroy (GTS_OBJECT (v2));
-
-  (* GTS_OBJECT_CLASS (gts_segment_class ())->parent_class->destroy) (object);
-}
-
-static void segment_class_init (GtsObjectClass * klass)
-{
-  klass->destroy = segment_destroy;
-}
-
-static void segment_init (GtsSegment * segment)
-{
-  segment->v1 = segment->v2 = NULL;
-}
-
-/**
- * gts_segment_class:
- *
- * Returns: the #GtsSegmentClass.
- */
-GtsSegmentClass * gts_segment_class (void)
-{
-  static GtsSegmentClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo segment_info = {
-      "GtsSegment",
-      sizeof (GtsSegment),
-      sizeof (GtsSegmentClass),
-      (GtsObjectClassInitFunc) segment_class_init,
-      (GtsObjectInitFunc) segment_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), 
-				  &segment_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_segment_new:
- * @klass: a #GtsSegmentClass.
- * @v1: a #GtsVertex.
- * @v2: another #GtsVertex different from @v1.
- *
- * Returns: a new #GtsSegment linking @v1 and @v2.
- */
-GtsSegment * gts_segment_new (GtsSegmentClass * klass, 
-			      GtsVertex * v1, GtsVertex * v2)
-{
-  GtsSegment * s;
-
-  g_return_val_if_fail (v1 != NULL, NULL);
-  g_return_val_if_fail (v2 != NULL, NULL);
-  g_return_val_if_fail (v1 != v2, NULL);
-
-  s = GTS_SEGMENT (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  s->v1 = v1;
-  s->v2 = v2;
-  v1->segments = g_slist_prepend (v1->segments, s);
-  v2->segments = g_slist_prepend (v2->segments, s);
-  
-  return s;
-}
-
-/**
- * gts_segment_is_duplicate:
- * @s: a #GtsSegment.
- *
- * Returns: the first #GtsSegment different from @s which shares the
- * same endpoints or %NULL if there is none.
- */
-GtsSegment * gts_segment_is_duplicate (GtsSegment * s)
-{
-  GSList * i;
-  GtsVertex * v2;
-
-  g_return_val_if_fail (s != NULL, NULL);
-
-  v2 = s->v2;
-  i = s->v1->segments;
-  if (s->v1 == v2) /* s is degenerate: special treatment */
-    while (i) {
-      GtsSegment * s1 = i->data;
-      if (s1 != s && s1->v1 == v2 && s1->v2 == v2)
-	return s1;
-      i = i->next;
-    }
-  else /* s is not degenerate */
-    while (i) {
-      GtsSegment * s1 = i->data;
-      if (s1 != s && (s1->v1 == v2 || s1->v2 == v2))
-	return s1;
-      i = i->next;
-    }
-  return NULL;
-}
-
-/**
- * gts_segments_are_intersecting:
- * @s1: a #GtsSegment.
- * @s2: a #GtsSegment.
- *
- * Returns: %GTS_IN if @s1 and @s2 are intersecting, %GTS_ON if one of the
- * endpoints of @s1 (resp. @s2) lies on @s2 (resp. @s1), %GTS_OUT otherwise.
- */
-GtsIntersect gts_segments_are_intersecting (GtsSegment * s1, GtsSegment * s2)
-{
-  GtsPoint * p1, * p2, * p3, * p4;
-  gdouble d1, d2, d3, d4;
-
-  g_return_val_if_fail (s1 != NULL && s2 != NULL, FALSE);
-
-  p1 = GTS_POINT (s1->v1); p2 = GTS_POINT (s1->v2);
-  p3 = GTS_POINT (s2->v1); p4 = GTS_POINT (s2->v2);
-  d1 = gts_point_orientation (p1, p2, p3);
-  d2 = gts_point_orientation (p1, p2, p4);
-  if ((d1 > 0.0 && d2 > 0.0) ||
-      (d1 < 0.0 && d2 < 0.0))
-    return GTS_OUT;
-  d3 = gts_point_orientation (p3, p4, p1);
-  d4 = gts_point_orientation (p3, p4, p2);
-  if ((d3 > 0.0 && d4 > 0.0) ||
-      (d3 < 0.0 && d4 < 0.0))
-    return GTS_OUT;
-  if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0 || d4 == 0.0)
-    return GTS_ON;
-  return GTS_IN;
-}
-
-/**
- * gts_segment_midvertex:
- * @s: a #GtsSegment.
- * @klass: a #GtsVertexClass to be used for the new vertex.
- *
- * Returns: a new #GtsVertex, midvertex of @s.
- */
-GtsVertex * gts_segment_midvertex (GtsSegment * s, GtsVertexClass * klass)
-{
-  GtsPoint * p1, * p2;
-
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (klass != NULL, NULL);
-
-  p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2);
-  return gts_vertex_new (klass,
-			 (p1->x + p2->x)/2., 
-			 (p1->y + p2->y)/2.,
-			 (p1->z + p2->z)/2.);
-}
-
-/**
- * gts_segments_from_vertices:
- * @vertices: a list of #GtsVertex.
- * 
- * Returns: a list of unique #GtsSegment which have one of their vertices in 
- * @vertices.
- */
-GSList * gts_segments_from_vertices (GSList * vertices)
-{
-  GHashTable * hash;
-  GSList * segments = NULL, * i;
-
-  hash = g_hash_table_new (NULL, NULL);
-  i = vertices;
-  while (i) {
-    GSList * j = GTS_VERTEX (i->data)->segments;
-    while (j) {
-      GtsSegment * s = j->data;
-      if (g_hash_table_lookup (hash, s) == NULL) {
-	segments = g_slist_prepend (segments, s);
-	g_hash_table_insert (hash, s, i);
-      }
-      j = j->next;
-    }
-    i = i->next;
-  }
-  g_hash_table_destroy (hash);
-  return segments;
-}
-
-/**
- * gts_segment_is_ok:
- * @s: a #GtsSegment.
- * 
- * Returns: %TRUE if @s is not degenerate (i.e. @s->v1 != @s->v2) and not 
- * duplicate, %FALSE otherwise.
- */
-gboolean gts_segment_is_ok (GtsSegment * s)
-{
-  g_return_val_if_fail (s != NULL, FALSE);
-  g_return_val_if_fail (s->v1 != s->v2, FALSE);
-  g_return_val_if_fail (!gts_segment_is_duplicate (s), FALSE);
-  g_return_val_if_fail (GTS_OBJECT (s)->reserved == NULL, FALSE);
-  return TRUE;
-}
diff --git a/src_3rd/gts/split.c b/src_3rd/gts/split.c
deleted file mode 100644
index 43fea3a..0000000
--- a/src_3rd/gts/split.c
+++ /dev/null
@@ -1,1840 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include "gts.h"
-
-#define DYNAMIC_SPLIT
-#define NEW
-
-/* #define DEBUG
-   #define DEBUG_HEXPAND
-   #define DEBUG_EXPAND */
-
-struct _GtsSplitCFace {
-  GtsFace * f;
-  GtsTriangle ** a1, ** a2;
-};
-
-typedef struct _CFace      CFace;
-typedef struct _CFaceClass CFaceClass;
-
-struct _CFace {
-  GtsObject object; 
-
-  GtsSplit * parent_split;
-  GtsTriangle * t;
-  guint flags;
-};
-/* the size of the CFace structure must be smaller or equal to the size
-   of the GtsFace structure as both structures use the same memory location */
-
-struct _CFaceClass {
-  GtsObjectClass parent_class;
-};
-
-#define IS_CFACE(obj) (gts_object_is_from_class (obj, cface_class ()))
-#define CFACE(obj)    ((CFace *) obj)
-#define CFACE_ORIENTATION(cf) ((cf)->flags & 0x1)
-#define CFACE_ORIENTATION_DIRECT(cf) ((cf)->flags |= 0x1)
-#define CFACE_VVS(cf)                ((cf)->flags & 0x2)
-#define CFACE_VVS_DIRECT(cf)         ((cf)->flags |= 0x2)
-#define CFACE_E1                     0x4
-#define CFACE_E2                     0x8
-#define CFACE_KEEP_VVS               0x10
-
-#define ROTATE_ORIENT(e, e1, e2, e3)  { if (e1 == e) { e1 = e2; e2 = e3; }\
-                                 else if (e2 == e) { e2 = e1; e1 = e3; }\
-                                 else g_assert (e3 == e); }
-#define SEGMENT_USE_VERTEX(s, v) ((s)->v1 == v || (s)->v2 == v)
-#define TRIANGLE_REPLACE_EDGE(t, e, with) { if ((t)->e1 == e)\
-					      (t)->e1 = with;\
-					    else if ((t)->e2 == e)\
-					      (t)->e2 = with;\
-					    else {\
-					      g_assert ((t)->e3 == e);\
-					      (t)->e3 = with;\
-					    }\
-                                          }
-
-#define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\
-				  gts_eheap_insert (h, e))
-#define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\
-				   GTS_OBJECT (e)->reserved = NULL)
-
-static GtsObjectClass * cface_class (void)
-{
-  static GtsObjectClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo cface_info = {
-      "GtsCFace",
-      sizeof (CFace),
-      sizeof (CFaceClass),
-      (GtsObjectClassInitFunc) NULL,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), &cface_info);
-    g_assert (sizeof (CFace) <= sizeof (GtsFace));
-  }
-
-  return klass;
-}
-
-/* Replace @e with @with for all the triangles using @e but @f.
-   Destroys @e and removes it from @heap (if not %NULL). 
-   Returns a triangle using e different from f or %NULL. */
-static GtsTriangle * replace_edge_collapse (GtsEdge * e, 
-					    GtsEdge * with, 
-					    CFace * cf,
-					    GtsEHeap * heap
-#ifdef DYNAMIC_SPLIT
-					    , GtsTriangle *** a1
-#endif
-#ifdef NEW
-					    , guint edge_flag
-#endif
-					    )
-{
-  GSList * i;
-  GtsTriangle * rt = NULL;
-#ifdef DYNAMIC_SPLIT
-  guint size;
-  GtsTriangle ** a;
-#endif
-
-#ifdef NEW
-  i = e->triangles;
-  e->triangles = NULL;
-  size = g_slist_length (i)*sizeof (GtsTriangle *);
-  *a1 = a = g_malloc (size > 0 ? size : sizeof (GtsTriangle *));
-  while (i) {
-    GtsTriangle * t = i->data;
-    GSList * next = i->next;
-    if (t != ((GtsTriangle *) cf)) {
-      if (IS_CFACE (t)) {
-	i->next = e->triangles;
-	e->triangles = i;
-	/* set the edge given by edge_flag (CFACE_E1 or CFACE_E2) */
-	GTS_OBJECT (t)->reserved = GUINT_TO_POINTER (edge_flag);
-	cf->flags |= CFACE_KEEP_VVS;
-      }
-      else {
-	TRIANGLE_REPLACE_EDGE (t, e, with);
-	i->next = with->triangles;
-	with->triangles = i;
-	rt = t;
-	*(a++) = t;
-      }
-    }
-    else
-      g_slist_free_1 (i);
-    i = next;
-  }
-  *a = NULL;
-  if (!e->triangles) {
-    if (heap)
-      HEAP_REMOVE_OBJECT (heap, e);
-    gts_object_destroy (GTS_OBJECT (e));
-  }
-#else /* not NEW */
-  i = e->triangles;
-#ifdef DYNAMIC_SPLIT
-  size = g_slist_length (i)*sizeof (GtsTriangle *);
-  *a1 = a = g_malloc (size > 0 ? size : sizeof (GtsTriangle *));
-#endif
-  while (i) {
-    GtsTriangle * t = i->data;
-    GSList * next = i->next;
-    if (t != ((GtsTriangle *) cf)) {
-      TRIANGLE_REPLACE_EDGE (t, e, with);
-      i->next = with->triangles;
-      with->triangles = i;
-      rt = t;
-#ifdef DYNAMIC_SPLIT
-      *(a++) = t;
-#endif
-    }
-    else
-      g_slist_free_1 (i);
-    i = next;
-  }
-#ifdef DYNAMIC_SPLIT
-  *a = NULL;
-#endif
-  if (heap)
-    HEAP_REMOVE_OBJECT (heap, e);
-  e->triangles = NULL;
-  gts_object_destroy (GTS_OBJECT (e));
-#endif /* NEW */
-
-  return rt;
-}
-
-static CFace * cface_new (GtsFace * f,
-			  GtsEdge * e,
-			  GtsVertex * v1, 
-			  GtsVertex * v2,
-			  GtsSplit * vs,
-			  GtsEHeap * heap,
-			  GtsEdgeClass * klass
-#ifdef DYNAMIC_SPLIT
-			  , GtsSplitCFace * scf
-#endif
-			  )
-{
-  CFace * cf;
-  GtsVertex * v;
-  GtsEdge * e1, * e2, * e3, * vvs;
-  GSList * i;
-  GtsTriangle * t, * t1 = NULL, * t2 = NULL;
-  guint flags;
-
-  g_return_val_if_fail (f != NULL, NULL);
-#ifndef NEW
-  g_return_val_if_fail (GTS_IS_FACE (f), NULL);
-#endif
-  g_return_val_if_fail (e != NULL, NULL);
-  g_return_val_if_fail (vs != NULL, NULL);
-
-  t = ((GtsTriangle *) f);
-  if (heap)
-    g_return_val_if_fail (!gts_triangle_is_duplicate (t), NULL);
-
-#ifdef NEW
-  /* get CFACE_E1 and CFACE_E2 info */
-  flags = GPOINTER_TO_UINT (GTS_OBJECT (f)->reserved);
-#endif
-  GTS_OBJECT_SET_FLAGS (f, GTS_DESTROYED);
-
-  i = f->surfaces;
-  while (i) {
-    GSList * next = i->next;
-    gts_surface_remove_face (i->data, f);
-    i = next;
-  }
-  g_slist_free (f->surfaces);
-
-  e1 = t->e1; e2 = t->e2; e3 = t->e3;
-  ROTATE_ORIENT (e, e1, e2, e3);
-
-  cf = (CFace *) f;
-#ifndef NEW
-  GTS_OBJECT (cf)->klass = cface_class ();
-#else
-  cf->flags = flags;
-#endif
-  gts_object_init (GTS_OBJECT (cf), cface_class ());
-  cf->parent_split = vs;
-
-  if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) {
-    CFACE_ORIENTATION_DIRECT (cf); /* v1->v2->v */
-    e3 = e1; e1 = e2; e2 = e3;
-  }
-  v = GTS_SEGMENT (e1)->v1 == v1 ?
-    GTS_SEGMENT (e1)->v2 : GTS_SEGMENT (e1)->v1;
-#ifdef NEW
-  if ((cf->flags & CFACE_E1) || (cf->flags & CFACE_E2))
-    g_assert ((vvs = GTS_EDGE (gts_vertices_are_connected (vs->v, v))));
-  else
-#endif
-  vvs = gts_edge_new (klass, v, vs->v);
-
-  t1 = replace_edge_collapse (e1, vvs, cf, heap
-#ifdef DYNAMIC_SPLIT
-			      , &scf->a1
-#endif
-#ifdef NEW
-			      , CFACE_E1
-#endif
-			      );
-  t2 = replace_edge_collapse (e2, vvs, cf, heap
-#ifdef DYNAMIC_SPLIT
-			      , &scf->a2
-#endif
-#ifdef NEW
-			      , CFACE_E2
-#endif
-			      );
-  t = cf->t = t1 ? t1 : t2;
-  g_assert (t);
-
-  /* set up flags necessary to find vvs */
-  if (t->e1 == vvs) e2 = t->e2;
-  else if (t->e2 == vvs) e2 = t->e3;
-  else {
-    g_assert (t->e3 == vvs);
-    e2 = t->e1;
-  }
-  if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), v))
-    CFACE_VVS_DIRECT (cf);
-
-  return cf;
-}
-
-static void find_vvs (GtsVertex * vs,
-		      GtsTriangle * t,
-		      GtsVertex ** v, GtsEdge ** vvs,
-		      gboolean orientation)
-{
-  GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3, * tmp;
-
-  if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), vs)) {
-    tmp = e1; e1 = e2; e2 = e3; e3 = tmp;
-  }
-  else if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e3), vs)) {
-    tmp = e1; e1 = e3; e3 = e2; e2 = tmp;
-  }
-  else
-    g_assert (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), vs));
-  if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), vs) ||
-      !gts_segments_touch (GTS_SEGMENT (e1), GTS_SEGMENT (e2))) {
-    tmp = e1; e1 = e2; e2 = e3; e3 = tmp;
-    g_assert (gts_segments_touch (GTS_SEGMENT (e1), GTS_SEGMENT (e2)));
-  }
-
-  *vvs = orientation ? e1 : e3;
-
-  if (GTS_SEGMENT (*vvs)->v1 != vs) {
-    g_assert (GTS_SEGMENT (*vvs)->v2 == vs);
-    *v = GTS_SEGMENT (*vvs)->v1;
-  }
-  else
-    *v = GTS_SEGMENT (*vvs)->v2;
-}
-
-static void replace_edge_expand (GtsEdge * e, 
-				 GtsEdge * with,
-				 GtsTriangle ** a,
-				 GtsVertex * v)
-{
-  GtsTriangle ** i = a, * t;
-
-  while ((t = *(i++))) {
-#ifdef DEBUG_EXPAND
-    g_assert (!IS_CFACE (t));
-    fprintf (stderr, "replacing %p->%d: e: %p->%d with: %p->%d\n",
-	     t, id (t), e, id (e), with, id (with));
-#endif
-    TRIANGLE_REPLACE_EDGE (t, e, with);
-    with->triangles = g_slist_prepend (with->triangles, t);
-    if (GTS_OBJECT (t)->reserved) {
-      /* apart from the triangles having e as an edge, t is the only
-	 triangle using v */
-      g_assert (GTS_OBJECT (t)->reserved == v);
-      GTS_OBJECT (t)->reserved = NULL;
-    }
-    else
-      GTS_OBJECT (t)->reserved = v;
-  }
-}
-
-static void cface_expand (CFace * cf,
-			  GtsTriangle ** a1,
-			  GtsTriangle ** a2,
-			  GtsEdge * e,
-			  GtsVertex * v1, 
-			  GtsVertex * v2,
-			  GtsVertex * vs,
-			  GtsEdgeClass * klass)
-{
-  GtsVertex * v;
-  GtsEdge * e1, * e2, * vvs;
-  gboolean orientation;
-  guint flags;
-
-  g_return_if_fail (cf != NULL);
-  g_return_if_fail (IS_CFACE (cf));
-  g_return_if_fail (e != NULL);
-  g_return_if_fail (vs != NULL);
-
-  flags = cf->flags;
-  orientation = CFACE_ORIENTATION (cf);
-
-  find_vvs (vs, cf->t, &v, &vvs, CFACE_VVS (cf));
-
-#ifdef NEW
-  if (flags & CFACE_E1)
-    e1 = GTS_EDGE (gts_vertices_are_connected (v1, v));
-  else
-    e1 = gts_edge_new (klass, v, v1);
-  if (flags & CFACE_E2)
-    e2 = GTS_EDGE (gts_vertices_are_connected (v2, v));
-  else
-    e2 = gts_edge_new (klass, v, v2);
-#else
-  e1 = gts_edge_new (v, v1);
-  e2 = gts_edge_new (v, v2);
-#endif
-
-  replace_edge_expand (vvs, e1, a1, v1);
-  replace_edge_expand (vvs, e2, a2, v2);
-
-#ifdef NEW
-  if (!(flags & CFACE_KEEP_VVS)) {
-    g_slist_free (vvs->triangles);
-    vvs->triangles = NULL;
-    gts_object_destroy (GTS_OBJECT (vvs));
-  }
-#else
-  g_slist_free (vvs->triangles);
-  vvs->triangles = NULL;
-  gts_object_destroy (GTS_OBJECT (vvs));
-#endif
-
-  /* gts_face_new : because I am "creating" a face */
-  GTS_OBJECT (cf)->klass = GTS_OBJECT_CLASS (gts_face_class ());
-  gts_object_init (GTS_OBJECT (cf), GTS_OBJECT (cf)->klass);
-  
-  if (orientation)
-    gts_triangle_set (GTS_TRIANGLE (cf), e, e2, e1);
-  else
-    gts_triangle_set (GTS_TRIANGLE (cf), e, e1, e2);
-}
-
-static void split_destroy (GtsObject * object)
-{
-  GtsSplit * vs = GTS_SPLIT (object);
-  guint i = vs->ncf;
-  GtsSplitCFace * cf = vs->cfaces;
-
-  while (i--) {
-    if (IS_CFACE (cf->f))
-      gts_object_destroy (GTS_OBJECT (cf->f));
-    g_free (cf->a1);
-    g_free (cf->a2);
-    cf++;
-  }
-  g_free (vs->cfaces);
-
-  if (!gts_allow_floating_vertices && vs->v && vs->v->segments == NULL)
-    gts_object_destroy (GTS_OBJECT (vs->v));
-
-  (* GTS_OBJECT_CLASS (gts_split_class ())->parent_class->destroy) (object);
-}
-
-static void split_class_init (GtsObjectClass * klass)
-{
-  klass->destroy = split_destroy;
-}
-
-static void split_init (GtsSplit * split)
-{
-  split->v1 = split->v2 = NULL;
-  split->v = NULL;
-  split->cfaces = NULL;
-  split->ncf = 0;
-}
-
-/**
- * gts_split_class:
- *
- * Returns: the #GtsSplitClass.
- */
-GtsSplitClass * gts_split_class (void)
-{
-  static GtsSplitClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo split_info = {
-      "GtsSplit",
-      sizeof (GtsSplit),
-      sizeof (GtsSplitClass),
-      (GtsObjectClassInitFunc) split_class_init,
-      (GtsObjectInitFunc) split_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), 
-				  &split_info);
-  }
-
-  return klass;
-}
-
-#ifdef DEBUG
-static gboolean edge_collapse_is_valid (GtsEdge * e)
-{
-  GSList * i;
-
-  g_return_val_if_fail (e != NULL, FALSE);
-  
-  if (gts_segment_is_duplicate (GTS_SEGMENT (e))) {
-    g_warning ("collapsing duplicate edge");
-    return FALSE;
-  }
-    
-  i = GTS_SEGMENT (e)->v1->segments;
-  while (i) {
-    GtsEdge * e1 = i->data;
-    if (e1 != e && GTS_IS_EDGE (e1)) {
-      GtsEdge * e2 = NULL;
-      GSList * j = GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v1 ? 
-	GTS_SEGMENT (e1)->v2->segments : GTS_SEGMENT (e1)->v1->segments;
-      while (j && !e2) {
-	GtsEdge * e1 = j->data;
-	if (GTS_IS_EDGE (e1) && 
-	    (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v2 || 
-	     GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e)->v2))
-	  e2 = e1;
-	j = j->next;
-      }
-      if (e2 && !gts_triangle_use_edges (e, e1, e2)) {
-	g_warning ("collapsing empty triangle");
-	return FALSE;
-      }
-    }
-    i = i->next;
-  }
-
-  if (gts_edge_is_boundary (e, NULL)) {
-    GtsTriangle * t = e->triangles->data;
-    if (gts_edge_is_boundary (t->e1, NULL) &&
-	gts_edge_is_boundary (t->e2, NULL) &&
-	gts_edge_is_boundary (t->e3, NULL)) {
-      g_warning ("collapsing single triangle");
-      return FALSE;
-    }
-  }
-  else {
-    if (gts_vertex_is_boundary (GTS_SEGMENT (e)->v1, NULL) &&
-	gts_vertex_is_boundary (GTS_SEGMENT (e)->v2, NULL)) {
-      g_warning ("collapsing two sides of a strip");
-      return FALSE;    
-    }
-    if (gts_edge_belongs_to_tetrahedron (e)) {
-      g_warning ("collapsing tetrahedron");
-      return FALSE;
-    }
-  }
-
-  return TRUE;
-}
-#endif /* DEBUG */
-
-/* Not currently used.  May be useful for some debug code */
-#ifdef DEBUG
-static void print_split (GtsSplit * vs, FILE * fptr)
-{
-  guint j;
-  GtsSplitCFace * cf;
-
-  g_return_if_fail (vs != NULL);
-  g_return_if_fail (fptr != NULL);
-
-  fprintf (fptr, "%p: v: %p v1: %p v2: %p ncf: %u cfaces: %p\n",
-	   vs, vs->v, vs->v1, vs->v2, vs->ncf, vs->cfaces);
-  cf = vs->cfaces;
-  j = vs->ncf;
-  while (j--) {
-    fprintf (stderr, "  f: %p a1: %p a2: %p\n",
-	     cf->f, cf->a1, cf->a2);
-    cf++;
-  }
-}
-#endif
-
-/**
- * gts_split_collapse:
- * @vs: a #GtsSplit.
- * @klass: a #GtsEdgeClass.
- * @heap: a #GtsEHeap or %NULL.
- *
- * Collapses the vertex split @vs. Any new edge created during the process will
- * be of class @klass. If heap is not %NULL, the new edges will be inserted
- * into it and the destroyed edges will be removed from it.
- */
-void gts_split_collapse (GtsSplit * vs, 
-			 GtsEdgeClass * klass,
-			 GtsEHeap * heap)
-{
-  GtsEdge * e;
-  GtsVertex * v, * v1, * v2;
-  GSList * i, * end;
-#ifdef DYNAMIC_SPLIT
-  GtsSplitCFace * cf;
-  guint j;
-#endif
-#ifdef DEBUG
-  gboolean invalid = FALSE;
-  static guint ninvalid = 0;
-#endif
-
-  g_return_if_fail (vs != NULL);
-  g_return_if_fail (klass != NULL);
-
-  v = vs->v;
-
-  g_return_if_fail (v->segments == NULL);
-  
-  /* we don't want to destroy vertices */
-  gts_allow_floating_vertices = TRUE;
-
-  v1 = GTS_SPLIT_V1 (vs);
-  v2 = GTS_SPLIT_V2 (vs);
-  g_assert ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2))));
-
-#ifdef DEBUG
-  fprintf (stderr, "collapsing %p: v1: %p v2: %p v: %p\n", vs, v1, v2, v);
-  if (!edge_collapse_is_valid (e)) {
-    char fname[80];
-    FILE * fptr;
-    GSList * triangles, * i;
-
-    g_warning ("invalid edge collapse");
-    invalid = TRUE;
-    sprintf (fname, "invalid.%d", ninvalid);
-    fptr = fopen (fname, "wt");
-    gts_write_segment (GTS_SEGMENT (e), GTS_POINT (v), fptr);
-    triangles = gts_vertex_triangles (v1, NULL);
-    triangles = gts_vertex_triangles (v2, triangles);
-    i = triangles;
-    while (i) {
-      gts_write_triangle (i->data, GTS_POINT (v), fptr);
-      i = i->next;
-    }
-    g_slist_free (triangles);
-    fclose (fptr);
-  }
-#endif
-
-  i = e->triangles;
-#ifdef DYNAMIC_SPLIT
-  cf = vs->cfaces;
-  j = vs->ncf;
-  while (j--) {
-    g_free (cf->a1);
-    g_free (cf->a2);
-    cf++;
-  }
-  g_free (vs->cfaces);
-
-  vs->ncf = g_slist_length (i);
-  g_assert (vs->ncf > 0);
-  cf = vs->cfaces = g_malloc (vs->ncf*sizeof (GtsSplitCFace));
-#endif /* DYNAMIC_SPLIT */
-#ifdef NEW
-  while (i) {
-    cf->f = i->data;
-    g_assert (GTS_IS_FACE (cf->f));
-    GTS_OBJECT (cf->f)->klass = GTS_OBJECT_CLASS (cface_class ());
-    cf++;
-    i = i->next;
-  }
-  i = e->triangles;
-  cf = vs->cfaces;
-  while (i) {
-    cface_new (i->data, e, v1, v2, vs, heap, klass, cf);
-#ifdef DEBUG
-    fprintf (stderr, "cface: %p->%d t: %p->%d a1: ", 
-	     cf->f, id (cf->f), CFACE (cf->f)->t, id (CFACE (cf->f)->t));
-    {
-      GtsTriangle * t, ** a;
-      a = cf->a1;
-      while ((t = *(a++)))
-	fprintf (stderr, "%p->%d ", t, id (t));
-      fprintf (stderr, "a2: ");
-      a = cf->a2;
-      while ((t = *(a++)))
-	fprintf (stderr, "%p->%d ", t, id (t));
-      fprintf (stderr, "\n");
-    }
-#endif
-    cf++;
-    i = i->next;
-  }
-#else /* not NEW */
-  while (i) {
-    cface_new (i->data, e, v1, v2, vs, heap
-#ifdef DYNAMIC_SPLIT
-	       , cf
-#endif /* DYNAMIC_SPLIT */
-	       );
-#ifdef DYNAMIC_SPLIT
-    cf->f = i->data;
-    cf++;
-#endif /* DYNAMIC_SPLIT */
-    i = i->next;
-  }
-#endif /* NEW */
-  g_slist_free (e->triangles);
-  e->triangles = NULL;
-  gts_object_destroy (GTS_OBJECT (e));
-
-  gts_allow_floating_vertices = FALSE;
-
-  end = NULL;
-  i = v1->segments;
-  while (i) {
-    GtsSegment * s = i->data;
-    if (s->v1 == v1)
-      s->v1 = v;
-    else
-      s->v2 = v;
-    end = i;
-    i = i->next;
-  }
-  if (end) {
-    end->next = v->segments;
-    v->segments = v1->segments;
-    v1->segments = NULL;
-  }
-
-  end = NULL;
-  i = v2->segments;
-  while (i) {
-    GtsSegment * s = i->data;
-    if (s->v1 == v2)
-      s->v1 = v;
-    else
-      s->v2 = v;
-    end = i;
-    i = i->next;
-  }
-  if (end) {
-    end->next = v->segments;
-    v->segments = v2->segments;
-    v2->segments = NULL;
-  }
-
-#ifdef DEBUG
-  if (invalid) {
-    char fname[80];
-    FILE * fptr;
-    GSList * triangles, * i;
-    GtsSurface * surface = NULL;
-
-    sprintf (fname, "invalid_after.%d", ninvalid);
-    fptr = fopen (fname, "wt");
-    triangles = gts_vertex_triangles (v, NULL);
-    i = triangles;
-    while (i) {
-      GtsTriangle * t = i->data;
-      fprintf (stderr, "checking %p->%d\n", t, id (t));
-      g_assert (GTS_IS_FACE (t));
-      gts_write_triangle (t, GTS_POINT (v), fptr);
-      surface = GTS_FACE (t)->surfaces->data;
-      if (gts_triangle_is_duplicate (t))
-	fprintf (stderr, "%p->%d is duplicate\n", t, id (t));
-      if (gts_segment_is_duplicate (GTS_SEGMENT (t->e1)))
-	fprintf (stderr, "e1 of %p->%d is duplicate\n", t, id (t));
-      if (gts_segment_is_duplicate (GTS_SEGMENT (t->e2)))
-	fprintf (stderr, "e2 of %p->%d is duplicate\n", t, id (t));
-      if (gts_segment_is_duplicate (GTS_SEGMENT (t->e3)))
-	fprintf (stderr, "e3 of %p->%d is duplicate\n", t, id (t));
-      i = i->next;
-    }
-    fclose (fptr);
-    g_slist_free (triangles);
-#if 0
-    gts_split_expand (vs, surface);
-
-    sprintf (fname, "invalid_after_after.%d", ninvalid);
-    fptr = fopen (fname, "wt");
-    triangles = gts_vertex_triangles (v1, NULL);
-    triangles = gts_vertex_triangles (v2, triangles);
-    i = triangles;
-    while (i) {
-      GtsTriangle * t = i->data;
-      gts_write_triangle (t, GTS_POINT (v), fptr);
-      surface = GTS_FACE (t)->surfaces->data;
-      if (gts_triangle_is_duplicate (t))
-	fprintf (stderr, "%p->%d is duplicate\n", t, id (t));
-      if (gts_segment_is_duplicate (GTS_SEGMENT (t->e1)))
-	fprintf (stderr, "e1 of %p->%d is duplicate\n", t, id (t));
-      if (gts_segment_is_duplicate (GTS_SEGMENT (t->e2)))
-	fprintf (stderr, "e2 of %p->%d is duplicate\n", t, id (t));
-      if (gts_segment_is_duplicate (GTS_SEGMENT (t->e3)))
-	fprintf (stderr, "e3 of %p->%d is duplicate\n", t, id (t));
-      i = i->next;
-    }
-    fclose (fptr);
-    g_slist_free (triangles);
-
-    exit (1);
-#endif
-    ninvalid++;
-  }
-#endif
-}
-
-/**
- * gts_split_expand:
- * @vs: a #GtsSplit.
- * @s: a #GtsSurface.
- * @klass: a #GtsEdgeClass.
- *
- * Expands the vertex split @vs adding the newly created faces to @s. Any 
- * new edge will be of class @klass.
- */
-void gts_split_expand (GtsSplit * vs, 
-		       GtsSurface * s,
-		       GtsEdgeClass * klass)
-{
-  GSList * i;
-  GtsEdge * e;
-  GtsVertex * v, * v1, * v2;  
-  gboolean changed = FALSE;
-  GtsSplitCFace * cf;
-  guint j;
-  
-  g_return_if_fail (vs != NULL);
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (klass != NULL);
-
-  /* we don't want to destroy vertices */
-  gts_allow_floating_vertices = TRUE;
-
-  v1 = GTS_SPLIT_V1 (vs);
-  v2 = GTS_SPLIT_V2 (vs);
-  v = vs->v;
-#ifdef DEBUG_EXPAND
-  fprintf (stderr, "expanding %p->%d: v1: %p->%d v2: %p->%d v: %p->%d\n",
-	   vs, id (vs), v1, id (v1), v2, id (v2), v, id (v));
-#endif
-  e = gts_edge_new (klass, v1, v2);
-  cf = vs->cfaces;
-  j = vs->ncf;
-  while (j--) {
-    cface_expand (CFACE (cf->f), cf->a1, cf->a2, e, v1, v2, v, klass);
-    gts_surface_add_face (s, cf->f);
-    cf++;
-  }
-
-  gts_allow_floating_vertices = FALSE;
-
-  /* this part is described by figure "expand.fig" */
-  i = v->segments;
-  while (i) {
-    GtsEdge * e1 = i->data;
-    GtsVertex * with = NULL;
-    GSList * j = e1->triangles, * next = i->next;
-    // fprintf (stderr, "e1: %p->%d\n", e1, id (e1));
-    while (j && !with) {
-      with = GTS_OBJECT (j->data)->reserved;
-      j = j->next;
-    }
-    if (with) {
-      j = e1->triangles;
-      while (j) {
-	GtsTriangle * t = j->data;
-	if (GTS_OBJECT (t)->reserved) {
-	  g_assert (GTS_OBJECT (t)->reserved == with);
-	  GTS_OBJECT (t)->reserved = NULL;
-	}
-	else
-	  GTS_OBJECT (t)->reserved = with;
-	j = j->next;
-      }
-      if (GTS_SEGMENT (e1)->v1 == v)
-	GTS_SEGMENT (e1)->v1 = with;
-      else
-	GTS_SEGMENT (e1)->v2 = with;
-
-      v->segments = g_slist_remove_link (v->segments, i);
-      i->next = with->segments;
-      with->segments = i;
-      changed = TRUE;
-    }
-    if (next)
-      i = next;
-    else {
-      /* check for infinite loop (the crossed out case in 
-	 figure "expand.fig") */
-      g_assert (changed);
-      changed = FALSE;
-      i = v->segments;
-    }
-  }
-}
-
-#ifndef DYNAMIC_SPLIT
-static void cface_neighbors (GtsSplitCFace * cf,
-			     GtsEdge * e,
-			     GtsVertex * v1,
-			     GtsVertex * v2)
-{
-  GtsTriangle * t = GTS_TRIANGLE (cf->f), ** a;
-  GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3;
-  GSList * i;
-  guint size;
-
-  ROTATE_ORIENT (e, e1, e2, e3);
-  if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) {
-    e3 = e1; e1 = e2; e2 = e3;
-  }
-  
-  i = e1->triangles;
-  size = g_slist_length (i)*sizeof (GtsTriangle *);
-  a = cf->a1 = g_malloc (size > 0 ? size : sizeof (GtsTriangle *));
-  while (i) {
-    if (i->data != t)
-      *(a++) = i->data;
-    i = i->next;
-  }
-  *a = NULL;
-
-  i = e2->triangles;
-  size = g_slist_length (i)*sizeof (GtsTriangle *);
-  a = cf->a2 = g_malloc (size > 0 ? size : sizeof (GtsTriangle *));
-  while (i) {
-    if (i->data != t)
-      *(a++) = i->data;
-    i = i->next;
-  }
-  *a = NULL;
-}
-#endif /*ifndef DYNAMIC_SPLIT */
-
-/**
- * gts_split_new:
- * @klass: a #GtsSplitClass.
- * @v: a #GtsVertex.
- * @o1: either a #GtsVertex or a #GtsSplit.
- * @o2: either a #GtsVertex or a #GtsSplit.
- *
- * Creates a new #GtsSplit which would collapse @o1 and @o2 into @v. The 
- * collapse itself is not performed.
- *
- * Returns: the new #GtsSplit.
- */
-GtsSplit * gts_split_new (GtsSplitClass * klass,
-			  GtsVertex * v,
-			  GtsObject * o1,
-			  GtsObject * o2)
-{
-  GtsSplit * vs;
-#ifndef DYNAMIC_SPLIT
-  GtsVertex * v1, * v2;
-  GtsEdge * e;
-  GSList * i;
-  GtsSplitCFace * cf;
-#endif
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (v != NULL, NULL);
-  g_return_val_if_fail (GTS_IS_SPLIT (o1) || GTS_IS_VERTEX (o1), NULL);
-  g_return_val_if_fail (GTS_IS_SPLIT (o2) || GTS_IS_VERTEX (o2), NULL);
-
-  vs = GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  vs->v = v;
-  vs->v1 = o1;
-  vs->v2 = o2;
-#ifdef DYNAMIC_SPLIT
-  vs->ncf = 0;
-  vs->cfaces = NULL;
-#else
-  v1 = GTS_SPLIT_V1 (vs);
-  v2 = GTS_SPLIT_V2 (vs);
-  g_assert ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2))));
-  i = e->triangles;
-  vs->ncf = g_slist_length (i);
-  g_assert (vs->ncf > 0);
-  cf = vs->cfaces = g_malloc (vs->ncf*sizeof (GtsSplitCFace));
-  while (i) {
-    cf->f = i->data;
-    cface_neighbors (cf, e, v1, v2);
-    i = i->next;
-    cf++;
-  }
-#endif
-  
-  return vs;
-}
-
-static gboolean 
-split_traverse_pre_order (GtsSplit *           vs,
-			  GtsSplitTraverseFunc func,
-			  gpointer	       data)
-{
-  if (func (vs, data))
-    return TRUE;
-  if (GTS_IS_SPLIT (vs->v1) &&
-      split_traverse_pre_order (GTS_SPLIT (vs->v1), func, data))
-    return TRUE;
-  if (GTS_IS_SPLIT (vs->v2) &&
-      split_traverse_pre_order (GTS_SPLIT (vs->v2), func, data))
-    return TRUE;
-  return FALSE;
-}
-
-static gboolean 
-split_depth_traverse_pre_order (GtsSplit *             vs,
-				guint                  depth,
-				GtsSplitTraverseFunc   func,
-				gpointer	       data)
-{
-  if (func (vs, data))
-      return TRUE;
-    
-  depth--;
-  if (!depth)
-    return FALSE;
-
-  if (GTS_IS_SPLIT (vs->v1) &&
-      split_depth_traverse_pre_order (GTS_SPLIT (vs->v1), depth, func, data))
-    return TRUE;
-  if (GTS_IS_SPLIT (vs->v2) &&
-      split_depth_traverse_pre_order (GTS_SPLIT (vs->v2), depth, func, data))
-    return TRUE;
-  return FALSE;
-}
-
-static gboolean 
-split_traverse_post_order (GtsSplit *           vs,
-			   GtsSplitTraverseFunc func,
-			   gpointer	        data)
-{
-  if (GTS_IS_SPLIT (vs->v1) &&
-      split_traverse_post_order (GTS_SPLIT (vs->v1), func, data))
-    return TRUE;
-  if (GTS_IS_SPLIT (vs->v2) &&
-      split_traverse_post_order (GTS_SPLIT (vs->v2), func, data))
-    return TRUE;
-  if (func (vs, data))
-    return TRUE;
-  return FALSE;
-}
-
-static gboolean
-split_depth_traverse_post_order (GtsSplit *           vs,
-				 guint                depth,
-				 GtsSplitTraverseFunc func,
-				 gpointer	      data)
-{
-  depth--;
-  if (depth) {
-    if (GTS_IS_SPLIT (vs->v1) &&
-	split_depth_traverse_post_order (GTS_SPLIT (vs->v1), 
-					 depth, func, data))
-      return TRUE;
-    if (GTS_IS_SPLIT (vs->v2) &&
-	split_depth_traverse_post_order (GTS_SPLIT (vs->v2),
-					 depth, func, data))
-      return TRUE;
-  }
-  if (func (vs, data))
-    return TRUE;
-  return FALSE;
-}
-
-/**
- * gts_split_traverse:
- * @root: the #GtsSplit to start the traversal from.
- * @order: the order in which nodes are visited - G_PRE_ORDER or G_POST_ORDER.
- * @depth: the maximum depth of the traversal. Nodes below this depth
- * will not be visited. If depth is -1 all nodes in the tree are
- * visited. If depth is 1, only the root is visited. If depth is 2,
- * the root and its children are visited. And so on.
- * @func: the function to call for each visited #GtsHSplit.
- * @data: user data to pass to the function.
- *
- * Traverses the #GtsSplit tree having @root as root. Calls @func for each
- * #GtsSplit of the tree in the order specified by @order. If order is set
- * to G_PRE_ORDER @func is called for the #GtsSplit then its children, if order
- * is set to G_POST_ORDER @func is called for the children and then for the
- * #GtsSplit.
- */
-void gts_split_traverse (GtsSplit *           root,
-			 GTraverseType        order,
-			 gint                 depth,
-			 GtsSplitTraverseFunc func,
-			 gpointer             data)
-{
-  g_return_if_fail (root != NULL);
-  g_return_if_fail (func != NULL);
-  g_return_if_fail (order < G_LEVEL_ORDER);
-  g_return_if_fail (depth == -1 || depth > 0);
-
-  switch (order) {
-  case G_PRE_ORDER:
-    if (depth < 0)
-      split_traverse_pre_order (root, func, data);
-    else
-      split_depth_traverse_pre_order (root, depth, func, data);
-    break;
-  case G_POST_ORDER:
-    if (depth < 0)
-      split_traverse_post_order (root, func, data);
-    else
-      split_depth_traverse_post_order (root, depth, func, data);
-    break;
-  default:
-    g_assert_not_reached ();
-  }
-}
-
-/**
- * gts_split_height:
- * @root: a #GtsSplit.
- *
- * Returns: the maximum height of the vertex split tree having @root as root.
- */
-guint gts_split_height (GtsSplit * root)
-{
-  guint height = 0, tmp_height;
-
-  g_return_val_if_fail (root != NULL, 0);
-
-  if (GTS_IS_SPLIT (root->v1)) {
-    tmp_height = gts_split_height (GTS_SPLIT (root->v1));
-    if (tmp_height > height)
-      height = tmp_height;
-  }
-  if (GTS_IS_SPLIT (root->v2)) {
-    tmp_height = gts_split_height (GTS_SPLIT (root->v2));
-    if (tmp_height > height)
-      height = tmp_height;
-  }
-
-  return height + 1;
-}
-
-#ifndef DYNAMIC_SPLIT
-static gboolean list_array_are_identical (GSList * list, 
-					  gpointer * array,
-					  gpointer excluded)
-{
-  while (list) {
-    gpointer data = list->data;
-    if (data != excluded) {
-      gboolean found = FALSE;
-      gpointer * a = array;
-      
-      while (!found && *a)
-	if (*(a++) == data)
-	  found = TRUE;
-      if (!found)
-	return FALSE;
-    }
-    list = list->next;
-  }
-  return TRUE;
-}
-#endif /* ifndef DYNAMIC_SPLIT */
-
-#ifndef NEW
-gboolean gts_split_is_collapsable (GtsSplit * vs)
-{
-  guint i;
-  GtsSplitCFace * cf;
-  GtsVertex * v1, * v2;
-  GtsEdge * e;
-
-  g_return_val_if_fail (vs != NULL, FALSE);
-
-  v1 = GTS_SPLIT_V1 (vs);
-  v2 = GTS_SPLIT_V2 (vs);
-  g_return_val_if_fail ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2))),
-			FALSE);
-
-#ifdef DYNAMIC_SPLIT
-  if (!gts_edge_collapse_is_valid (e))
-    return FALSE;
-#else 
-  i = vs->ncf;
-  cf = vs->cfaces;
-  while (i--) {
-    GtsTriangle * t = GTS_TRIANGLE (cf->f);
-    GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3;
-
-    ROTATE_ORIENT (e, e1, e2, e3);
-    if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) {
-      e3 = e1; e1 = e2; e2 = e3;
-    }
-
-    if (!list_array_are_identical (e1->triangles, (gpointer *) cf->a1, t))
-      return FALSE;
-    if (!list_array_are_identical (e2->triangles, (gpointer *) cf->a2, t))
-      return FALSE;
-    
-    cf++;
-  }
-#endif
-  return TRUE;
-}
-#endif /* not NEW */
-
-#ifdef DEBUG_HEXPAND
-static guint expand_level = 0;
-
-static void expand_indent (FILE * fptr)
-{
-  guint i = expand_level;
-  while (i--)
-    fputc (' ', fptr);
-}
-#endif
-
-/**
- * gts_hsplit_force_expand:
- * @hs: a #GtsHSplit.
- * @hsurface: a #GtsHSurface.
- *
- * Forces the expansion of @hs by first expanding all its dependencies not
- * already expanded.
- */
-void gts_hsplit_force_expand (GtsHSplit * hs,
-			      GtsHSurface * hsurface)
-{
-  guint i;
-  GtsSplitCFace * cf;
-
-  g_return_if_fail (hs != NULL);
-  g_return_if_fail (hsurface != NULL);
-  g_return_if_fail (hs->nchild == 0);
-
-#ifdef DEBUG_HEXPAND
-  expand_level += 2;
-#endif
-
-  if (hs->parent && hs->parent->nchild == 0) {
-#ifdef DEBUG_HEXPAND
-    expand_indent (stderr); 
-    fprintf (stderr, "expand parent %p\n", hs->parent);
-#endif
-    gts_hsplit_force_expand (hs->parent, hsurface);
-  }
-
-  i = GTS_SPLIT (hs)->ncf;
-  cf = GTS_SPLIT (hs)->cfaces;
-  while (i--) {
-    GtsTriangle ** j, * t;
-
-    j = cf->a1;
-    while ((t = *(j++)))
-      if (IS_CFACE (t)) {
-#ifdef DEBUG_HEXPAND
-	expand_indent (stderr); 
-	fprintf (stderr, "expand a1: cf->f: %p t: %p parent_split: %p\n", 
-		 cf->f,
-		 t,
-		 GTS_HSPLIT (CFACE (t)->parent_split));
-#endif
-	gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t)->parent_split),
-				 hsurface);
-#ifdef DEBUG_HEXPAND
-	g_assert (!IS_CFACE (t));
-#endif
-      }
-    j = cf->a2;
-    while ((t = *(j++)))
-      if (IS_CFACE (t)) {
-#ifdef DEBUG_HEXPAND
-	expand_indent (stderr); 
-	fprintf (stderr, "expand a2: cf->f: %p t: %p parent_split: %p\n", 
-		 cf->f,
-		 t,
-		 GTS_HSPLIT (CFACE (t)->parent_split));
-#endif
-	gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t)->parent_split),
-				 hsurface);
-      }
-    cf++;
-  }
-
-  gts_hsplit_expand (hs, hsurface);
-
-#ifdef DEBUG_HEXPAND
-  expand_level -= 2; 
-  expand_indent (stderr); 
-  fprintf (stderr, "%p expanded\n", hs);
-#endif
-}
-
-static void index_object (GtsObject * o, guint * n)
-{
-  o->reserved = GUINT_TO_POINTER ((*n)++);
-}
-
-static void index_face (GtsFace * f, gpointer * data)
-{
-  guint * nf = data[1];
-
-  g_hash_table_insert (data[0], f, GUINT_TO_POINTER ((*nf)++));
-}
-
-/**
- * gts_psurface_write:
- * @ps: a #GtsPSurface.
- * @fptr: a file pointer.
- *
- * Writes to @fptr a GTS progressive surface description.
- */
-void gts_psurface_write (GtsPSurface * ps, FILE * fptr)
-{
-  guint nv = 1;
-  guint nf = 1;
-  GHashTable * hash;
-  gpointer data[2];
-
-  g_return_if_fail (ps != NULL);
-  g_return_if_fail (fptr != NULL);
-  g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps));
-
-  while (gts_psurface_remove_vertex (ps))
-    ;
-
-  GTS_POINT_CLASS (ps->s->vertex_class)->binary = FALSE;
-  gts_surface_write (ps->s, fptr);
-  
-  gts_surface_foreach_vertex (ps->s, (GtsFunc) index_object, &nv);
-  hash = g_hash_table_new (NULL, NULL);
-  data[0] = hash;
-  data[1] = &nf;
-  gts_surface_foreach_face (ps->s, (GtsFunc) index_face, data);
-
-  fprintf (fptr, "%u\n", ps->split->len);
-  while (ps->pos) {
-    GtsSplit * vs = g_ptr_array_index (ps->split, --ps->pos);
-    GtsSplitCFace * scf = vs->cfaces;
-    GtsVertex * v1, * v2;
-    guint i = vs->ncf;
-
-    fprintf (fptr, "%u %u",
-	     GPOINTER_TO_UINT (GTS_OBJECT (vs->v)->reserved),
-	     vs->ncf);
-    if (GTS_OBJECT (vs)->klass->write)
-      (*GTS_OBJECT (vs)->klass->write) (GTS_OBJECT (vs), fptr);
-    fputc ('\n', fptr);
-
-    v1 = GTS_IS_SPLIT (vs->v1) ? GTS_SPLIT (vs->v1)->v : GTS_VERTEX (vs->v1);
-    GTS_OBJECT (v1)->reserved = GUINT_TO_POINTER (nv++);
-    v2 = GTS_IS_SPLIT (vs->v2) ? GTS_SPLIT (vs->v2)->v : GTS_VERTEX (vs->v2);
-    GTS_OBJECT (v2)->reserved = GUINT_TO_POINTER (nv++);
-
-    (*GTS_OBJECT (v1)->klass->write) (GTS_OBJECT (v1), fptr);
-    fputc ('\n', fptr);
-
-    (*GTS_OBJECT (v2)->klass->write) (GTS_OBJECT (v2), fptr);
-    fputc ('\n', fptr);
-    
-    while (i--) {
-      CFace * cf = CFACE (scf->f);
-      GtsTriangle ** a, * t;
-
-      fprintf (fptr, "%u %u",
-	       GPOINTER_TO_UINT (g_hash_table_lookup (hash, cf->t)),
-	       cf->flags);
-      if (GTS_OBJECT_CLASS (ps->s->face_class)->write)
-	(*GTS_OBJECT_CLASS (ps->s->face_class)->write) (GTS_OBJECT (cf), fptr);
-      fputc ('\n', fptr);
-
-      a = scf->a1;
-      while ((t = *(a++)))
-	fprintf (fptr, "%u ",
-		 GPOINTER_TO_UINT (g_hash_table_lookup (hash, t)));
-      fprintf (fptr, "\n");
-
-      a = scf->a2;
-      while ((t = *(a++)))
-	fprintf (fptr, "%u ",
-		 GPOINTER_TO_UINT (g_hash_table_lookup (hash, t)));
-      fprintf (fptr, "\n");
-
-      g_hash_table_insert (hash, cf, GUINT_TO_POINTER (nf++));
-
-      scf++;
-    }
-
-    gts_split_expand (vs, ps->s, ps->s->edge_class);
-  }
-
-  gts_surface_foreach_vertex (ps->s, 
-			      (GtsFunc) gts_object_reset_reserved, NULL);
-  g_hash_table_destroy (hash);
-}
-
-static guint surface_read (GtsSurface * surface, 
-			   GtsFile * f,
-			   GPtrArray * vertices,
-			   GPtrArray * faces)
-{
-  GtsEdge ** edges;
-  guint n, nv, ne, nf;
-
-  g_return_val_if_fail (surface != NULL, 1);
-  g_return_val_if_fail (f != NULL, 1);
-  
-  if (f->type != GTS_INT) {
-    gts_file_error (f, "expecting an integer (number of vertices)");
-    return f->line;
-  }
-  nv = atoi (f->token->str);
-
-  gts_file_next_token (f);
-  if (f->type != GTS_INT) {
-    gts_file_error (f, "expecting an integer (number of edges)");
-    return f->line;
-  }
-  ne = atoi (f->token->str);
-
-  gts_file_next_token (f);
-  if (f->type != GTS_INT) {
-    gts_file_error (f, "expecting an integer (number of faces)");
-    return f->line;
-  }
-  nf = atoi (f->token->str);
-
-  gts_file_next_token (f);
-  if (f->type == GTS_STRING) {
-    if (f->type != GTS_STRING) {
-      gts_file_error (f, "expecting a string (GtsSurfaceClass)");
-      return f->line;
-    }
-    gts_file_next_token (f);
-    if (f->type != GTS_STRING) {
-      gts_file_error (f, "expecting a string (GtsFaceClass)");
-      return f->line;
-    }
-    gts_file_next_token (f);
-    if (f->type != GTS_STRING) {
-      gts_file_error (f, "expecting a string (GtsEdgeClass)");
-      return f->line;
-    }
-    gts_file_next_token (f);
-    if (f->type != GTS_STRING) {
-      gts_file_error (f, "expecting a string (GtsVertexClass)");
-      return f->line;
-    }
-    if (!strcmp (f->token->str, "GtsVertexBinary"))
-      GTS_POINT_CLASS (surface->vertex_class)->binary = TRUE;
-    else
-      gts_file_first_token_after (f, '\n');
-  }
-  else
-    gts_file_first_token_after (f, '\n');
-
-  g_ptr_array_set_size (vertices, nv);
-  g_ptr_array_set_size (faces, nf);
-  /* allocate nv + 1 just in case nv == 0 */
-  edges = g_malloc ((ne + 1)*sizeof (GtsEdge *));
-  
-  n = 0;
-  while (n < nv && f->type != GTS_ERROR) {
-    GtsObject * new_vertex =
-      gts_object_new (GTS_OBJECT_CLASS (surface->vertex_class));
-
-    (* GTS_OBJECT_CLASS (surface->vertex_class)->read) (&new_vertex, f);
-    if (f->type != GTS_ERROR) {
-      if (!GTS_POINT_CLASS (surface->vertex_class)->binary)
-	gts_file_first_token_after (f, '\n');
-      g_ptr_array_index (vertices, n++) = new_vertex;
-    }
-    else
-      gts_object_destroy (new_vertex);
-  }
-  if (f->type == GTS_ERROR)
-    nv = n;
-  if (GTS_POINT_CLASS (surface->vertex_class)->binary)
-    gts_file_first_token_after (f, '\n');
-
-  n = 0;
-  while (n < ne && f->type != GTS_ERROR) {
-    guint p1, p2;
-
-    if (f->type != GTS_INT)
-      gts_file_error (f, "expecting an integer (first vertex index)");
-    else {
-      p1 = atoi (f->token->str);
-      if (p1 == 0 || p1 > nv)
-	gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", 
-			p1, nv);
-      else {
-	gts_file_next_token (f);
-	if (f->type != GTS_INT)
-	  gts_file_error (f, "expecting an integer (second vertex index)");
-	else {
-	  p2 = atoi (f->token->str);
-	  if (p2 == 0 || p2 > nv)
-	    gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", 
-			    p2, nv);
-	  else {
-	    GtsEdge * new_edge =
-	      gts_edge_new (surface->edge_class,
-			    g_ptr_array_index (vertices, p1 - 1),
-			    g_ptr_array_index (vertices, p2 - 1));
-
-	    gts_file_next_token (f);
-	    if (f->type != '\n')
-	      if (GTS_OBJECT_CLASS (surface->edge_class)->read)
-		(*GTS_OBJECT_CLASS (surface->edge_class)->read)
-		  ((GtsObject **) &new_edge, f);
-	    gts_file_first_token_after (f, '\n');
-	    edges[n++] = new_edge;
-	  }
-	}
-      }
-    }
-  }
-  if (f->type == GTS_ERROR)
-    ne = n;
-
-  n = 0;
-  while (n < nf && f->type != GTS_ERROR) {
-    guint s1, s2, s3;
-
-    if (f->type != GTS_INT)
-      gts_file_error (f, "expecting an integer (first edge index)");
-    else {
-      s1 = atoi (f->token->str);
-      if (s1 == 0 || s1 > ne)
-	gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
-			s1, ne);
-      else {
-	gts_file_next_token (f);
-	if (f->type != GTS_INT)
-	  gts_file_error (f, "expecting an integer (second edge index)");
-	else {
-	  s2 = atoi (f->token->str);
-	  if (s2 == 0 || s2 > ne)
-	    gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
-			    s2, ne);
-	  else {
-	    gts_file_next_token (f);
-	    if (f->type != GTS_INT)
-	      gts_file_error (f, "expecting an integer (third edge index)");
-	    else {
-	      s3 = atoi (f->token->str);
-	      if (s3 == 0 || s3 > ne)
-		gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
-				s3, ne);
-	      else {
-		GtsFace * new_face = gts_face_new (surface->face_class,
-						   edges[s1 - 1],
-						   edges[s2 - 1],
-						   edges[s3 - 1]);
-
-		gts_file_next_token (f);
-		if (f->type != '\n')
-		  if (GTS_OBJECT_CLASS (surface->face_class)->read)
-		    (*GTS_OBJECT_CLASS (surface->face_class)->read)
-		      ((GtsObject **) &new_face, f);
-		gts_file_first_token_after (f, '\n');
-		gts_surface_add_face (surface, new_face);
-		g_ptr_array_index (faces, n++) = new_face;
-	      }
-	    }
-	  }
-	}
-      }
-    }
-  }
-
-  g_free (edges);
-
-  if (f->type == GTS_ERROR) {
-    gts_allow_floating_vertices = TRUE;
-    while (nv)
-      gts_object_destroy (GTS_OBJECT (g_ptr_array_index (vertices, nv-- - 1)));
-    gts_allow_floating_vertices = FALSE;    
-    return f->line;
-  }
-
-  return 0;
-}
-
-/**
- * gts_psurface_open:
- * @klass: a #GtsPSurfaceClass.
- * @s: a #GtsSurface.
- * @split_class: a #GtsSplitClass to use for the #GtsSplit.
- * @f: a #GtsFile.
- *
- * Creates a new #GtsPSurface prepared for input from the file @f 
- * containing a valid GTS representation of a progressive surface. The initial
- * shape of the progressive surface is loaded into @s.
- * 
- * Before being usable as such this progressive surface must be closed using
- * gts_psurface_close(). While open however, the functions
- * gts_psurface_get_vertex_number(), gts_psurface_min_vertex_number() and
- * gts_psurface_max_vertex_number() can still be used.
- *
- * Returns: a new #GtsPSurface or %NULL if there was a format error while
- * reading the file, in which case @f contains information about the error.
- */
-GtsPSurface * gts_psurface_open (GtsPSurfaceClass * klass,
-				 GtsSurface * s,
-				 GtsSplitClass * split_class,
-				 GtsFile * f)
-{
-  GtsPSurface * ps;
-
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (split_class != NULL, NULL);
-  g_return_val_if_fail (f != NULL, NULL);
-
-  ps = GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  ps->s = s;
-  ps->split_class = split_class;
-
-  ps->vertices = g_ptr_array_new ();
-  ps->faces = g_ptr_array_new ();
-
-  if (surface_read (s, f, ps->vertices, ps->faces)) {
-    ps->s = NULL;
-    gts_object_destroy (GTS_OBJECT (ps));
-    return NULL;
-  }
-
-  ps->min = gts_surface_vertex_number (ps->s);
-  ps->pos = 0;
-
-  if (f->type == GTS_INT) {
-    gint ns = atoi (f->token->str);
-    
-    if (ns > 0) {
-      g_ptr_array_set_size (ps->split, ns);
-      gts_file_first_token_after (f, '\n');
-    }
-  }
-
-  return ps;
-}
-
-/**
- * gts_psurface_read_vertex:
- * @ps: a #GtsPSurface prealably created with gts_psurface_open().
- * @fp: a #GtsFile.
- *
- * Reads in one vertex split operation from @fp and performs the expansion.
- *
- * If an error occurs while reading the file, the @error field of @fp is set.
- *
- * Returns: the newly created #GtsSplit or %NULL if no vertex split could be
- * read from @fp.
- */
-GtsSplit * gts_psurface_read_vertex (GtsPSurface * ps, GtsFile * fp)
-{
-  guint nv, ncf;
-  GtsSplit * vs, * parent;
-  GtsSplitCFace * scf;
-
-  g_return_val_if_fail (ps != NULL, NULL);
-  g_return_val_if_fail (fp != NULL, NULL);
-  g_return_val_if_fail (!GTS_PSURFACE_IS_CLOSED (ps), NULL);
-  
-  if (ps->pos >= ps->split->len)
-    return NULL;
-
-  if (fp->type == GTS_NONE)
-    return NULL;
-  if (fp->type != GTS_INT) {
-    gts_file_error (fp, "expecting an integer (vertex index)");
-    return NULL;
-  }
-  nv = atoi (fp->token->str);
-  if (nv == 0 || nv > ps->vertices->len) {
-    gts_file_error (fp, "vertex index `%d' is out of range `[1,%d]'",
-		    nv, ps->vertices->len);
-    return NULL;
-  }
-
-  gts_file_next_token (fp);
-  if (fp->type != GTS_INT) {
-    gts_file_error (fp, "expecting an integer (ncf)");
-    return NULL;
-  }
-  ncf = atoi (fp->token->str);
-  
-  vs = GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (ps->split_class)));
-
-  vs->v = g_ptr_array_index (ps->vertices, nv - 1);
-  vs->v1 = vs->v2 = NULL;
-  vs->cfaces = NULL;
-  vs->ncf = 0;
-
-  gts_file_next_token (fp);
-  if (fp->type != '\n')
-    if (GTS_OBJECT (vs)->klass->read)
-      (* GTS_OBJECT (vs)->klass->read) ((GtsObject **) &vs, fp);
-  gts_file_first_token_after (fp, '\n');
-
-  if (fp->type != GTS_ERROR) {
-    vs->v1 = gts_object_new (GTS_OBJECT_CLASS (ps->s->vertex_class));
-    (* GTS_OBJECT_CLASS (ps->s->vertex_class)->read) (&(vs->v1), fp);
-    if (fp->type != GTS_ERROR) {
-      vs->v1->reserved = vs;
-      g_ptr_array_add (ps->vertices, vs->v1);
-
-      gts_file_first_token_after (fp, '\n');
-      
-      vs->v2 = gts_object_new (GTS_OBJECT_CLASS (ps->s->vertex_class));
-      (*GTS_OBJECT_CLASS (ps->s->vertex_class)->read) (&(vs->v2), fp);
-      if (fp->type != GTS_ERROR) {
-	vs->v2->reserved = vs;
-	g_ptr_array_add (ps->vertices, vs->v2);
-	gts_file_first_token_after (fp, '\n');
-      }
-    }
-  }
-
-  if (fp->type != GTS_ERROR) {
-    scf = vs->cfaces = g_malloc (sizeof (GtsSplitCFace)*ncf);
-    while (fp->type != GTS_ERROR && ncf--) {
-      guint it, flags;
-      GtsFace * f;
-      CFace * cf;
-      GPtrArray * a;
-
-      if (fp->type != GTS_INT)
-	gts_file_error (fp, "expecting an integer (face index)");
-      else {
-	it = atoi (fp->token->str);
-	if (it == 0 || it > ps->faces->len)
-	  gts_file_error (fp, "face index `%d' is out of range `[1,%d]'",
-			  it, ps->faces->len);
-	else {
-	  gts_file_next_token (fp);
-	  if (fp->type != GTS_INT)
-	    gts_file_error (fp, "expecting an integer (flags)");
-	  else {
-	    flags = atoi (fp->token->str);
-	    f = 
-	      GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (ps->s->face_class)));
-
-	    gts_file_next_token (fp);
-	    if (fp->type != '\n')
-	      if (GTS_OBJECT (f)->klass->read)
-		(*GTS_OBJECT (f)->klass->read) ((GtsObject **) &f, fp);
-	    gts_file_first_token_after (fp, '\n');
-	    if (fp->type != GTS_ERROR) {
-	      scf->f = f;
-
-	      cf = (CFace *) f;
-	      GTS_OBJECT (cf)->klass = GTS_OBJECT_CLASS (cface_class ());
-	      cf->parent_split = vs;
-	      cf->t = g_ptr_array_index (ps->faces, it - 1);
-	      cf->flags = flags;
-	  
-	      a = g_ptr_array_new ();
-	      do {
-		if (fp->type != GTS_INT)
-		  gts_file_error (fp, "expecting an integer (face index)");
-		else {
-		  it = atoi (fp->token->str);
-		  if (it > ps->faces->len)
-		    gts_file_error (fp, 
-				    "face index `%d' is out of range `[1,%d]'",
-				    it, ps->faces->len);
-		  else {
-		    g_ptr_array_add (a, g_ptr_array_index (ps->faces, 
-							   it - 1));
-		    gts_file_next_token (fp);
-		  }
-		}
-	      } while (fp->type != GTS_ERROR && fp->type != '\n');
-	      gts_file_first_token_after (fp, '\n');
-	      g_ptr_array_add (a, NULL);
-	      scf->a1 = (GtsTriangle **) a->pdata;
-	      g_ptr_array_free (a, FALSE);
-
-	      if (fp->type != GTS_ERROR) {
-		a = g_ptr_array_new ();
-		do {
-		  if (fp->type != GTS_INT)
-		    gts_file_error (fp, "expecting an integer (face index)");
-		  else {
-		    it = atoi (fp->token->str);
-		    if (it > ps->faces->len)
-		      gts_file_error (fp, 
-				   "face index `%d' is out of range `[1,%d]'",
-				      it, ps->faces->len);
-		    else {
-		      g_ptr_array_add (a, g_ptr_array_index (ps->faces, 
-							     it - 1));
-		      gts_file_next_token (fp);
-		    }
-		  }
-		} while (fp->type != GTS_ERROR && fp->type != '\n');
-		gts_file_first_token_after (fp, '\n');
-		g_ptr_array_add (a, NULL);
-		scf->a2 = (GtsTriangle **) a->pdata;
-		g_ptr_array_free (a, FALSE);
-		
-		g_ptr_array_add (ps->faces, f);
-	      
-		vs->ncf++;
-		scf++;
-	      }
-	    }
-	  }
-	}
-      }
-    }
-  }
-
-  if (fp->type != GTS_ERROR) {
-    if ((parent = GTS_OBJECT (vs->v)->reserved)) {
-      GTS_OBJECT (vs->v)->reserved = NULL;
-      if (parent->v1 == GTS_OBJECT (vs->v))
-	parent->v1 = GTS_OBJECT (vs);
-      else {
-	g_assert (parent->v2 == GTS_OBJECT (vs->v));
-	parent->v2 = GTS_OBJECT (vs);
-      }
-    }
-    g_ptr_array_index (ps->split, ps->pos++) = vs;
-    gts_split_expand (vs, ps->s, ps->s->edge_class);
-
-    return vs;
-  }
-
-  if (vs->v1) gts_object_destroy (vs->v1);
-  if (vs->v2) gts_object_destroy (vs->v2);
-  gts_object_destroy (GTS_OBJECT (vs));
-  
-  return NULL;
-}
-
-/**
- * gts_psurface_close:
- * @ps: a #GtsPSurface prealably created with gts_psurface_open().
- *
- * Closes a progressive surface.
- */
-void gts_psurface_close (GtsPSurface * ps)
-{
-  g_return_if_fail (ps != NULL);
-  g_return_if_fail (!GTS_PSURFACE_IS_CLOSED (ps));
-
-  g_ptr_array_free (ps->vertices, TRUE);
-  g_ptr_array_free (ps->faces, TRUE);
-  ps->faces = ps->vertices = NULL;
-  
-  gts_surface_foreach_vertex (ps->s, 
-			      (GtsFunc) gts_object_reset_reserved, NULL);
-  if (ps->pos > 0)
-    g_ptr_array_set_size (ps->split, ps->pos);
-  if (ps->split->len > 1) {
-    guint i, half = ps->split->len/2, n = ps->split->len - 1;
-    
-    for (i = 0; i < half; i++) {
-      gpointer p1 = g_ptr_array_index (ps->split, i);
-      gpointer p2 = g_ptr_array_index (ps->split, n - i);
-      g_ptr_array_index (ps->split, n - i) = p1;
-      g_ptr_array_index (ps->split, i) = p2;
-    }
-  }
-  ps->pos = 0;
-}
diff --git a/src_3rd/gts/stripe.c b/src_3rd/gts/stripe.c
deleted file mode 100644
index 7e98a9c..0000000
--- a/src_3rd/gts/stripe.c
+++ /dev/null
@@ -1,766 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999-2003  Wagner Toledo Correa, St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-#define PRINT_HEAP_ELEMENTS 0
-
-typedef struct {
-  GtsTriangle * t;
-  gboolean used;
-  GSList * neighbors;
-  GtsEHeapPair *pos;
-} tri_data_t;
-
-typedef struct {
-  GHashTable * ht;
-} map_t;
-
-typedef struct {
-  map_t * map;
-  GtsEHeap * heap;
-} heap_t;
-
-static tri_data_t    * tri_data_new (GtsTriangle * t);
-static void            tri_data_destroy (tri_data_t * td);
-static guint           tri_data_num_unused_neighbors2 (const tri_data_t * td,
-						       const map_t * map);
-static GHashTable    * tri_data_unused_neighbors2 (const tri_data_t * td,
-						   const map_t * map);
-
-static map_t         * map_new (GtsSurface * s);
-static void            map_destroy (map_t * map);
-static tri_data_t    * map_lookup (const map_t * map, GtsTriangle * t);
-
-
-static heap_t        * heap_new (GtsSurface * s);
-static void            heap_destroy (heap_t * heap);
-static gboolean        heap_is_empty (const heap_t * heap);
-static GtsTriangle   * heap_top (const heap_t * heap);
-static void            heap_remove (heap_t * heap, GtsTriangle * t);
-
-/* helper functions */
-
-static gboolean vertices_are_unique (GtsVertex * v1,
-				     GtsVertex * v2,
-				     GtsVertex * v3)
-{
-  g_assert (v1 && v2 && v3);
-  return (v1 != v2 && v1 != v3 && v2 != v3);
-}
-
-static gboolean vertex_is_one_of (GtsVertex * v,
-				  GtsVertex * v1,
-				  GtsVertex * v2,
-				  GtsVertex * v3)
-{
-  g_assert (v && v1 && v2 && v3);
-  return v == v1 || v == v2 || v == v3;
-}
-
-static guint num_shared_vertices (GtsVertex * u1,
-				  GtsVertex * u2,
-				  GtsVertex * u3,
-				  GtsVertex * v1,
-				  GtsVertex * v2,
-				  GtsVertex * v3)
-{
-  guint n = 0;
-  
-  g_assert (u1 && u2 && u3);
-  g_assert (v1 && v2 && v3);
-  g_assert (vertices_are_unique (u1, u2, u3));
-  g_assert (vertices_are_unique (v1, v2, v3));
-  
-  if (vertex_is_one_of (v1, u1, u2, u3))
-    n++;
-  if (vertex_is_one_of (v2, u1, u2, u3))
-    n++;
-  if (vertex_is_one_of (v3, u1, u2, u3))
-    n++;
-  return n;
-}
-
-static gboolean vertices_match (GtsVertex * v1,
-				GtsVertex * v2,
-				GtsVertex * v3,
-				GtsVertex ** v4,
-				GtsVertex ** v5,
-				GtsVertex ** v6)
-{
-  guint i;
-
-  g_assert (v4 && v5 && v6);
-  g_assert (*v4 && *v5 && *v6);
-  g_assert (vertices_are_unique (*v4, *v5, *v6));
-  
-  for (i = 0; i < 2; i++) {
-    if ((!v1 || (v1 == *v4)) &&
-	(!v2 || (v2 == *v5)) &&
-	(!v3 || (v3 == *v6)))
-      return TRUE;
-    else {
-      GtsVertex * v7 = * v4;
-
-      *v4 = *v5;
-      *v5 = *v6;
-      *v6 = v7;
-    }
-  }
-  return ((!v1 || (v1 == *v4)) &&
-	  (!v2 || (v2 == *v5)) &&
-	  (!v3 || (v3 == *v6)));
-}
-
-static GtsVertex * non_shared_vertex1 (GtsVertex * u1,
-				       GtsVertex * u2,
-				       GtsVertex * u3,
-				       GtsVertex * v1,
-				       GtsVertex * v2,
-				       GtsVertex * v3)
-{
-  GtsVertex * u = NULL;
-
-  g_assert (u1 && u2 && u3);
-  g_assert (v1 && v2 && v3);
-  g_assert (vertices_are_unique (u1, u2, u3));
-  g_assert (vertices_are_unique (v1, v2, v3));
-  g_assert (num_shared_vertices (u1, u2, u3, v1, v2, v3) == 2);
-
-  if (!vertex_is_one_of (u1, v1, v2, v3)) {
-    g_assert (vertex_is_one_of (u2, v1, v2, v3));
-    g_assert (vertex_is_one_of (u3, v1, v2, v3));
-    u = u1;
-  } else if (!vertex_is_one_of (u2, v1, v2, v3)) {
-    g_assert (vertex_is_one_of (u1, v1, v2, v3));
-    g_assert (vertex_is_one_of (u3, v1, v2, v3));
-    u = u2;
-  } else if (!vertex_is_one_of (u3, v1, v2, v3)) {
-    g_assert (vertex_is_one_of (u1, v1, v2, v3));
-    g_assert (vertex_is_one_of (u2, v1, v2, v3));
-    u = u3;
-  } else 
-    g_assert_not_reached ();
-
-  return u;
-}
-
-static void match_vertex (GtsVertex * v,
-			  GtsVertex ** v1,
-			  GtsVertex ** v2,
-			  GtsVertex ** v3)
-{
-  g_assert (v && v1 && v2 && v3);
-  g_assert (*v1 && *v2 && *v3);
-  g_assert (vertex_is_one_of (v, *v1, *v2, *v3));
-  while (*v1 != v) {
-    GtsVertex *v0 = *v1;
-
-    *v1 = *v2;
-    *v2 = *v3;
-    *v3 = v0;
-  }
-}
-
-/* tri_data_t functions */
-
-static tri_data_t * tri_data_new (GtsTriangle * t)
-{
-  tri_data_t * td;
-  
-  td = g_malloc (sizeof (tri_data_t));
-  td->t = t;
-  td->used = FALSE;
-  td->neighbors = gts_triangle_neighbors (t);
-  td->pos = NULL;
-
-  return td;
-}
-
-static void tri_data_destroy (tri_data_t * td)
-{
-  if (!td)
-    return;
-  g_slist_free (td->neighbors);
-  g_free (td);
-}
-
-static guint tri_data_num_unused_neighbors2 (const tri_data_t * td,
-					     const map_t * map)
-{
-  GHashTable *h;
-  guint n;
-
-  g_assert (td);
-  g_assert (map);
-  h = tri_data_unused_neighbors2 (td, map);
-  n = g_hash_table_size (h);
-  g_hash_table_destroy (h);
-  return n;
-}
-
-static void copy_key_to_array (gpointer key,
-			       gpointer value,
-			       gpointer user_data)
-{
-  GtsTriangle * t = key;
-  GtsTriangle *** p = user_data;
-
-  (void) value;
-  g_assert (t);
-  g_assert (p && *p);
-  **p = t;
-  (*p)++;
-}
-
-static gboolean are_neighbors_unique (GHashTable *h)
-{
-  GtsTriangle ** a;
-  GtsTriangle ** p;
-  gint i, j, n;		/* guint won't work if n == 0 */
-
-  g_assert (h);
-  n = g_hash_table_size (h);
-#ifdef DEBUG
-  if (n > 9)
-    g_warning ("triangle has %d 2-level neighbors", n);
-#endif /* DEBUG */
-  a = g_malloc(n*sizeof (GtsTriangle *));
-  p = a;
-  g_hash_table_foreach (h, copy_key_to_array, &p);
-  for (i = 0; i < n - 1; i++) {
-    g_assert (a[i]);
-    for (j = i + 1; j < n; j++) {
-      g_assert (a[j]);
-      if (a[i] == a[j]) {
-	g_free (a);
-	return FALSE;
-      }
-    }
-  }
-  g_free (a);
-  return TRUE;
-}
-
-static GHashTable * tri_data_unused_neighbors2 (const tri_data_t * td,
-						const map_t * map)
-{
-  GHashTable * h = g_hash_table_new (NULL, NULL);
-  GSList * li;
-
-  g_assert (td);
-  g_assert (map);
-  for (li = td->neighbors; li != NULL; li = li->next) {
-    GtsTriangle * t2 = li->data;
-    tri_data_t * td2 = map_lookup (map, t2);
-    GSList * lj;
-
-    g_assert (td2);
-    if (!td2->used) {
-      g_hash_table_insert (h, t2, td2);
-      for (lj = td2->neighbors; lj != NULL; lj = lj->next) {
-	GtsTriangle * t3 = lj->data;
-	tri_data_t * td3 = map_lookup (map, t3);
-
-	g_assert (td3);
-	if (td3 != td && !td3->used)
-	  g_hash_table_insert (h, t3, td3);
-      }
-    }
-  }
-  g_assert (are_neighbors_unique (h));
-  return h;
-}
-
-#if PRINT_HEAP_ELEMENTS
-static void tri_data_print (const tri_data_t * td, FILE * fp)
-{
-  g_assert (td);
-  g_assert (fp);
-  fprintf(fp, "td=%p t=%p used=%d pos=%p key=%f\n",
-	  td, td->t, td->used, td->pos,
-	  td->pos ? td->pos->key : -1.0);
-}
-#endif /* PRINT_HEAP_ELEMENTS */
-
-/* heap_t functions */
-
-static gdouble triangle_priority (gpointer item, gpointer data)
-{
-  GtsTriangle * t = item;
-  map_t * map = data;
-  tri_data_t * td;
-  gdouble k;
-  
-  g_assert (t);
-  g_assert (map);
-  td = map_lookup (map, t);
-  g_assert (td);
-  k = tri_data_num_unused_neighbors2 (td, map);
-  return k;
-}
-
-#if PRINT_HEAP_ELEMENTS
-static void print_heap_element (gpointer data, gpointer user_data)
-{
-  GtsTriangle * t = data;
-  map_t * map = user_data;
-  tri_data_t * td;
-  
-  g_assert (t);
-  g_assert (map);
-  td = map_lookup (map, t);
-  g_assert (td);
-  g_assert (!td->used);
-  g_assert (td->pos);
-  tri_data_print (td, stderr);
-}
-#endif /* PRINT_HEAP_ELEMENTS */
-
-static void insert_entry_into_heap (gpointer key,
-				    gpointer value,
-				    gpointer user_data)
-{
-  GtsTriangle * t = key;
-  tri_data_t * td = value;
-  GtsEHeap * heap = user_data;
-  
-  g_assert (!td->pos);
-  td->pos = gts_eheap_insert (heap, t);
-  g_assert (td->pos);
-}
-
-static heap_t * heap_new (GtsSurface *s)
-{
-  heap_t * heap;
-
-  g_assert (s);
-  heap = g_malloc (sizeof (heap_t));
-  heap->map = map_new (s);
-  heap->heap = gts_eheap_new (triangle_priority, heap->map);
-  g_hash_table_foreach (heap->map->ht,
-			insert_entry_into_heap,
-			heap->heap);
-#if PRINT_HEAP_ELEMENTS
-  gts_eheap_foreach (heap->heap, print_heap_element, heap->map);
-#endif /* PRINT_HEAP_ELEMENTS */
-  return heap;
-}
-
-static void heap_destroy (heap_t * heap)
-{
-  if (!heap)
-    return;
-  map_destroy (heap->map);
-  gts_eheap_destroy (heap->heap);
-  g_free (heap);
-}
-
-static gboolean heap_is_empty (const heap_t * heap)
-{
-  g_assert (heap);
-  g_assert (heap->heap);
-  return gts_eheap_size (heap->heap) == 0;
-}
-
-typedef struct {
-  const heap_t * heap;
-  double min_key;
-} min_key_t;
-
-static GtsTriangle * heap_top (const heap_t * heap)
-{
-  GtsTriangle * t;
-  
-  g_assert (heap);
-  g_assert (heap->heap);
-  t = gts_eheap_top (heap->heap, NULL);
-  return t;
-}
-
-static void decrease_key (gpointer key, gpointer value, gpointer user_data)
-{
-  GtsTriangle * t = key;
-  tri_data_t * td = value;
-  heap_t *heap = user_data;
-  gdouble k;
-  
-  (void) t;
-  g_assert (heap);
-  g_assert (heap->map);
-  g_assert (heap->heap);
-  g_assert (td);
-  g_assert (!td->used);
-  g_assert (td->pos);
-  
-  k = tri_data_num_unused_neighbors2 (td, heap->map);
-  g_assert (k <= td->pos->key);
-#ifdef DEBUG
-  if (k == td->pos->key)
-    g_warning ("same key: %f\n", k);
-#endif /* DEBUG */
-  if (k != td->pos->key) {
-    g_assert (k < td->pos->key);
-    g_assert (k >= 0.0);
-    gts_eheap_decrease_key (heap->heap, td->pos, k);
-  }
-}
-
-static void heap_remove (heap_t * heap, GtsTriangle * t)
-{
-  tri_data_t * td;
-  GHashTable * h;
-  
-  g_assert (heap);
-  g_assert (t);
-  td = map_lookup (heap->map, t);
-  g_assert (td);
-  g_assert (!td->used);
-  g_assert (td->pos);
-  td->used = TRUE;
-  gts_eheap_remove (heap->heap, td->pos);
-  td->pos = NULL;
-  
-  /*	fprintf(stderr, "td: %p\n", td); */
-  h = tri_data_unused_neighbors2 (td, heap->map);
-  g_hash_table_foreach (h, decrease_key, heap);
-  g_hash_table_destroy (h);
-}
-
-/* map_t functions */
-
-static gint create_map_entry (gpointer item, gpointer data)
-{
-  GtsTriangle * t = item;
-  GHashTable * ht = data;
-  tri_data_t * td;
-
-  g_assert (t);
-  g_assert (ht);
-  td = tri_data_new (t);
-  g_hash_table_insert (ht, t, td);
-  return 0;
-}
-
-static void free_map_entry (gpointer key, gpointer value, gpointer user_data)
-{
-  GtsTriangle * t = key;
-  tri_data_t * td = value;
-
-  (void) user_data;
-  g_assert (t);
-  g_assert (td);
-  g_assert (td->t == t);
-  tri_data_destroy (td);
-}
-
-static map_t * map_new (GtsSurface * s)
-{
-  map_t * map;
-
-  map = g_malloc (sizeof (map_t));
-  map->ht = g_hash_table_new (NULL, NULL);
-  gts_surface_foreach_face (s, create_map_entry, map->ht);
-  return map;
-}
-
-static void map_destroy (map_t * map)
-{
-  if (!map)
-    return;
-  g_hash_table_foreach (map->ht, free_map_entry, NULL);
-  g_hash_table_destroy (map->ht);
-  g_free (map);
-}
-
-static tri_data_t * map_lookup (const map_t * map, GtsTriangle * t)
-{
-  tri_data_t * td;
-
-  g_assert (map);
-  g_assert (map->ht);
-  g_assert (t);
-  td = g_hash_table_lookup (map->ht, t);
-  g_assert (td);
-  g_assert (td->t == t);
-  return td;
-}
-
-/* other helper functions */
-
-static GtsTriangle * find_min_neighbor (heap_t * heap, GtsTriangle * t)
-{
-  GtsTriangle * min_neighbor = NULL;
-  gdouble min_key = G_MAXDOUBLE;
-  tri_data_t * td;
-  GSList * li;
-
-  g_assert (heap);
-  g_assert (t);
-
-  td = map_lookup (heap->map, t);
-  for (li = td->neighbors; li != NULL; li = li->next) {
-    GtsTriangle * t2 = li->data;
-    tri_data_t * td2 = map_lookup (heap->map, t2);
-    gdouble k;
-    
-    g_assert (td2);
-    if (td2->used)
-      continue;
-    g_assert (td2->pos);
-    k = td2->pos->key;
-    if (k < min_key) {
-      min_key = k;
-      min_neighbor = t2;
-    }
-  }
-  return min_neighbor;
-}
-
-static GtsTriangle * find_neighbor_forward (heap_t * heap,
-					    GtsTriangle * t,
-					    GtsVertex ** v1,
-					    GtsVertex ** v2,
-					    GtsVertex ** v3,
-					    gboolean left_turn)
-{
-  GtsTriangle * neighbor = NULL;
-  tri_data_t * td;
-  GSList * li;
-
-  g_assert (heap);
-  g_assert (t);
-  g_assert (v1 && v2 && v3);
-  g_assert (vertices_are_unique (*v1, *v2, *v3));
-  
-  td = map_lookup (heap->map, t);
-  g_assert (td);
-  for (li = td->neighbors; li && !neighbor; li = li->next) {
-    GtsTriangle * t2 = li->data;
-    tri_data_t * td2 = map_lookup (heap->map, t2);
-    GtsVertex * v4, * v5, * v6;
-    
-    g_assert (td2);
-    if (t2 == t || td2->used)
-      continue;
-    gts_triangle_vertices (t2, &v4, &v5, &v6);
-    if (left_turn) {
-      if (!vertices_match (*v1, *v3, NULL, &v4, &v5, &v6))
-	continue;
-    } else {
-      if (!vertices_match (*v3, *v2, NULL, &v4, &v5, &v6))
-	continue;
-    }
-    neighbor = t2;
-    *v1 = v4;
-    *v2 = v5;
-    *v3 = v6;
-  }
-  return neighbor;
-}
-
-static GtsTriangle * find_neighbor_backward (heap_t * heap,
-					     GtsTriangle * t,
-					     GtsVertex ** v1,
-					     GtsVertex ** v2,
-					     GtsVertex ** v3,
-					     gboolean left_turn)
-{
-  GtsTriangle * neighbor = NULL;
-  tri_data_t * td;
-  GSList * li;
-
-  g_assert (heap);
-  g_assert (t);
-  g_assert (v1 && v2 && v3);
-  g_assert (vertices_are_unique (*v1, *v2, *v3));
-
-  td = map_lookup (heap->map, t);
-  g_assert (td);
-  for (li = td->neighbors; li && !neighbor; li = li->next) {
-    GtsTriangle * t2 = li->data;
-    tri_data_t * td2 = map_lookup (heap->map, t2);
-    GtsVertex * v4, * v5, * v6;
-    
-    g_assert (td2);
-    if (t2 == t || td2->used)
-      continue;
-    gts_triangle_vertices (t2, &v4, &v5, &v6);
-    if (left_turn) {
-      if (!vertices_match (NULL, *v2, *v1, &v4, &v5, &v6))
-	continue;
-    } else if (!vertices_match(*v1, NULL, *v2, &v4, &v5, &v6))
-      continue;
-    neighbor = t2;
-    *v1 = v4;
-    *v2 = v5;
-    *v3 = v6;
-  }
-  return neighbor;
-}
-
-static GSList * grow_strip_forward (heap_t * heap,
-				    GSList * strip,
-				    GtsTriangle * t,
-				    GtsVertex * v1,
-				    GtsVertex * v2,
-				    GtsVertex * v3)
-{
-  gboolean left_turn;
-  
-  g_assert (heap);
-  g_assert (g_slist_length(strip) == 2);
-  g_assert (t);
-  g_assert (v1 && v2 && v3);
-  g_assert (vertices_are_unique (v1, v2, v3));
-
-  left_turn = TRUE;
-  while ((t = find_neighbor_forward (heap, t, &v1, &v2, &v3, 
-				     left_turn)) != NULL) {
-    heap_remove (heap, t);
-    strip = g_slist_prepend (strip, t);
-    left_turn = !left_turn;
-  }
-  return strip;
-}
-
-static GSList * grow_strip_backward (heap_t * heap,
-				     GSList * strip,
-				     GtsTriangle * t,
-				     GtsVertex * v1,
-				     GtsVertex * v2,
-				     GtsVertex * v3)
-{
-  /* we have to make sure we add an even number of triangles */
-  GtsTriangle * t2;
-
-  g_assert (heap);
-  g_assert (g_slist_length(strip) >= 2);
-  g_assert (t);
-  g_assert (v1 && v2 && v3);
-  g_assert (vertices_are_unique (v1, v2, v3));
-
-  while ((t2 = find_neighbor_backward (heap, t, &v1, &v2, &v3,
-				       FALSE)) != NULL
-	 && (t = find_neighbor_backward (heap, t2, &v1, &v2, &v3,
-					 TRUE)) != NULL) {
-    heap_remove (heap, t2);
-    heap_remove (heap, t);
-    strip = g_slist_prepend (strip, t2);
-    strip = g_slist_prepend (strip, t);
-  }
-  return strip;
-}
-
-static gboolean find_right_turn (GtsVertex ** v1,
-				 GtsVertex ** v2,
-				 GtsVertex ** v3,
-				 GtsVertex ** v4,
-				 GtsVertex ** v5,
-				 GtsVertex ** v6)
-{
-  GtsVertex * v;
-
-  g_assert (v1 && v2 && v3);
-  g_assert (v4 && v5 && v6);
-  g_assert (vertices_are_unique (*v1, *v2, *v3));
-  g_assert (vertices_are_unique (*v4, *v5, *v6));
-  g_assert (num_shared_vertices (*v1, *v2, *v3, *v4, *v5, *v6) == 2);
-
-  v = non_shared_vertex1 (*v1, *v2, *v3, *v4, *v5, *v6);
-  match_vertex (v, v1, v2, v3);
-  match_vertex (*v3, v4, v5, v6);
-
-  g_assert (v1 && v2 && v3);
-  g_assert (v4 && v5 && v6);
-  g_assert (*v4 == *v3);
-
-  if (*v5 == *v2) {
-    g_assert (vertices_are_unique (*v1, *v2, *v3));
-    g_assert (vertices_are_unique (*v4, *v5, *v6));
-    g_assert (num_shared_vertices (*v1, *v2, *v3,
-					*v4, *v5, *v6) == 2);
-    return TRUE;
-  } else {
-#ifdef DEBUG
-    g_warning ("couldn't find a right turn");
-#endif /* DEBUG */
-    return FALSE;
-  }
-}
-
-/**
- * gts_surface_strip:
- * @s: a #GtsSurface.
- *
- * Decompose @s into triangle strips for fast-rendering.
- *
- * Returns: a list of triangle strips containing all the triangles of @s. 
- * A triangle strip is itself a list of successive triangles having one edge
- * in common.
- */
-GSList * gts_surface_strip (GtsSurface *s)
-{
-  GSList * strips = NULL;
-  heap_t * heap;
-
-  g_return_val_if_fail (s != NULL, NULL);
-
-  heap = heap_new (s);
-  while (!heap_is_empty (heap)) {
-    GtsTriangle * t1, * t2;
-    GtsVertex * v1, * v2, * v3, * v4, * v5, * v6;
-    GSList * strip = NULL;
-
-    /* remove heap top */
-    t1 = heap_top (heap);
-    g_assert (t1);
-    heap_remove (heap, t1);
-
-    /* start a new strip */
-    strip = g_slist_prepend (strip, t1);
-
-    /* find second triangle */
-    t2 = find_min_neighbor (heap, t1);
-    if (t2) {
-      g_assert (t2 != t1);
-
-      /* find right turn */
-      gts_triangle_vertices (t1, &v1, &v2, &v3);
-      gts_triangle_vertices (t2, &v4, &v5, &v6);
-      if (find_right_turn (&v1, &v2, &v3, &v4, &v5, &v6)) {
-	heap_remove (heap, t2);
-	strip = g_slist_prepend (strip, t2);
-
-	/* grow strip forward */
-	strip = grow_strip_forward (heap, strip, t2, v4, v5, v6);
-
-	strip = g_slist_reverse (strip);
-
-	/* grow strip backward */
-	strip = grow_strip_backward (heap, strip, t1, v1, v2, v3);
-      }
-    }
-    strips = g_slist_prepend (strips, strip);
-  }
-  strips = g_slist_reverse (strips);
-  heap_destroy (heap);
-
-  return strips;
-}
diff --git a/src_3rd/gts/surface.c b/src_3rd/gts/surface.c
deleted file mode 100644
index 34c5cbe..0000000
--- a/src_3rd/gts/surface.c
+++ /dev/null
@@ -1,2743 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
-#include "gts.h"
-
-#include "gts-private.h"
-
-static void destroy_foreach_face (GtsFace * f, GtsSurface * s)
-{
-  f->surfaces = g_slist_remove (f->surfaces, s);
-  if (!GTS_OBJECT_DESTROYED (f) &&
-      !gts_allow_floating_faces && f->surfaces == NULL)
-    gts_object_destroy (GTS_OBJECT (f));
-}
-
-static void surface_destroy (GtsObject * object)
-{
-  GtsSurface * surface = GTS_SURFACE (object);
-  
-  gts_surface_foreach_face (surface, (GtsFunc) destroy_foreach_face, surface);
-#ifdef USE_SURFACE_BTREE
-  g_tree_destroy (surface->faces);
-#else /* not USE_SURFACE_BTREE */
-  g_hash_table_destroy (surface->faces);
-#endif /* not USE_SURFACE_BTREE */
-
-  (* GTS_OBJECT_CLASS (gts_surface_class ())->parent_class->destroy) (object);
-}
-
-static void surface_write (GtsObject * object, FILE * fptr)
-{
-  fprintf (fptr, " %s %s %s %s", 
-	   object->klass->info.name,
-	   GTS_OBJECT_CLASS (GTS_SURFACE (object)->face_class)->info.name,
-	   GTS_OBJECT_CLASS (GTS_SURFACE (object)->edge_class)->info.name,
-	   GTS_POINT_CLASS (GTS_SURFACE (object)->vertex_class)->binary ?
-	   "GtsVertexBinary" :
-	   GTS_OBJECT_CLASS (GTS_SURFACE (object)->vertex_class)->info.name);
-}
-
-static void surface_class_init (GtsSurfaceClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->destroy = surface_destroy;
-  GTS_OBJECT_CLASS (klass)->write = surface_write;
-  klass->add_face = NULL;
-  klass->remove_face = NULL;
-}
-
-#ifdef USE_SURFACE_BTREE
-static gint compare_pointers (gconstpointer a, gconstpointer b)
-{
-  if (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b))
-    return -1;
-  if (GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b))
-    return 1;
-  return 0;
-}
-#endif /* USE_SURFACE_BTREE */
-
-static void surface_init (GtsSurface * surface)
-{
-#ifdef USE_SURFACE_BTREE
-  surface->faces = g_tree_new (compare_pointers);
-#else /* not USE_SURFACE_BTREE */
-  surface->faces = g_hash_table_new (NULL, NULL);
-#endif /* not USE_SURFACE_BTREE */
-  surface->vertex_class = gts_vertex_class ();
-  surface->edge_class = gts_edge_class ();
-  surface->face_class = gts_face_class ();
-  surface->keep_faces = FALSE;
-}
-
-/**
- * gts_surface_class:
- *
- * Returns: the #GtsSurfaceClass.
- */
-GtsSurfaceClass * gts_surface_class (void)
-{
-  static GtsSurfaceClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo surface_info = {
-      "GtsSurface",
-      sizeof (GtsSurface),
-      sizeof (GtsSurfaceClass),
-      (GtsObjectClassInitFunc) surface_class_init,
-      (GtsObjectInitFunc) surface_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), &surface_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_surface_new:
- * @klass: a #GtsSurfaceClass.
- * @face_class: a #GtsFaceClass.
- * @edge_class: a #GtsEdgeClass.
- * @vertex_class: a #GtsVertexClass.
- *
- * Returns: a new empty #GtsSurface.
- */
-GtsSurface * gts_surface_new (GtsSurfaceClass * klass,
-			      GtsFaceClass * face_class,
-			      GtsEdgeClass * edge_class,
-			      GtsVertexClass * vertex_class)
-{
-  GtsSurface * s;
-
-  s = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  s->vertex_class = vertex_class;
-  s->edge_class = edge_class;
-  s->face_class = face_class;
-
-  return s;
-}
-
-/**
- * gts_surface_add_face:
- * @s: a #GtsSurface.
- * @f: a #GtsFace.
- *
- * Adds face @f to surface @s.
- */
-void gts_surface_add_face (GtsSurface * s, GtsFace * f)
-{
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (f != NULL);
-
-  g_assert (s->keep_faces == FALSE);
-
-#ifdef USE_SURFACE_BTREE
-  if (!g_tree_lookup (s->faces, f)) {
-    f->surfaces = g_slist_prepend (f->surfaces, s);
-    g_tree_insert (s->faces, f, f);
-  }
-#else /* not USE_SURFACE_BTREE */
-  if (!g_hash_table_lookup (s->faces, f)) {
-    f->surfaces = g_slist_prepend (f->surfaces, s);
-    g_hash_table_insert (s->faces, f, f);
-  }
-#endif /* not USE_SURFACE_BTREE */
-
-  if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->add_face)
-    (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->add_face) (s, f);
-}
-
-/**
- * gts_surface_remove_face:
- * @s: a #GtsSurface.
- * @f: a #GtsFace.
- *
- * Removes face @f from surface @s.
- */
-void gts_surface_remove_face (GtsSurface * s, 
-			      GtsFace * f)
-{
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (f != NULL);
-
-  g_assert (s->keep_faces == FALSE);
-
-#ifdef USE_SURFACE_BTREE
-  g_tree_remove (s->faces, f);
-#else /* not USE_SURFACE_BTREE */
-  g_hash_table_remove (s->faces, f);
-#endif /* not USE_SURFACE_BTREE */
-
-  f->surfaces = g_slist_remove (f->surfaces, s);
-
-  if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face)
-    (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f);
-
-  if (!GTS_OBJECT_DESTROYED (f) &&
-      !gts_allow_floating_faces && 
-      f->surfaces == NULL)
-    gts_object_destroy (GTS_OBJECT (f));
-}
-
-/**
- * gts_surface_read:
- * @surface: a #GtsSurface.
- * @f: a #GtsFile.
- *
- * Add to @surface the data read from @f. The format of the file pointed to
- * by @f is as described in gts_surface_write().
- *
- * Returns: 0 if successful or the line number at which the parsing
- * stopped in case of error (in which case the @error field of @f is
- * set to a description of the error which occured).  
- */
-/* Update split.c/surface_read() if modifying this function */
-guint gts_surface_read (GtsSurface * surface, GtsFile * f)
-{
-  GtsVertex ** vertices;
-  GtsEdge ** edges;
-  guint n, nv, ne, nf;
-
-  g_return_val_if_fail (surface != NULL, 1);
-  g_return_val_if_fail (f != NULL, 1);
-
-  if (f->type != GTS_INT) {
-    gts_file_error (f, "expecting an integer (number of vertices)");
-    return f->line;
-  }
-  nv = atoi (f->token->str);
-
-  gts_file_next_token (f);
-  if (f->type != GTS_INT) {
-    gts_file_error (f, "expecting an integer (number of edges)");
-    return f->line;
-  }
-  ne = atoi (f->token->str);
-
-  gts_file_next_token (f);
-  if (f->type != GTS_INT) {
-    gts_file_error (f, "expecting an integer (number of faces)");
-    return f->line;
-  }
-  nf = atoi (f->token->str);
-  
-  gts_file_next_token (f);
-  if (f->type == GTS_STRING) {
-    if (f->type != GTS_STRING) {
-      gts_file_error (f, "expecting a string (GtsSurfaceClass)");
-      return f->line;
-    }
-    gts_file_next_token (f);
-    if (f->type != GTS_STRING) {
-      gts_file_error (f, "expecting a string (GtsFaceClass)");
-      return f->line;
-    }
-    gts_file_next_token (f);
-    if (f->type != GTS_STRING) {
-      gts_file_error (f, "expecting a string (GtsEdgeClass)");
-      return f->line;
-    }
-    gts_file_next_token (f);
-    if (f->type != GTS_STRING) {
-      gts_file_error (f, "expecting a string (GtsVertexClass)");
-      return f->line;
-    }
-    if (!strcmp (f->token->str, "GtsVertexBinary"))
-      GTS_POINT_CLASS (surface->vertex_class)->binary = TRUE;
-    else {
-      GTS_POINT_CLASS (surface->vertex_class)->binary = FALSE;
-      gts_file_first_token_after (f, '\n');
-    }
-  }
-  else
-    gts_file_first_token_after (f, '\n');
-
-  if (nf <= 0)
-    return 0;
-
-  /* allocate nv + 1 just in case nv == 0 */
-  vertices = g_malloc ((nv + 1)*sizeof (GtsVertex *));
-  edges = g_malloc ((ne + 1)*sizeof (GtsEdge *));
-  
-  n = 0;
-  while (n < nv && f->type != GTS_ERROR) {
-    GtsObject * new_vertex =
-      gts_object_new (GTS_OBJECT_CLASS (surface->vertex_class));
-
-    (* GTS_OBJECT_CLASS (surface->vertex_class)->read) (&new_vertex, f);
-    if (f->type != GTS_ERROR) {
-      if (!GTS_POINT_CLASS (surface->vertex_class)->binary)
-	gts_file_first_token_after (f, '\n');
-      vertices[n++] = GTS_VERTEX (new_vertex);
-    }
-    else
-      gts_object_destroy (new_vertex);
-  }
-  if (f->type == GTS_ERROR)
-    nv = n;
-  if (GTS_POINT_CLASS (surface->vertex_class)->binary)
-    gts_file_first_token_after (f, '\n');
-
-  n = 0;
-  while (n < ne && f->type != GTS_ERROR) {
-    guint p1, p2;
-
-    if (f->type != GTS_INT)
-      gts_file_error (f, "expecting an integer (first vertex index)");
-    else {
-      p1 = atoi (f->token->str);
-      if (p1 == 0 || p1 > nv)
-	gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", 
-			p1, nv);
-      else {
-	gts_file_next_token (f);
-	if (f->type != GTS_INT)
-	  gts_file_error (f, "expecting an integer (second vertex index)");
-	else {
-	  p2 = atoi (f->token->str);
-	  if (p2 == 0 || p2 > nv)
-	    gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", 
-			    p2, nv);
-	  else {
-	    GtsEdge * new_edge =
-	      gts_edge_new (surface->edge_class,
-			    vertices[p1 - 1], vertices[p2 - 1]);
-
-	    gts_file_next_token (f);
-	    if (f->type != '\n')
-	      if (GTS_OBJECT_CLASS (surface->edge_class)->read)
-		(*GTS_OBJECT_CLASS (surface->edge_class)->read)
-		  ((GtsObject **) &new_edge, f);
-	    gts_file_first_token_after (f, '\n');
-	    edges[n++] = new_edge;
-	  }
-	}
-      }
-    }
-  }
-  if (f->type == GTS_ERROR)
-    ne = n;
-
-  n = 0;
-  while (n < nf && f->type != GTS_ERROR) {
-    guint s1, s2, s3;
-
-    if (f->type != GTS_INT)
-      gts_file_error (f, "expecting an integer (first edge index)");
-    else {
-      s1 = atoi (f->token->str);
-      if (s1 == 0 || s1 > ne)
-	gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
-			s1, ne);
-      else {
-	gts_file_next_token (f);
-	if (f->type != GTS_INT)
-	  gts_file_error (f, "expecting an integer (second edge index)");
-	else {
-	  s2 = atoi (f->token->str);
-	  if (s2 == 0 || s2 > ne)
-	    gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
-			    s2, ne);
-	  else {
-	    gts_file_next_token (f);
-	    if (f->type != GTS_INT)
-	      gts_file_error (f, "expecting an integer (third edge index)");
-	    else {
-	      s3 = atoi (f->token->str);
-	      if (s3 == 0 || s3 > ne)
-		gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
-				s3, ne);
-	      else {
-		GtsFace * new_face = gts_face_new (surface->face_class,
-						   edges[s1 - 1],
-						   edges[s2 - 1],
-						   edges[s3 - 1]);
-
-		gts_file_next_token (f);
-		if (f->type != '\n')
-		  if (GTS_OBJECT_CLASS (surface->face_class)->read)
-		    (*GTS_OBJECT_CLASS (surface->face_class)->read)
-		      ((GtsObject **) &new_face, f);
-		gts_file_first_token_after (f, '\n');
-		gts_surface_add_face (surface, new_face);
-		n++;
-	      }
-	    }
-	  }
-	}
-      }
-    }
-  }
-
-  if (f->type == GTS_ERROR) {
-    gts_allow_floating_vertices = TRUE;
-    while (nv)
-      gts_object_destroy (GTS_OBJECT (vertices[nv-- - 1]));
-    gts_allow_floating_vertices = FALSE;
-  }
-
-  g_free (vertices);
-  g_free (edges);
-
-  if (f->type == GTS_ERROR)
-    return f->line;
-  return 0;
-}
-
-static void sum_area (GtsFace * f, gdouble * area) {
-  *area += gts_triangle_area (GTS_TRIANGLE (f));
-}
-
-/**
- * gts_surface_area:
- * @s: a #GtsSurface.
- *
- * Returns: the area of @s obtained as the sum of the signed areas of its
- * faces.
- */
-gdouble gts_surface_area (GtsSurface * s)
-{  
-  gdouble area = 0.0;
-  gts_surface_foreach_face (s, (GtsFunc)sum_area, &area);
-  return area;
-}
-
-/**
- * gts_range_init:
- * @r: a #GtsRange.
- *
- * Initializes a #GtsRange.
- */
-void gts_range_init (GtsRange * r)
-{
-  g_return_if_fail (r != NULL);
-
-  r->max = - G_MAXDOUBLE;
-  r->min = G_MAXDOUBLE;
-  r->sum = r->sum2 = 0.0;
-  r->n = 0;
-}
-
-/**
- * gts_range_reset:
- * @r: a #GtsRange.
- *
- * Sets all the fields of @r to 0.
- */
-void gts_range_reset (GtsRange * r)
-{
-  g_return_if_fail (r != NULL);
-
-  r->max = 0.0;
-  r->min = 0.0;
-  r->sum = r->sum2 = 0.0;
-  r->n = 0;
-}
-
-/**
- * gts_range_add_value:
- * @r: a #GtsRange.
- * @val: a value to add to @r.
- *
- * Adds @val to @r.
- */
-void gts_range_add_value (GtsRange * r, gdouble val)
-{
-  g_return_if_fail (r != NULL);
-
-  if (val < r->min) r->min = val;
-  if (val > r->max) r->max = val;
-  r->sum += val;
-  r->sum2 += val*val;
-  r->n++;
-}
-
-/**
- * gts_range_update:
- * @r: a #GtsRange.
- * 
- * Updates the fields of @r.
- */
-void gts_range_update (GtsRange * r)
-{
-  g_return_if_fail (r != NULL);
-
-  if (r->n > 0) {
-    if (r->sum2 - r->sum*r->sum/(gdouble) r->n >= 0.)
-      r->stddev = sqrt ((r->sum2 - r->sum*r->sum/(gdouble) r->n)
-			/(gdouble) r->n);
-    else
-      r->stddev = 0.;
-    r->mean = r->sum/(gdouble) r->n;
-  }
-  else 
-    r->min = r->max = r->mean = r->stddev = 0.;
-}
-
-/**
- * gts_range_print:
- * @r: a #GtsRange.
- * @fptr: a file pointer.
- * 
- * Writes a text representation of @r in @fptr.
- */
-void gts_range_print (GtsRange * r, FILE * fptr)
-{
-  g_return_if_fail (r != NULL);
-  g_return_if_fail (fptr != NULL);
-  fprintf (fptr, "min: %g mean: %g | %g max: %g", 
-	   r->min, r->mean, r->stddev, r->max);
-}
-
-static void stats_foreach_vertex (GtsVertex * v, GtsSurfaceStats * stats) 
-{
-  GSList * i = v->segments;
-  guint nedges = 0;
-
-  while (i) {
-    if (GTS_IS_EDGE (i->data) && 
-	gts_edge_has_parent_surface (i->data, stats->parent))
-      nedges++;
-    i = i->next;
-  }
-  gts_range_add_value (&stats->edges_per_vertex, nedges);
-}
-
-static void stats_foreach_edge (GtsEdge * e, GtsSurfaceStats * stats) 
-{
-  guint nt = gts_edge_face_number (e, stats->parent);
-
-  if (gts_segment_is_duplicate (GTS_SEGMENT (e)))
-    stats->n_duplicate_edges++;
-  if (nt == 1)
-    stats->n_boundary_edges++;
-  else if (nt > 2)
-    stats->n_non_manifold_edges++;
-  gts_range_add_value (&stats->faces_per_edge, nt);
-}
-
-static void stats_foreach_face (GtsTriangle * t, GtsSurfaceStats * stats)
-{
-  if (!gts_face_is_compatible (GTS_FACE (t), stats->parent))
-    stats->n_incompatible_faces++;
-  if (gts_triangle_is_duplicate (t))
-    stats->n_duplicate_faces++;
-  stats->n_faces++;
-}
-
-/**
- * gts_surface_stats:
- * @s: a #GtsSurface.
- * @stats: a #GtsSurfaceStats.
- *
- * Fills @stats with the statistics relevant to surface @s.
- */
-void gts_surface_stats (GtsSurface * s, GtsSurfaceStats * stats)
-{
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (stats != NULL);
-
-  stats->parent = s;
-  stats->n_faces = 0;
-  stats->n_incompatible_faces = 0;
-  stats->n_duplicate_faces = 0;
-  stats->n_duplicate_edges = 0;
-  stats->n_boundary_edges = 0;
-  stats->n_non_manifold_edges = 0;
-  gts_range_init (&stats->edges_per_vertex);
-  gts_range_init (&stats->faces_per_edge);
-
-  gts_surface_foreach_vertex (s, (GtsFunc) stats_foreach_vertex, stats);
-  gts_surface_foreach_edge (s, (GtsFunc) stats_foreach_edge, stats);
-  gts_surface_foreach_face (s, (GtsFunc) stats_foreach_face, stats);
-
-  gts_range_update (&stats->edges_per_vertex);
-  gts_range_update (&stats->faces_per_edge);
-}
-
-static void quality_foreach_edge (GtsSegment * s,
-				  GtsSurfaceQualityStats * stats) 
-{
-  GSList * i = GTS_EDGE (s)->triangles;
-
-  gts_range_add_value (&stats->edge_length, 
-		   gts_point_distance (GTS_POINT (s->v1), 
-				       GTS_POINT (s->v2)));
-  while (i) {
-    GSList * j = i->next;
-    while (j) {
-      gts_range_add_value (&stats->edge_angle,
-			   fabs (gts_triangles_angle (i->data, j->data)));
-      j = j->next;
-    }
-    i = i->next;
-  }
-}
-
-static void quality_foreach_face (GtsTriangle * t,
-				  GtsSurfaceQualityStats * stats) 
-{
-  gts_range_add_value (&stats->face_quality, gts_triangle_quality (t));
-  gts_range_add_value (&stats->face_area, gts_triangle_area (t));
-}
-
-/**
- * gts_surface_quality_stats:
- * @s: a #GtsSurface.
- * @stats: a #GtsSurfaceQualityStats.
- *
- * Fills @stats with quality statistics relevant to surface @s.
- */
-void gts_surface_quality_stats (GtsSurface * s, GtsSurfaceQualityStats * stats)
-{
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (stats != NULL);
-
-  stats->parent = s;
-  gts_range_init (&stats->face_quality);
-  gts_range_init (&stats->face_area);
-  gts_range_init (&stats->edge_length);
-  gts_range_init (&stats->edge_angle);
-
-  gts_surface_foreach_edge (s, (GtsFunc) quality_foreach_edge, stats);  
-  gts_surface_foreach_face (s, (GtsFunc) quality_foreach_face, stats);
-
-  gts_range_update (&stats->face_quality);
-  gts_range_update (&stats->face_area);
-  gts_range_update (&stats->edge_length);
-  gts_range_update (&stats->edge_angle);
-}
-
-/**
- * gts_surface_print_stats:
- * @s: a #GtsSurface.
- * @fptr: a file pointer.
- *
- * Writes in the file pointed to by @fptr the statistics for surface @s.
- */
-void gts_surface_print_stats (GtsSurface * s, FILE * fptr)
-{
-  GtsSurfaceStats stats;
-  GtsSurfaceQualityStats qstats;
-
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (fptr != NULL);
-
-  gts_surface_stats (s, &stats);
-  gts_surface_quality_stats (s, &qstats);
-
-  fprintf (fptr, 
-	   "# vertices: %u edges: %u faces: %u\n"
-	   "# Connectivity statistics\n"
-	   "#   incompatible faces: %u\n"
-	   "#   duplicate faces: %u\n"
-	   "#   boundary edges: %u\n"
-	   "#   duplicate edges: %u\n"
-	   "#   non-manifold edges: %u\n",
-	   stats.edges_per_vertex.n, 
-	   stats.faces_per_edge.n,
-	   stats.n_faces,
-	   stats.n_incompatible_faces,
-	   stats.n_duplicate_faces,
-	   stats.n_boundary_edges,
-	   stats.n_duplicate_edges,
-	   stats.n_non_manifold_edges);
-  fputs ("#   edges per vertex: ", fptr); 
-  gts_range_print (&stats.edges_per_vertex, fptr);
-  fputs ("\n#   faces per edge: ", fptr);
-  gts_range_print (&stats.faces_per_edge, fptr);
-  fputs ("\n# Geometric statistics\n#   face quality: ", fptr);
-  gts_range_print (&qstats.face_quality, fptr);
-  fputs ("\n#   face area  : ", fptr);
-  gts_range_print (&qstats.face_area, fptr);
-  fputs ("\n#   edge length : ", fptr);
-  gts_range_print (&qstats.edge_length, fptr);
-  fputc ('\n', fptr);
-}
-
-static void write_vertex (GtsPoint * p, gpointer * data)
-{
-  (*GTS_OBJECT (p)->klass->write) (GTS_OBJECT (p), (FILE *) data[0]);
-  if (!GTS_POINT_CLASS (GTS_OBJECT (p)->klass)->binary)
-    fputc ('\n', (FILE *) data[0]);
-  g_hash_table_insert (data[2], p, 
-		       GUINT_TO_POINTER (++(*((guint *) data[1]))));
-}
-
-static void write_edge (GtsSegment * s, gpointer * data) 
-{
-  fprintf ((FILE *) data[0], "%u %u",
-	   GPOINTER_TO_UINT (g_hash_table_lookup (data[2], s->v1)),
-	   GPOINTER_TO_UINT (g_hash_table_lookup (data[2], s->v2)));
-  if (GTS_OBJECT (s)->klass->write)
-    (*GTS_OBJECT (s)->klass->write) (GTS_OBJECT (s), (FILE *) data[0]);
-  fputc ('\n', (FILE *) data[0]);
-  g_hash_table_insert (data[3], s, 
-		       GUINT_TO_POINTER (++(*((guint *) data[1]))));
-}
-
-static void write_face (GtsTriangle * t, gpointer * data)
-{
-  fprintf (data[0], "%u %u %u",
-	   GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e1)),
-	   GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e2)),
-	   GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e3)));
-  if (GTS_OBJECT (t)->klass->write)
-    (*GTS_OBJECT (t)->klass->write) (GTS_OBJECT (t), data[0]);
-  fputc ('\n', data[0]);
-}
-
-/**
- * gts_surface_write:
- * @s: a #GtsSurface.
- * @fptr: a file pointer.
- * 
- * Writes in the file @fptr an ASCII representation of @s. The file
- * format is as follows. 
- *
- * All the lines beginning with #GTS_COMMENTS are ignored. The first line
- * contains three unsigned integers separated by spaces. The first
- * integer is the number of vertices, nv, the second is the number of
- * edges, ne and the third is the number of faces, nf.
- *
- * Follows nv lines containing the x, y and z coordinates of the
- * vertices.  Follows ne lines containing the two indices (starting
- * from one) of the vertices of each edge. Follows nf lines containing
- * the three ordered indices (also starting from one) of the edges of
- * each face.  
- *
- * The format described above is the least common denominator to all
- * GTS files.  Consistent with an object-oriented approach, the GTS
- * file format is extensible. Each of the lines of the file can be
- * extended with user-specific attributes accessible through the
- * read() and write() virtual methods of each of the objects written
- * (surface, vertices, edges or faces). When read with different
- * object classes, these extra attributes are just ignored.  
- */
-void gts_surface_write (GtsSurface * s, FILE * fptr)
-{
-  guint n;
-  gpointer data[4];
-  GHashTable * vindex, * eindex;
-  GtsSurfaceStats stats;
-
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (fptr != NULL);
-
-  data[0] = fptr;
-  data[1] = &n;
-  data[2] = vindex = g_hash_table_new (NULL, NULL);
-  data[3] = eindex = g_hash_table_new (NULL, NULL);
-
-  gts_surface_stats (s, &stats);
-  fprintf (fptr, "%u %u %u", 
-	   stats.edges_per_vertex.n, 
-	   stats.faces_per_edge.n, 
-	   stats.n_faces);
-  if (GTS_OBJECT (s)->klass->write)
-    (*GTS_OBJECT (s)->klass->write) (GTS_OBJECT (s), fptr);
-  fputc ('\n', fptr);
-  n = 0;
-  gts_surface_foreach_vertex (s, (GtsFunc) write_vertex, data);
-  n = 0;
-  if (GTS_POINT_CLASS (s->vertex_class)->binary)
-    fputc ('\n', fptr);
-  gts_surface_foreach_edge (s, (GtsFunc) write_edge, data);
-  gts_surface_foreach_face (s, (GtsFunc) write_face, data);
-  g_hash_table_destroy (vindex);
-  g_hash_table_destroy (eindex);
-}
-
-static void write_vertex_oogl (GtsPoint * p, gpointer * data)
-{
-  FILE * fp = data[0];
-
-  fprintf (fp, "%g %g %g", p->x, p->y, p->z);
-  if (GTS_OBJECT (p)->klass->color) {
-    GtsColor c = (* GTS_OBJECT (p)->klass->color) (GTS_OBJECT (p));
-    fprintf (fp, " %g %g %g 1.0\n", c.r, c.g, c.b);
-  }
-  else
-    fputc ('\n', fp);
-  GTS_OBJECT (p)->reserved = GUINT_TO_POINTER ((*((guint *) data[1]))++);
-}
-
-static void write_face_oogl (GtsTriangle * t, FILE * fp)
-{
-  GtsVertex * v1, * v2, * v3;
-  gts_triangle_vertices (t, &v1, &v2, &v3);
-  fprintf (fp, "3 %u %u %u",
-	   GPOINTER_TO_UINT (GTS_OBJECT (v1)->reserved),
-	   GPOINTER_TO_UINT (GTS_OBJECT (v2)->reserved),
-	   GPOINTER_TO_UINT (GTS_OBJECT (v3)->reserved));
-  if (GTS_OBJECT (t)->klass->color) {
-    GtsColor c = (* GTS_OBJECT (t)->klass->color) (GTS_OBJECT (t));
-    fprintf (fp, " %g %g %g\n", c.r, c.g, c.b);
-  }
-  else
-    fputc ('\n', fp);
-}
-
-/**
- * gts_surface_write_oogl:
- * @s: a #GtsSurface.
- * @fptr: a file pointer.
- * 
- * Writes in the file @fptr an OOGL (Geomview) representation of @s.
- */
-void gts_surface_write_oogl (GtsSurface * s, FILE * fptr)
-{
-  guint n = 0;
-  gpointer data[2];
-  GtsSurfaceStats stats;
-
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (fptr != NULL);
-
-  data[0] = fptr;
-  data[1] = &n;
-
-  gts_surface_stats (s, &stats);
-  if (GTS_OBJECT_CLASS (s->vertex_class)->color)
-    fputs ("COFF ", fptr);
-  else
-    fputs ("OFF ", fptr);
-  fprintf (fptr, "%u %u %u\n", 
-	   stats.edges_per_vertex.n, 
-	   stats.n_faces,
-	   stats.faces_per_edge.n);
-  gts_surface_foreach_vertex (s, (GtsFunc) write_vertex_oogl, data);
-  gts_surface_foreach_face (s, (GtsFunc) write_face_oogl, fptr);
-  gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL);
-}
-
-static void write_vertex_vtk (GtsPoint * p, gpointer * data)
-{
-  FILE * fp = data[0];
-
-  fprintf (fp, "%g %g %g\n", p->x, p->y, p->z);
-  GTS_OBJECT (p)->reserved = GUINT_TO_POINTER ((*((guint *) data[1]))++);
-}
-
-static void write_face_vtk (GtsTriangle * t, FILE * fp)
-{
-  GtsVertex * v1, * v2, * v3;
-  gts_triangle_vertices (t, &v1, &v2, &v3);
-  fprintf (fp, "3 %u %u %u\n",
-	   GPOINTER_TO_UINT (GTS_OBJECT (v1)->reserved),
-	   GPOINTER_TO_UINT (GTS_OBJECT (v2)->reserved),
-	   GPOINTER_TO_UINT (GTS_OBJECT (v3)->reserved));
-}
-
-/**
- * gts_surface_write_vtk:
- * @s: a #GtsSurface.
- * @fptr: a file pointer.
- * 
- * Writes in the file @fptr a VTK representation of @s.
- */
-void gts_surface_write_vtk (GtsSurface * s, FILE * fptr)
-{
-  guint n = 0;
-  gpointer data[2];
-  GtsSurfaceStats stats;
-
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (fptr != NULL);
-
-  data[0] = fptr;
-  data[1] = &n;
-
-  gts_surface_stats (s, &stats);
-  fprintf (fptr,
-	   "# vtk DataFile Version 2.0\n"
-	   "Generated by GTS\n"
-           "ASCII\n"
-	   "DATASET POLYDATA\n"
-	   "POINTS %u float\n",
-	   stats.edges_per_vertex.n);
-  gts_surface_foreach_vertex (s, (GtsFunc) write_vertex_vtk, data);
-  fprintf (fptr,
-	   "POLYGONS %u %u\n",
-	   stats.n_faces, stats.n_faces*4);
-  gts_surface_foreach_face (s, (GtsFunc) write_face_vtk, fptr);
-  gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL);  
-}
-
-static void write_edge_oogl_boundary (GtsSegment * s, gpointer * data)
-{
-  if (!gts_edge_is_boundary (GTS_EDGE (s), data[1]))
-    return;
-
-  if (GTS_OBJECT (s)->klass->color) {
-    GtsColor c = (* GTS_OBJECT (s)->klass->color) (GTS_OBJECT (s));
-    fprintf (data[0], "VECT 1 2 1 2 1 %g %g %g %g %g %g %g %g %g 1.\n",
-	     GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z,
-	     GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z,
-	     c.r, c.g, c.b);
-  }
-  else
-    fprintf (data[0], "VECT 1 2 0 2 0 %g %g %g %g %g %g\n",
-	     GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z,
-	     GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z);
-}
-
-/**
- * gts_surface_write_oogl_boundary:
- * @s: a #GtsSurface.
- * @fptr: a file pointer.
- * 
- * Writes in the file @fptr an OOGL (Geomview) representation of the
- * boundary of @s.  
- */
-void gts_surface_write_oogl_boundary (GtsSurface * s, FILE * fptr)
-{
-  gpointer data[2];
-
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (fptr != NULL);
-
-  data[0] = fptr;
-  data[1] = s;
-  fputs ("LIST {\n", fptr);
-  gts_surface_foreach_edge (s, (GtsFunc) write_edge_oogl_boundary, data);
-  fputs ("}\n", fptr);
-}
-
-#ifdef USE_SURFACE_BTREE
-static gint vertex_foreach_face (GtsTriangle * t,
-				 gpointer t_data,
-				 gpointer * info)
-#else /* not USE_SURFACE_BTREE */
-static void vertex_foreach_face (GtsTriangle * t,
-				 gpointer t_data,
-				 gpointer * info)
-#endif /* not USE_SURFACE_BTREE */
-{
-  GHashTable * hash = info[0];
-  gpointer data = info[1];
-  GtsFunc func = (GtsFunc) info[2];
-  GtsSegment 
-    * s1 = GTS_SEGMENT (t->e1);
-
-  if (!g_hash_table_lookup (hash, s1->v1)) {
-    (*func) (s1->v1, data);
-    g_hash_table_insert (hash, s1->v1, GINT_TO_POINTER (-1));
-  }
-  if (!g_hash_table_lookup (hash, s1->v2)) {
-    (*func) (s1->v2, data);
-    g_hash_table_insert (hash, s1->v2, GINT_TO_POINTER (-1));
-  }
-  if (!g_hash_table_lookup (hash, gts_triangle_vertex (t))) {
-    (*func) (gts_triangle_vertex (t), data);
-    g_hash_table_insert (hash, gts_triangle_vertex (t), 
-			 GINT_TO_POINTER (-1));
-  }
-#ifdef USE_SURFACE_BTREE
-  return FALSE;
-#endif /* USE_SURFACE_BTREE */
-}
-
-/**
- * gts_surface_foreach_vertex:
- * @s: a #GtsSurface.
- * @func: a #GtsFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func once for each vertex of @s.
- */
-void gts_surface_foreach_vertex (GtsSurface * s, GtsFunc func, gpointer data)
-{
-  gpointer info[3];
-
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (func != NULL);
-
-  /* forbid removal of faces */
-  s->keep_faces = TRUE;
-  info[0] = g_hash_table_new (NULL, NULL);
-  info[1] = data;
-  info[2] = func;
-#ifdef USE_SURFACE_BTREE
-  g_tree_traverse (s->faces, (GTraverseFunc) vertex_foreach_face, G_IN_ORDER,
-		   info);
-#else /* not USE_SURFACE_BTREE */
-  g_hash_table_foreach (s->faces, (GHFunc) vertex_foreach_face, info);
-#endif /* not USE_SURFACE_BTREE */
-  g_hash_table_destroy (info[0]);
-  /* allow removal of faces */
-  s->keep_faces = FALSE;
-}
-
-#ifdef USE_SURFACE_BTREE
-static gint edge_foreach_face (GtsTriangle * t,
-			       gpointer t_data, 
-			       gpointer * info)
-#else /* not USE_SURFACE_BTREE */
-static void edge_foreach_face (GtsTriangle * t,
-			       gpointer t_data, 
-			       gpointer * info)
-#endif /* not USE_SURFACE_BTREE */
-{
-  GHashTable * hash = info[0];
-  gpointer data = info[1];
-  GtsFunc func = (GtsFunc) info[2];
-
-  if (!g_hash_table_lookup (hash, t->e1)) {
-    (*func) (t->e1, data);
-    g_hash_table_insert (hash, t->e1, GINT_TO_POINTER (-1));
-  }
-  if (!g_hash_table_lookup (hash, t->e2)) {
-    (*func) (t->e2, data);
-    g_hash_table_insert (hash, t->e2, GINT_TO_POINTER (-1));
-  }
-  if (!g_hash_table_lookup (hash, t->e3)) {
-    (*func) (t->e3, data);
-    g_hash_table_insert (hash, t->e3, GINT_TO_POINTER (-1));
-  }
-#ifdef USE_SURFACE_BTREE
-  return FALSE;
-#endif /* not USE_SURFACE_BTREE */
-}
-
-/**
- * gts_surface_foreach_edge:
- * @s: a #GtsSurface.
- * @func: a #GtsFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func once for each edge of @s.
- */
-void gts_surface_foreach_edge (GtsSurface * s, GtsFunc func, gpointer data)
-{
-  gpointer info[3];
-
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (func != NULL);
-  
-  /* forbid removal of faces */
-  s->keep_faces = TRUE;
-  info[0] = g_hash_table_new (NULL, NULL);
-  info[1] = data;
-  info[2] = func;
-#ifdef USE_SURFACE_BTREE
-  g_tree_traverse (s->faces, (GTraverseFunc) edge_foreach_face, G_IN_ORDER,
-		   info);
-#else /* not USE_SURFACE_BTREE */
-  g_hash_table_foreach (s->faces, (GHFunc) edge_foreach_face, info);
-#endif /* not USE_SURFACE_BTREE */
-  g_hash_table_destroy (info[0]);
-  /* allow removal of faces */
-  s->keep_faces = FALSE;
-}
-
-#ifdef USE_SURFACE_BTREE
-static gint foreach_face (GtsFace * f, 
-			  gpointer t_data,
-			  gpointer * info)
-#else /* not USE_SURFACE_BTREE */
-static void foreach_face (GtsFace * f, 
-			  gpointer t_data,
-			  gpointer * info)
-#endif /* not USE_SURFACE_BTREE */
-{
-  (*((GtsFunc) info[0])) (f, info[1]);
-#ifdef USE_SURFACE_BTREE
-  return FALSE;
-#endif /* USE_SURFACE_BTREE */
-}
-
-/**
- * gts_surface_foreach_face:
- * @s: a #GtsSurface.
- * @func: a #GtsFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func once for each face of @s.
- */
-void gts_surface_foreach_face (GtsSurface * s,
-			       GtsFunc func, 
-			       gpointer data)
-{
-  gpointer info[2];
-
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (func != NULL);
-
-  /* forbid removal of faces */
-  s->keep_faces = TRUE;
-  info[0] = func;
-  info[1] = data;
-#ifdef USE_SURFACE_BTREE
-  g_tree_traverse (s->faces, (GTraverseFunc) foreach_face, G_IN_ORDER,
-		   info);
-#else /* not USE_SURFACE_BTREE */
-  g_hash_table_foreach (s->faces, (GHFunc) foreach_face, info);
-#endif /* not USE_SURFACE_BTREE */
-  /* allow removal of faces */
-  s->keep_faces = FALSE;
-}
-
-#ifdef USE_SURFACE_BTREE
-static gint foreach_face_remove (GtsFace * f,
-				 gpointer t_data,
-				 gpointer * info)
-{
-  if ((*((GtsFunc) info[0])) (f, info[1])) {
-    GtsSurface * s = info[2];
-    guint * n = info[3];
-
-    f->surfaces = g_slist_remove (f->surfaces, s);
-    if (!GTS_OBJECT_DESTROYED (f) &&
-	!gts_allow_floating_faces && 
-	f->surfaces == NULL)
-      gts_object_destroy (GTS_OBJECT (f));
-    
-    if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face)
-      (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f);
-
-    g_tree_remove (s->faces, f);
-    (*n)++;
-  }
-  return FALSE;
-}
-#else /* not USE_SURFACE_BTREE */
-static gboolean foreach_face_remove (GtsFace * f,
-				     gpointer t_data,
-				     gpointer * info)
-{
-  if ((*((GtsFunc) info[0])) (f, info[1])) {
-    GtsSurface * s = info[2];
-
-    f->surfaces = g_slist_remove (f->surfaces, s);
-    if (!GTS_OBJECT_DESTROYED (f) &&
-	!gts_allow_floating_faces && 
-	f->surfaces == NULL)
-      gts_object_destroy (GTS_OBJECT (f));
-    
-    if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face)
-      (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f);
-
-    return TRUE;
-  }
-  return FALSE;
-}
-#endif /* not USE_SURFACE_BTREE */
-
-/**
- * gts_surface_foreach_face_remove:
- * @s: a #GtsSurface.
- * @func: a #GtsFunc.
- * @data: user data to be passed to @func.
- *
- * Calls @func once for each face of @s. If @func returns %TRUE the
- * corresponding face is removed from @s (and destroyed if it does not
- * belong to any other surface and #gts_allow_floating_faces is set to
- * %FALSE).
- *
- * Returns: the number of faces removed from @s.  
- */
-guint gts_surface_foreach_face_remove (GtsSurface * s,
-				       GtsFunc func, 
-				       gpointer data)
-{
-  gpointer info[4];
-  guint n = 0;
-
-  g_return_val_if_fail (s != NULL, 0);
-  g_return_val_if_fail (func != NULL, 0);
-
-  /* forbid removal of faces */
-  s->keep_faces = TRUE;
-  info[0] = func;
-  info[1] = data;
-  info[2] = s;
-#ifdef USE_SURFACE_BTREE
-  info[3] = &n;
-  g_tree_traverse (s->faces, (GTraverseFunc) foreach_face_remove, G_PRE_ORDER,
-		   info);
-#else /* not USE_SURFACE_BTREE */
-  n = g_hash_table_foreach_remove (s->faces, 
-				   (GHRFunc) foreach_face_remove, 
-				   info);
-#endif /* not USE_SURFACE_BTREE */
-  /* allow removal of faces */
-  s->keep_faces = FALSE;
-  
-  return n;
-}
-
-static void midvertex_insertion (GtsEdge * e,
-				 GtsSurface * surface,
-				 GtsEHeap * heap,
-				 GtsRefineFunc refine_func,
-				 gpointer refine_data,
-				 GtsVertexClass * vertex_class,
-				 GtsEdgeClass * edge_class)
-{
-  GtsVertex * midvertex;
-  GtsEdge * e1, * e2;
-  GSList * i;
-
-  midvertex = (*refine_func) (e, vertex_class, refine_data);
-  e1 = gts_edge_new (edge_class, GTS_SEGMENT (e)->v1, midvertex);
-  gts_eheap_insert (heap, e1);
-  e2 = gts_edge_new (edge_class, GTS_SEGMENT (e)->v2, midvertex);
-  gts_eheap_insert (heap, e2);
-  
-  /* creates new faces and modifies old ones */
-  i = e->triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    GtsVertex * v1, * v2, * v3;
-    GtsEdge * te2, * te3, * ne, * tmp;
-
-    gts_triangle_vertices_edges (t, e, &v1, &v2, &v3, &e, &te2, &te3);
-    ne = gts_edge_new (edge_class, midvertex, v3);
-    gts_eheap_insert (heap, ne);
-    if (GTS_SEGMENT (e1)->v1 == v2) {
-      tmp = e1; e1 = e2; e2 = tmp;
-    }
-    e1->triangles = g_slist_prepend (e1->triangles, t);
-    ne->triangles = g_slist_prepend (ne->triangles, t);
-    te2->triangles = g_slist_remove (te2->triangles, t);
-    t->e1 = e1; t->e2 = ne; t->e3 = te3;
-    gts_surface_add_face (surface, 
-			  gts_face_new (surface->face_class, e2, te2, ne));
-    i = i->next;
-  }
-  /* destroys edge */
-  g_slist_free (e->triangles);
-  e->triangles = NULL;
-  gts_object_destroy (GTS_OBJECT (e));
-}
-
-static gdouble edge_length2_inverse (GtsSegment * s)
-{
-  return - gts_point_distance2 (GTS_POINT (s->v1), GTS_POINT (s->v2));
-}
-
-static void create_heap_refine (GtsEdge * e, GtsEHeap * heap)
-{
-  gts_eheap_insert (heap, e);
-}
-
-/**
- * gts_surface_refine:
- * @surface: a #GtsSurface.
- * @cost_func: a function returning the cost for a given edge.
- * @cost_data: user data to be passed to @cost_func.
- * @refine_func: a #GtsRefineFunc.
- * @refine_data: user data to be passed to @refine_func.
- * @stop_func: a #GtsStopFunc.
- * @stop_data: user data to be passed to @stop_func.
- *
- * Refine @surface using a midvertex insertion technique. All the
- * edges of @surface are ordered according to @cost_func. The edges
- * are then processed in order until @stop_func returns %TRUE. Each
- * edge is split in two and new edges and faces are created.
- *
- * If @cost_func is set to %NULL, the edges are sorted according 
- * to their length squared (the longest is on top).
- *
- * If @refine_func is set to %NULL gts_segment_midvertex() is used.
- * 
- */
-void gts_surface_refine (GtsSurface * surface,
-			 GtsKeyFunc cost_func,
-			 gpointer cost_data,
-			 GtsRefineFunc refine_func,
-			 gpointer refine_data,
-			 GtsStopFunc stop_func,
-			 gpointer stop_data)
-{
-  GtsEHeap * heap;
-  GtsEdge * e;
-  gdouble top_cost;
-
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (stop_func != NULL);
-
-  if (cost_func == NULL)
-    cost_func = (GtsKeyFunc) edge_length2_inverse;
-  if (refine_func == NULL)
-    refine_func = (GtsRefineFunc) gts_segment_midvertex;
-
-  heap = gts_eheap_new (cost_func, cost_data);
-  gts_eheap_freeze (heap);
-  gts_surface_foreach_edge (surface, (GtsFunc) create_heap_refine, heap);
-  gts_eheap_thaw (heap);
-  while ((e = gts_eheap_remove_top (heap, &top_cost)) &&
-	 !(*stop_func) (top_cost,
-			gts_eheap_size (heap) + 
-			gts_edge_face_number (e, surface) + 2,
-			stop_data))
-    midvertex_insertion (e, surface, heap, refine_func, refine_data,
-			 surface->vertex_class, surface->edge_class);
-  gts_eheap_destroy (heap);
-}
-
-static GSList * edge_triangles (GtsEdge * e1, GtsEdge * e)
-{
-  GSList * i = e1->triangles;
-  GSList * triangles = NULL;
-  
-  while (i) {
-    GtsTriangle * t = i->data;
-    if (t->e1 == e || t->e2 == e || t->e3 == e) {
-      GtsEdge * e2;
-      GSList * j;
-      if (t->e1 == e) {
-	if (t->e2 == e1)
-	  e2 = t->e3;
-	else
-	  e2 = t->e2;
-      }
-      else if (t->e2 == e) {
-	if (t->e3 == e1)
-	  e2 = t->e1;
-	else
-	  e2 = t->e3;
-      }
-      else {
-	if (t->e2 == e1)
-	  e2 = t->e1;
-	else
-	  e2 = t->e2;
-      }
-      j = e2->triangles;
-      while (j) {
-	GtsTriangle * t = j->data;
-	if (t->e1 != e && t->e2 != e && t->e3 != e)
-	  triangles = g_slist_prepend (triangles, t);
-	j = j->next;
-      }
-    }
-    else
-      triangles = g_slist_prepend (triangles, t);
-    i = i->next;
-  }
-  return triangles;
-}
-
-static void replace_vertex (GSList * i, GtsVertex * v1, GtsVertex * v)
-{
-  while (i) {
-    GtsSegment * s = i->data;
-    if (s->v1 == v1)
-      s->v1 = v;
-    else
-      s->v2 = v;
-    i = i->next;
-  }
-}
-
-/**
- * gts_edge_collapse_creates_fold:
- * @e: a #GtsEdge.
- * @v: a #GtsVertex.
- * @max:  the maximum value of the square of the cosine of the angle between
- * two triangles.
- *
- * Returns: %TRUE if collapsing edge @e to vertex @v would create
- * faces making an angle the cosine squared of which would be larger than max,
- * %FALSE otherwise.  
- */
-gboolean gts_edge_collapse_creates_fold (GtsEdge * e, 
-					 GtsVertex * v,
-					 gdouble max)
-{
-  GtsVertex * v1, * v2;
-  GtsSegment * s;
-  GSList * i;
-  gboolean folded = FALSE;
-
-  g_return_val_if_fail (e != NULL, TRUE);
-  g_return_val_if_fail (v != NULL, TRUE);
-
-  s = GTS_SEGMENT (e);
-  v1 = s->v1;
-  v2 = s->v2;
-  replace_vertex (v1->segments, v1, v);
-  replace_vertex (v2->segments, v2, v);
-
-  i = v1->segments;
-  while (i && !folded) {
-    GtsSegment * s = i->data;
-    if (GTS_IS_EDGE (s)) {
-      GtsEdge * e1 = GTS_EDGE (s);
-      if (e1 != e) {
-	GSList * triangles = edge_triangles (e1, e);
-	folded = gts_triangles_are_folded (triangles, s->v1, s->v2, max);
-	g_slist_free (triangles);
-      }
-    }
-    i = i->next;
-  }
-
-  i = v2->segments;
-  while (i && !folded) {
-    GtsSegment * s = i->data;
-    if (GTS_IS_EDGE (s)) {
-      GtsEdge * e1 = GTS_EDGE (s);
-      if (e1 != e) {
-	GSList * triangles = edge_triangles (e1, e);
-	folded = gts_triangles_are_folded (triangles, s->v1, s->v2, max);
-	g_slist_free (triangles);
-      }
-    }
-    i = i->next;
-  }
-#if 1
-  if (!folded) {
-    GSList * triangles = gts_vertex_triangles (v1, NULL);
-    i = triangles = gts_vertex_triangles (v2, triangles);
-    while (i && !folded) {
-      GtsTriangle * t = i->data;
-      if (t->e1 != e && t->e2 != e && t->e3 != e) {
-	GtsEdge * e1 = gts_triangle_edge_opposite (t, v);
-	g_assert (e1);
-	folded = gts_triangles_are_folded (e1->triangles, 
-					   GTS_SEGMENT (e1)->v1,
-					   GTS_SEGMENT (e1)->v2,
-					   max);
-      }
-      i = i->next;
-    }
-    g_slist_free (triangles);
-  }
-#endif
-  replace_vertex (v1->segments, v, v1);
-  replace_vertex (v2->segments, v, v2);
-  return folded;
-}
-
-/**
- * gts_edge_collapse_is_valid:
- * @e: a #GtsEdge.
- *
- * An implementation of the topological constraints described in the 
- * "Mesh Optimization" article of Hoppe et al (1993).
- *
- * Returns: %TRUE if @e can be collapsed without violation of the topological
- * constraints, %FALSE otherwise.
- */
-gboolean gts_edge_collapse_is_valid (GtsEdge * e)
-{
-  GSList * i;
-
-  g_return_val_if_fail (e != NULL, FALSE);
-
-  i = GTS_SEGMENT (e)->v1->segments;
-  while (i) {
-    GtsEdge * e1 = i->data;
-    if (e1 != e && GTS_IS_EDGE (e1)) {
-      GtsEdge * e2 = NULL;
-      GSList * j = GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v1 ? 
-	GTS_SEGMENT (e1)->v2->segments : GTS_SEGMENT (e1)->v1->segments;
-      while (j && !e2) {
-	GtsEdge * e1 = j->data;
-	if (GTS_IS_EDGE (e1) && 
-	    (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v2 || 
-	     GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e)->v2))
-	  e2 = e1;
-	j = j->next;
-      }
-      if (e2 && !gts_triangle_use_edges (e, e1, e2))
-	return FALSE;
-    }
-    i = i->next;
-  }
-
-  if (gts_edge_is_boundary (e, NULL)) {
-    GtsTriangle * t = e->triangles->data;
-    if (gts_edge_is_boundary (t->e1, NULL) &&
-	gts_edge_is_boundary (t->e2, NULL) &&
-	gts_edge_is_boundary (t->e3, NULL))
-      return FALSE;
-  }
-  else {
-    if (gts_vertex_is_boundary (GTS_SEGMENT (e)->v1, NULL) &&
-	gts_vertex_is_boundary (GTS_SEGMENT (e)->v2, NULL))
-      return FALSE;    
-    if (gts_edge_belongs_to_tetrahedron (e))
-      return FALSE;
-  }
-
-  return TRUE;
-}
-
-#define HEAP_INSERT_EDGE(h, e) (GTS_OBJECT (e)->reserved = gts_eheap_insert (h, e))
-#define HEAP_REMOVE_EDGE(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\
-                                GTS_OBJECT (e)->reserved = NULL)
-
-static GtsVertex * edge_collapse (GtsEdge * e,
-				  GtsEHeap * heap,
-				  GtsCoarsenFunc coarsen_func,
-				  gpointer coarsen_data,
-				  GtsVertexClass * klass,
-				  gdouble maxcosine2)
-{
-  GSList * i;
-  GtsVertex  * v1 = GTS_SEGMENT (e)->v1, * v2 = GTS_SEGMENT (e)->v2, * mid;
-
-  /* if the edge is degenerate (i.e. v1 == v2), destroy and return */
-  if (v1 == v2) {
-    gts_object_destroy (GTS_OBJECT (e));
-    return NULL;
-  }
-
-  if (!gts_edge_collapse_is_valid (e)) {
-    GTS_OBJECT (e)->reserved = 
-      gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE);
-    return NULL;
-  }
-
-  mid = (*coarsen_func) (e, klass, coarsen_data);
-
-  if (gts_edge_collapse_creates_fold (e, mid, maxcosine2)) {
-    GTS_OBJECT (e)->reserved = 
-      gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE);
-    gts_object_destroy (GTS_OBJECT (mid));
-    return NULL;
-  }
-
-  gts_object_destroy (GTS_OBJECT (e));
-
-  gts_vertex_replace (v1, mid);
-  gts_object_destroy (GTS_OBJECT (v1));
-  gts_vertex_replace (v2, mid);
-  gts_object_destroy (GTS_OBJECT (v2));
-
-  /* destroy duplicate edges */
-  i = mid->segments;
-  while (i) {
-    GtsEdge * e1 = i->data;
-    GtsEdge * duplicate;
-    while ((duplicate = gts_edge_is_duplicate (e1))) {
-      gts_edge_replace (duplicate, GTS_EDGE (e1));
-      HEAP_REMOVE_EDGE (heap, duplicate);
-      gts_object_destroy (GTS_OBJECT (duplicate));
-    }
-    i = i->next;
-    if (!e1->triangles) {
-      /* e1 is the result of the collapse of one edge of a pair of identical
-	 faces (it should not happen unless duplicate triangles are present in
-	 the initial surface) */
-      g_warning ("file %s: line %d (%s): probably duplicate triangle.",
-		 __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
-      HEAP_REMOVE_EDGE (heap, e1);
-      gts_object_destroy (GTS_OBJECT (e1));
-      if (i == NULL) /* mid has been destroyed */
-	mid = NULL;
-    }
-  }
-
-  return mid;
-}
-
-/*
- * I don't see where this code is ever used, but keep it for a bit 
- * in case it is needed for debugging
- */
-#ifdef GTS_NEED_UPDATE_CLOSEST_NEIGHBORS
-static void update_closest_neighbors (GtsVertex * v, GtsEHeap * heap)
-{
-  GSList * i = v->segments;
-  
-  while (i) {
-    GtsSegment * s = i->data;
-    if (GTS_IS_EDGE (s)) {
-      HEAP_REMOVE_EDGE (heap, GTS_EDGE (s));
-      HEAP_INSERT_EDGE (heap, GTS_EDGE (s));
-    }
-    i = i->next;
-  }
-}
-#endif
-
-static void update_2nd_closest_neighbors (GtsVertex * v, GtsEHeap * heap)
-{
-  GSList * i = v->segments;
-  GSList * list = NULL;
-  
-  while (i) {
-    GtsSegment * s = i->data;
-    if (GTS_IS_EDGE (s)) {
-      GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1;
-      GSList * j = v1->segments;
-      while (j) {
-	GtsSegment * s1 = j->data;
-	if (GTS_IS_EDGE (s1) && !g_slist_find (list, s1))
-	  list = g_slist_prepend (list, s1);
-	j = j->next;
-      }
-    }
-    i = i->next;
-  }
-
-  i = list;
-  while (i) {
-    GtsEdge * e = i->data;
-    HEAP_REMOVE_EDGE (heap, e);
-    HEAP_INSERT_EDGE (heap, e);
-    i = i->next;
-  }
-
-  g_slist_free (list);
-}
-
-static gdouble edge_length2 (GtsEdge * e)
-{
-  return gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), 
-			      GTS_POINT (GTS_SEGMENT (e)->v2));
-}
-
-static void create_heap_coarsen (GtsEdge * e, GtsEHeap * heap)
-{
-  HEAP_INSERT_EDGE (heap, e);
-}
-
-/**
- * gts_surface_coarsen:
- * @surface: a #GtsSurface.
- * @cost_func: a function returning the cost for a given edge.
- * @cost_data: user data to be passed to @cost_func.
- * @coarsen_func: a #GtsCoarsenVertexFunc.
- * @coarsen_data: user data to be passed to @coarsen_func.
- * @stop_func: a #GtsStopFunc.
- * @stop_data: user data to be passed to @stop_func.
- * @minangle: minimum angle between two neighboring triangles.
- *
- * The edges of @surface are sorted according to @cost_func to 
- * create a priority heap (a #GtsEHeap). The edges are extracted in
- * turn from the top of the heap and collapsed (i.e. the vertices are
- * replaced by the vertex returned by the @coarsen_func function)
- * until the @stop_func functions returns %TRUE.
- *
- * If @cost_func is set to %NULL, the edges are sorted according 
- * to their length squared (the shortest is on top).
- *
- * If @coarsen_func is set to %NULL gts_segment_midvertex() is used.
- *
- * The minimum angle is used to avoid introducing faces which would be folded.
- */
-void gts_surface_coarsen (GtsSurface * surface,
-			  GtsKeyFunc cost_func,
-			  gpointer cost_data,
-			  GtsCoarsenFunc coarsen_func,
-			  gpointer coarsen_data,
-			  GtsStopFunc stop_func,
-			  gpointer stop_data,
-			  gdouble minangle)
-{
-  GtsEHeap * heap;
-  GtsEdge * e;
-  gdouble top_cost;
-  gdouble maxcosine2;
-
-  g_return_if_fail (surface != NULL);
-  g_return_if_fail (stop_func != NULL);
-
-  if (cost_func == NULL)
-    cost_func = (GtsKeyFunc) edge_length2;
-  if (coarsen_func == NULL)
-    coarsen_func = (GtsCoarsenFunc) gts_segment_midvertex;
-
-  heap = gts_eheap_new (cost_func, cost_data);
-  maxcosine2 = cos (minangle); maxcosine2 *= maxcosine2;
-
-  gts_eheap_freeze (heap);
-  gts_surface_foreach_edge (surface, (GtsFunc) create_heap_coarsen, heap);
-  gts_eheap_thaw (heap);
-  /* we want to control edge destruction manually */
-  gts_allow_floating_edges = TRUE;
-  while ((e = gts_eheap_remove_top (heap, &top_cost)) &&
-	 (top_cost < G_MAXDOUBLE) &&
-	 !(*stop_func) (top_cost, gts_eheap_size (heap) - 
-			gts_edge_face_number (e, surface), stop_data))
-    {
-      GtsVertex * v = edge_collapse (e, heap, coarsen_func, coarsen_data,
-				     surface->vertex_class, maxcosine2);
-      if (v != NULL)
-	update_2nd_closest_neighbors (v, heap);
-    }
-  gts_allow_floating_edges = FALSE;
-
-  /* set reserved field of remaining edges back to NULL */
-  if (e) GTS_OBJECT (e)->reserved = NULL;
-  gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL);
-
-  gts_eheap_destroy (heap);
-}
-
-/**
- * gts_coarsen_stop_number:
- * @cost: the cost of the edge collapse considered.
- * @nedge: the current number of edges of the surface being simplified.
- * @min_number: a pointer to the minimum number of edges desired for the 
- * surface being simplified.
- *
- * This function is to be used as the @stop_func argument of 
- * gts_surface_coarsen() or gts_psurface_new().
- *
- * Returns: %TRUE if the edge collapse would create a surface with a smaller 
- * number of edges than given by @min_number, %FALSE otherwise.
- */
-gboolean gts_coarsen_stop_number (gdouble cost, 
-				  guint nedge, 
-				  guint * min_number)
-{
-  g_return_val_if_fail (min_number != NULL, TRUE);
-
-  if (nedge < *min_number)
-    return TRUE;
-  return FALSE;
-}
-
-/**
- * gts_coarsen_stop_cost:
- * @cost: the cost of the edge collapse considered.
- * @nedge: the current number of edges of the surface being simplified.
- * @max_cost: a pointer to the maximum cost allowed for an edge collapse.
- *
- * This function is to be used as the @stop_func argument of 
- * gts_surface_coarsen() or gts_psurface_new().
- *
- * Returns: %TRUE if the cost of the edge collapse considered is larger than
- * given by @max_cost, %FALSE otherwise.
- */
-gboolean gts_coarsen_stop_cost (gdouble cost, 
-				guint nedge, 
-				gdouble * max_cost)
-{
-  g_return_val_if_fail (max_cost != NULL, TRUE);
-
-  if (cost > *max_cost)
-    return TRUE;
-  return FALSE;
-}
-
-#define GTS_M_ICOSAHEDRON_X /* sqrt(sqrt(5)+1)/sqrt(2*sqrt(5)) */ \
-  0.850650808352039932181540497063011072240401406
-#define GTS_M_ICOSAHEDRON_Y /* sqrt(2)/sqrt(5+sqrt(5))         */ \
-  0.525731112119133606025669084847876607285497935
-#define GTS_M_ICOSAHEDRON_Z 0.0
-
-static guint generate_icosahedron (GtsSurface * s)
-{
-  GtsVertex * v01 = gts_vertex_new (s->vertex_class,
-      +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y);
-  GtsVertex * v02 = gts_vertex_new (s->vertex_class,
-      +GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z);
-  GtsVertex * v03 = gts_vertex_new (s->vertex_class,
-      +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X);
-  GtsVertex * v04 = gts_vertex_new (s->vertex_class,
-      +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X);
-  GtsVertex * v05 = gts_vertex_new (s->vertex_class,
-      +GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z);
-  GtsVertex * v06 = gts_vertex_new (s->vertex_class,
-      +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y);
-  GtsVertex * v07 = gts_vertex_new (s->vertex_class,
-      -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X);
-  GtsVertex * v08 = gts_vertex_new (s->vertex_class,
-      +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y);
-  GtsVertex * v09 = gts_vertex_new (s->vertex_class,
-      -GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z);
-  GtsVertex * v10 = gts_vertex_new (s->vertex_class,
-      -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X);
-  GtsVertex * v11 = gts_vertex_new (s->vertex_class,
-      -GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z);
-  GtsVertex * v12 = gts_vertex_new (s->vertex_class,
-      +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y);
-
-  GtsEdge * e01 = gts_edge_new (s->edge_class, v01, v02);
-  GtsEdge * e02 = gts_edge_new (s->edge_class, v03, v02);
-  GtsEdge * e03 = gts_edge_new (s->edge_class, v01, v03);
-  GtsEdge * e04 = gts_edge_new (s->edge_class, v04, v05);
-  GtsEdge * e05 = gts_edge_new (s->edge_class, v02, v05);
-  GtsEdge * e06 = gts_edge_new (s->edge_class, v04, v02);
-  GtsEdge * e07 = gts_edge_new (s->edge_class, v06, v07);
-  GtsEdge * e08 = gts_edge_new (s->edge_class, v04, v07);
-  GtsEdge * e09 = gts_edge_new (s->edge_class, v06, v04);
-  GtsEdge * e10 = gts_edge_new (s->edge_class, v08, v03);
-  GtsEdge * e11 = gts_edge_new (s->edge_class, v03, v05);
-  GtsEdge * e12 = gts_edge_new (s->edge_class, v08, v05);
-  GtsEdge * e13 = gts_edge_new (s->edge_class, v06, v09);
-  GtsEdge * e14 = gts_edge_new (s->edge_class, v07, v09);
-  GtsEdge * e15 = gts_edge_new (s->edge_class, v08, v10);
-  GtsEdge * e16 = gts_edge_new (s->edge_class, v03, v10);
-  GtsEdge * e17 = gts_edge_new (s->edge_class, v06, v01);
-  GtsEdge * e18 = gts_edge_new (s->edge_class, v01, v09);
-  GtsEdge * e19 = gts_edge_new (s->edge_class, v08, v11);
-  GtsEdge * e20 = gts_edge_new (s->edge_class, v10, v11);
-  GtsEdge * e21 = gts_edge_new (s->edge_class, v06, v02);
-  GtsEdge * e22 = gts_edge_new (s->edge_class, v12, v11);
-  GtsEdge * e23 = gts_edge_new (s->edge_class, v12, v08);
-  GtsEdge * e24 = gts_edge_new (s->edge_class, v12, v07);
-  GtsEdge * e25 = gts_edge_new (s->edge_class, v07, v11);
-  GtsEdge * e26 = gts_edge_new (s->edge_class, v12, v04);
-  GtsEdge * e27 = gts_edge_new (s->edge_class, v09, v11);
-  GtsEdge * e28 = gts_edge_new (s->edge_class, v10, v09);
-  GtsEdge * e29 = gts_edge_new (s->edge_class, v12, v05);
-  GtsEdge * e30 = gts_edge_new (s->edge_class, v01, v10);
-  
-  gts_surface_add_face (s, gts_face_new (s->face_class, e01, e02, e03));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e04, e05, e06));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e07, e08, e09));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e10, e11, e12));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e13, e14, e07));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e15, e16, e10));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e17, e18, e13));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e19, e20, e15));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e21, e01, e17));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e22, e19, e23));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e09, e06, e21));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e24, e25, e22));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e26, e08, e24));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e20, e27, e28));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e29, e04, e26));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e14, e27, e25));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e23, e12, e29));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e02, e05, e11));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e30, e28, e18));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e03, e16, e30));
-
-  return 0;
-}
-
-static GtsVertex * unit_sphere_arc_midvertex (GtsSegment * s, 
-					      GtsVertexClass * vertex_class)
-{
-  GtsPoint * p1, * p2;
-  gdouble x, y, z, norm;
-
-  p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2);
-
-  x = 0.5*(p1->x + p2->x);
-  y = 0.5*(p1->y + p2->y);
-  z = 0.5*(p1->z + p2->z);
-
-  norm = x*x + y*y + z*z;
-  norm = sqrt (norm);
-
-  x /= norm; y /= norm; z /= norm;
-
-  return gts_vertex_new (vertex_class, x, y, z);
-}
-
-static void tessellate_face (GtsFace * f,
-			     GtsSurface * s,
-			     GtsRefineFunc refine_func,
-			     gpointer refine_data,
-			     GtsVertexClass * vertex_class,
-			     GtsEdgeClass * edge_class)
-{
-  GtsTriangle * t;
-  GtsEdge * e1, * e2, * e3;                          /* former edges     */
-  GtsVertex * v1, * v2, * v3;                        /* initial vertices */
-  GtsVertex * v4, * v5, * v6;                        /* new vertices     */ 
-  GtsEdge * e56, * e64, * e45;                       /* new inside edges */
-  GtsEdge * e24, * e34, * e35, * e15, * e16, * e26;  /* new border edges */
-  GSList * dum;
-  GtsEdge * edum;
-  
-  t = GTS_TRIANGLE (f);
-  e1 = t->e1; e2 = t->e2; e3 = t->e3;
-
-  if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) {
-    v1 = GTS_SEGMENT (e2)->v2;
-    v2 = GTS_SEGMENT (e1)->v1;
-    v3 = GTS_SEGMENT (e1)->v2;
-  }
-  else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) {
-    v1 = GTS_SEGMENT (e2)->v1;
-    v2 = GTS_SEGMENT (e1)->v1;
-    v3 = GTS_SEGMENT (e1)->v2;
-  }
-  else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) {
-    v1 = GTS_SEGMENT (e2)->v2;
-    v2 = GTS_SEGMENT (e1)->v2;
-    v3 = GTS_SEGMENT (e1)->v1;
-  }
-  else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2) {
-    v1 = GTS_SEGMENT (e2)->v1;
-    v2 = GTS_SEGMENT (e1)->v2;
-    v3 = GTS_SEGMENT (e1)->v1;
-  }
-  else {
-    v1 = v2 = v3 = NULL;
-    g_assert_not_reached ();
-  }
-
-  e1->triangles = g_slist_remove (e1->triangles, t);
-  e2->triangles = g_slist_remove (e2->triangles, t);
-  e3->triangles = g_slist_remove (e3->triangles, t);
-  
-  if (GTS_OBJECT (e1)->reserved) {
-    dum = (GTS_OBJECT (e1)->reserved);
-    e24 = dum->data;
-    e34 = dum->next->data;
-    v4 = GTS_SEGMENT (e24)->v2;
-    if (GTS_SEGMENT (e24)->v1 == v3) {
-      edum = e34; e34 = e24; e24 = edum;
-    }
-  }
-  else {
-    v4 = (*refine_func) (e1, vertex_class, refine_data);
-    e24 = gts_edge_new (edge_class, v2, v4);
-    e34 = gts_edge_new (edge_class, v3, v4);
-    dum = g_slist_append (NULL, e24);
-    dum = g_slist_append (dum,  e34);
-    GTS_OBJECT (e1)->reserved = dum;
-  }
-  if (GTS_OBJECT (e2)->reserved) {
-    dum = (GTS_OBJECT (e2)->reserved);
-    e35 = dum->data;
-    e15 = dum->next->data;
-    v5 = GTS_SEGMENT (e35)->v2;
-    if (GTS_SEGMENT (e35)->v1 == v1) {
-      edum = e15; e15 = e35; e35 = edum;
-    }
-  }
-  else {
-    v5 = (*refine_func) (e2, vertex_class, refine_data);
-    e35 = gts_edge_new (edge_class, v3, v5);
-    e15 = gts_edge_new (edge_class, v1, v5);
-    dum = g_slist_append (NULL, e35);
-    dum = g_slist_append (dum,  e15);
-    GTS_OBJECT (e2)->reserved = dum;
-  }
-  if (GTS_OBJECT (e3)->reserved) {
-    dum = (GTS_OBJECT (e3)->reserved);
-    e16 = dum->data;
-    e26 = dum->next->data;
-    v6 = GTS_SEGMENT (e16)->v2;
-    if (GTS_SEGMENT (e16)->v1 == v2) {
-      edum = e16; e16 = e26; e26 = edum;
-    }
-  }
-  else {
-    v6 = (*refine_func) (e3, vertex_class, refine_data);
-    e16 = gts_edge_new (edge_class, v1, v6);
-    e26 = gts_edge_new (edge_class, v2, v6);
-    dum = g_slist_append (NULL, e16);
-    dum = g_slist_append (dum,  e26);
-    GTS_OBJECT (e3)->reserved = dum;
-  }
-  
-  if (e1->triangles == NULL) {
-    g_slist_free (GTS_OBJECT (e1)->reserved);
-    GTS_OBJECT (e1)->reserved = NULL;
-    gts_object_destroy (GTS_OBJECT (e1));
-    e1 = NULL;
-  }
-  if (e2->triangles == NULL) {
-    g_slist_free (GTS_OBJECT (e2)->reserved);
-    GTS_OBJECT (e2)->reserved = NULL;
-    gts_object_destroy (GTS_OBJECT (e2));
-    e2 = NULL;
-  }
-  if (e3->triangles == NULL) {
-    g_slist_free (GTS_OBJECT (e3)->reserved);
-    GTS_OBJECT (e3)->reserved = NULL;
-    gts_object_destroy (GTS_OBJECT (e3));
-    e3 = NULL;
-  }
-
-  e56 = gts_edge_new (edge_class, v5, v6);
-  e64 = gts_edge_new (edge_class, v6, v4);
-  e45 = gts_edge_new (edge_class, v4, v5);
-  t->e1 = e56; e56->triangles = g_slist_prepend (e56->triangles, t);
-  t->e2 = e64; e64->triangles = g_slist_prepend (e64->triangles, t);
-  t->e3 = e45; e45->triangles = g_slist_prepend (e45->triangles, t);
-  
-  gts_surface_add_face (s, gts_face_new (s->face_class, e16, e56, e15));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e26, e24, e64));
-  gts_surface_add_face (s, gts_face_new (s->face_class, e45, e34, e35)); 
-}
-
-static void create_array_tessellate (GtsFace * f, GPtrArray * array)
-{
-  g_ptr_array_add (array, f);
-}
-
-/**
- * gts_surface_tessellate:
- * @s: a #GtsSurface.
- * @refine_func: a #GtsRefineFunc.
- * @refine_data: user data to be passed to @refine_func.
- *
- * Tessellate each triangle of @s with 4 triangles:   
- * the number of triangles is increased by a factor of 4.
- * http://mathworld.wolfram.com/GeodesicDome.html
- *
- * If @refine_func is set to %NULL a mid arc function is used: if
- * the surface is a polyhedron with the unit sphere as circum sphere,
- * then gts_surface_tessellate() corresponds to a geodesation step
- * (see gts_surface_generate_sphere()).
- * 
- */
-void gts_surface_tessellate (GtsSurface * s,
-			     GtsRefineFunc refine_func,
-			     gpointer refine_data)
-{
-  GPtrArray * array;
-  guint i;
-
-  g_return_if_fail (s != NULL);
-  
-  if (refine_func == NULL) /* tessellate_surface == geodesate_surface */
-    refine_func = (GtsRefineFunc) unit_sphere_arc_midvertex;
-
-  array = g_ptr_array_new ();
-  gts_surface_foreach_face (s, (GtsFunc) create_array_tessellate, array);
-  for(i = 0; i < array->len; i++)
-    tessellate_face (g_ptr_array_index (array, i),
-		     s, refine_func, refine_data, 
-		     s->vertex_class, s->edge_class);
-  g_ptr_array_free (array, TRUE);
-}
-
-/**
- * gts_surface_generate_sphere:
- * @s: a #GtsSurface.
- * @geodesation_order: a #guint.
- *
- * Add a triangulated unit sphere generated by recursive subdivision to @s.
- * First approximation is an isocahedron; each level of refinement
- * (@geodesation_order) increases the number of triangles by a factor of 4.
- * http://mathworld.wolfram.com/GeodesicDome.html
- *
- * Returns: @s.
- */
-GtsSurface * gts_surface_generate_sphere (GtsSurface * s, 
-					  guint geodesation_order)
-{
-  guint cgo; 
-
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (geodesation_order != 0, NULL);
-
-  generate_icosahedron (s);
-
-  for (cgo = 1; cgo < geodesation_order; cgo++)
-    gts_surface_tessellate (s, NULL, NULL);
-  
-  return s;
-}
-
-static void foreach_vertex_copy (GtsPoint * p, GtsVertexClass * klass)
-{
-  GTS_OBJECT (p)->reserved = gts_vertex_new (klass, p->x, p->y, p->z);
-}
-
-static void foreach_edge_copy (GtsSegment * s, GtsEdgeClass * klass)
-{
-  GTS_OBJECT (s)->reserved = gts_edge_new (klass,
-					   GTS_OBJECT (s->v1)->reserved, 
-					   GTS_OBJECT (s->v2)->reserved);
-}
-
-static void foreach_face_copy (GtsTriangle * t,
-			       GtsSurface * s)
-{
-  gts_surface_add_face (s, gts_face_new (s->face_class,
-					 GTS_OBJECT (t->e1)->reserved,
-					 GTS_OBJECT (t->e2)->reserved,
-					 GTS_OBJECT (t->e3)->reserved));
-}
-
-/**
- * gts_surface_copy:
- * @s1: a #GtsSurface.
- * @s2: a #GtsSurface.
- *
- * Add a copy of all the faces, edges and vertices of @s2 to @s1.
- *
- * Returns: @s1.
- */
-GtsSurface * gts_surface_copy (GtsSurface * s1, GtsSurface * s2)
-{
-  g_return_val_if_fail (s1 != NULL, NULL);
-  g_return_val_if_fail (s2 != NULL, NULL);
-  
-  gts_surface_foreach_vertex (s2, (GtsFunc) foreach_vertex_copy, 
-			      s1->vertex_class);
-  gts_surface_foreach_edge (s2, (GtsFunc) foreach_edge_copy, s1->edge_class);
-  gts_surface_foreach_face (s2, (GtsFunc) foreach_face_copy, s1);
-
-  gts_surface_foreach_vertex (s2, (GtsFunc) gts_object_reset_reserved, NULL);
-  gts_surface_foreach_edge (s2, (GtsFunc) gts_object_reset_reserved, NULL);
-  
-  return s1;
-}
-
-static void merge_foreach_face (GtsFace * f, 
-				GtsSurface * s)
-{
-  gts_surface_add_face (s, f);
-}
-
-/**
- * gts_surface_merge:
- * @s: a #GtsSurface.
- * @with: another #GtsSurface.
- *
- * Adds all the faces of @with which do not already belong to @s
- * to @s.
- */
-void gts_surface_merge (GtsSurface * s, GtsSurface * with)
-{
-  g_return_if_fail (s != NULL);
-  g_return_if_fail (with != NULL);
-  
-  gts_surface_foreach_face (with, (GtsFunc) merge_foreach_face, s);
-}
-
-static void manifold_foreach_edge (GtsEdge * e, gpointer * data)
-{
-  gboolean * is_manifold = data[0];
-
-  if (*is_manifold) {
-    if (gts_edge_face_number (e, data[1]) > 2)
-      *is_manifold = FALSE;
-  }
-}
-
-/**
- * gts_surface_is_manifold:
- * @s: a #GtsSurface.
- *
- * Returns: %TRUE if the surface is a manifold, %FALSE otherwise.
- */
-gboolean gts_surface_is_manifold (GtsSurface * s)
-{
-  gboolean is_manifold = TRUE;
-  gpointer data[2];
-
-  g_return_val_if_fail (s != NULL, FALSE);
-
-  data[0] = &is_manifold;
-  data[1] = s;
-  gts_surface_foreach_edge (s, (GtsFunc) manifold_foreach_edge, data);
-  return is_manifold;
-}
-
-static void closed_foreach_edge (GtsEdge * e, gpointer * data)
-{
-  gboolean * is_closed = data[0];
-
-  if (*is_closed) {
-    if (gts_edge_face_number (e, data[1]) != 2)
-      *is_closed = FALSE;
-  }
-}
-
-/**
- * gts_surface_is_closed:
- * @s: a #GtsSurface.
- *
- * Returns: %TRUE if @s is a closed surface, %FALSE otherwise. Note that a
- * closed surface is also a manifold.
- */
-gboolean gts_surface_is_closed (GtsSurface * s)
-{
-  gboolean is_closed = TRUE;
-  gpointer data[2];
-
-  g_return_val_if_fail (s != NULL, FALSE);
-
-  data[0] = &is_closed;
-  data[1] = s;
-  gts_surface_foreach_edge (s, (GtsFunc) closed_foreach_edge, data);
-  return is_closed;
-}
-
-static void orientable_foreach_edge (GtsEdge * e, gpointer * data)
-{
-  gboolean * is_orientable = data[0];
-
-  if (*is_orientable) {
-    GtsSurface * surface = data[1];
-    GtsFace * f1 = NULL, * f2 = NULL;
-    GSList * i = e->triangles;
-    while (i && *is_orientable) {
-      GtsFace * f = i->data;
-      if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, surface)) {
-	if (!f1) f1 = f;
-	else if (!f2) f2 = f;
-	else *is_orientable = FALSE;
-      }
-      i = i->next;
-    }
-    if (f1 && f2 && !gts_triangles_are_compatible (GTS_TRIANGLE (f1), 
-						   GTS_TRIANGLE (f2), e))
-      *is_orientable = FALSE;
-  }
-}
-
-/**
- * gts_surface_is_orientable:
- * @s: a #GtsSurface.
- *
- * Returns: %TRUE if all the faces of @s have compatible orientation
- * as checked by gts_faces_are_compatible(), %FALSE otherwise. Note that
- * an orientable surface is also a manifold.
- */
-gboolean gts_surface_is_orientable (GtsSurface * s)
-{
-  gboolean is_orientable = TRUE;
-  gpointer data[2];
-
-  g_return_val_if_fail (s != NULL, FALSE);
-
-  data[0] = &is_orientable;
-  data[1] = s;
-  gts_surface_foreach_edge (s, (GtsFunc) orientable_foreach_edge, data);
-  return is_orientable;
-}
-
-static void volume_foreach_face (GtsTriangle * t,
-				 gdouble * volume)
-{
-  GtsVertex * va, * vb, * vc;
-  GtsPoint * pa, * pb, * pc;
-
-  gts_triangle_vertices (t, &va, &vb, &vc);
-  pa = GTS_POINT (va);
-  pb = GTS_POINT (vb);
-  pc = GTS_POINT (vc);
-  
-  *volume += (pa->x * (pb->y * pc->z - pb->z * pc->y) +
-	      pb->x * (pc->y * pa->z - pc->z * pa->y) +
-	      pc->x * (pa->y * pb->z - pa->z * pb->y));
-}
-
-/**
- * gts_surface_volume:
- * @s: a #GtsSurface.
- *
- * Returns: the signed volume of the domain bounded by the surface @s. It
- * makes sense only if @s is a closed and orientable manifold.
- */
-gdouble gts_surface_volume (GtsSurface * s)
-{
-  gdouble volume = 0.0;
-
-  g_return_val_if_fail (s != NULL, 0.0);
-
-  gts_surface_foreach_face (s, (GtsFunc) volume_foreach_face, &volume);
-
-  return volume/6.;
-}
-
-static void center_of_mass_foreach_face (GtsTriangle * t,
-					 gpointer * data)
-{
-  GtsVertex * v1, * v2, * v3;
-  GtsPoint * p1, * p2, * p3;
-  gdouble x1, y1, z1, x2, y2, z2, nx, ny, nz;
-  gdouble * volume = data[0];
-  gdouble * cm = data[1];
-
-  gts_triangle_vertices (t, &v1, &v2, &v3);
-  p1 = GTS_POINT (v1);
-  p2 = GTS_POINT (v2);
-  p3 = GTS_POINT (v3);
-
-  x1 = p2->x - p1->x;
-  y1 = p2->y - p1->y;
-  z1 = p2->z - p1->z;
-
-  x2 = p3->x - p1->x;
-  y2 = p3->y - p1->y;
-  z2 = p3->z - p1->z;
-  
-  nx = y1*z2 - z1*y2;
-  ny = z1*x2 - x1*z2;
-  nz = x1*y2 - y1*x2;
-
-  cm[0] += nx*(p1->x*p1->x + p2->x*p2->x + p3->x*p3->x + 
-	       p1->x*p2->x + p1->x*p3->x + p2->x*p3->x);
-  cm[1] += ny*(p1->y*p1->y + p2->y*p2->y + p3->y*p3->y + 
-	       p1->y*p2->y + p1->y*p3->y + p2->y*p3->y);
-  cm[2] += nz*(p1->z*p1->z + p2->z*p2->z + p3->z*p3->z + 
-	       p1->z*p2->z + p1->z*p3->z + p2->z*p3->z);
-
-  *volume += nx*(p1->x + p2->x + p3->x);
-}
-
-
-/**
- * gts_surface_center_of_mass:
- * @s: a #GtsSurface.
- * @cm: a #GtsVector.
- *
- * Fills @cm with the coordinates of the center of mass of @s.
- *
- * Returns: the signed volume of the domain bounded by the surface @s.
- */
-gdouble gts_surface_center_of_mass (GtsSurface * s,
-				    GtsVector cm)
-{
-  gdouble volume = 0.;
-  gpointer data[2];
-
-  g_return_val_if_fail (s != NULL, 0.0);
-
-  data[0] = &volume;
-  data[1] = &(cm[0]);
-  cm[0] = cm[1] = cm[2] = 0.;
-  gts_surface_foreach_face (s, (GtsFunc) center_of_mass_foreach_face, data);
-  
-  if (volume != 0.) {
-    cm[0] /= 4.*volume;
-    cm[1] /= 4.*volume;
-    cm[2] /= 4.*volume;
-  }
-
-  return volume/6.;
-}
-
-static void center_of_area_foreach_face (GtsTriangle * t,
-					 gpointer * data)
-{
-  GtsVertex * v1, * v2, * v3;
-  GtsPoint * p1, * p2, * p3;
-  gdouble a;
-  gdouble * area = data[0];
-  gdouble * cm = data[1];
-
-  gts_triangle_vertices (t, &v1, &v2, &v3);
-  p1 = GTS_POINT (v1);
-  p2 = GTS_POINT (v2);
-  p3 = GTS_POINT (v3);
-
-  a = gts_triangle_area (t);
-  cm[0] += a*(p1->x + p2->x + p3->x);
-  cm[1] += a*(p1->y + p2->y + p3->y);
-  cm[2] += a*(p1->z + p2->z + p3->z);
-  *area += a;
-}
-
-
-/**
- * gts_surface_center_of_area:
- * @s: a #GtsSurface.
- * @cm: a #GtsVector.
- *
- * Fills @cm with the coordinates of the center of area of @s.
- *
- * Returns: the area of surface @s.
- */
-gdouble gts_surface_center_of_area (GtsSurface * s,
-				    GtsVector cm)
-{
-  gdouble area = 0.;
-  gpointer data[2];
-
-  g_return_val_if_fail (s != NULL, 0.0);
-
-  data[0] = &area;
-  data[1] = &(cm[0]);
-  cm[0] = cm[1] = cm[2] = 0.;
-  gts_surface_foreach_face (s, (GtsFunc) center_of_area_foreach_face, data);
-  
-  if (area != 0.) {
-    cm[0] /= 3.*area;
-    cm[1] /= 3.*area;
-    cm[2] /= 3.*area;
-  }
-
-  return area;
-}
-
-static void number_foreach (gpointer data, guint * n)
-{
-  (*n)++;
-}
-
-/**
- * gts_surface_vertex_number:
- * @s: a #GtsSurface.
- *
- * Returns: the number of vertices of @s.
- */
-guint gts_surface_vertex_number (GtsSurface * s)
-{
-  guint n = 0;
-
-  g_return_val_if_fail (s != NULL, 0);
-
-  gts_surface_foreach_vertex (s, (GtsFunc) number_foreach, &n);
-
-  return n;
-}
-
-/**
- * gts_surface_edge_number:
- * @s: a #GtsSurface.
- *
- * Returns: the number of edges of @s.
- */
-guint gts_surface_edge_number (GtsSurface * s)
-{
-  guint n = 0;
-
-  g_return_val_if_fail (s != NULL, 0);
-
-  gts_surface_foreach_edge (s, (GtsFunc) number_foreach, &n);
-
-  return n;
-}
-
-/**
- * gts_surface_face_number:
- * @s: a #GtsSurface.
- *
- * Returns: the number of faces of @s
- */
-guint gts_surface_face_number (GtsSurface * s)
-{
-  g_return_val_if_fail (s != NULL, 0);
-
-#ifdef USE_SURFACE_BTREE
-  return g_tree_nnodes (s->faces);
-#else /* not USE_SURFACE_BTREE */
-  return g_hash_table_size (s->faces);
-#endif /* not USE_SURFACE_BTREE */
-}
-
-static void build_list_face (GtsTriangle * t, GSList ** list)
-{
-  *list = g_slist_prepend (*list, gts_bbox_triangle (gts_bbox_class (), t));
-}
-
-static void build_list_boundary (GtsEdge * e, GSList ** list)
-{
-  if (gts_edge_is_boundary (e, NULL))
-    *list = g_slist_prepend (*list, gts_bbox_segment (gts_bbox_class (),
-						      GTS_SEGMENT (e)));
-}
-
-/**
- * gts_surface_distance:
- * @s1: a #GtsSurface.
- * @s2: a #GtsSurface.
- * @delta: a spatial increment defined as the percentage of the diagonal
- * of the bounding box of @s2.
- * @face_range: a #GtsRange.
- * @boundary_range: a #GtsRange.
- *
- * Using the gts_bb_tree_surface_distance() and
- * gts_bb_tree_surface_boundary_distance() functions fills @face_range
- * and @boundary_range with the min, max and average Euclidean
- * (minimum) distances between the faces of @s1 and the faces of @s2
- * and between the boundary edges of @s1 and @s2.  
- */
-void gts_surface_distance (GtsSurface * s1, GtsSurface * s2, gdouble delta,
-			   GtsRange * face_range, GtsRange * boundary_range)
-{
-  GNode * face_tree, * boundary_tree;
-  GSList * bboxes;
-
-  g_return_if_fail (s1 != NULL);
-  g_return_if_fail (s2 != NULL);
-  g_return_if_fail (delta > 0. && delta < 1.);
-  g_return_if_fail (face_range != NULL);
-  g_return_if_fail (boundary_range != NULL);
-
-  bboxes = NULL;
-  gts_surface_foreach_face (s2, (GtsFunc) build_list_face, &bboxes);
-  if (bboxes != NULL) {
-    face_tree = gts_bb_tree_new (bboxes);
-    g_slist_free (bboxes);
-    
-    gts_bb_tree_surface_distance (face_tree, s1, 
-			       (GtsBBoxDistFunc) gts_point_triangle_distance,
-				  delta, face_range);
-    gts_bb_tree_destroy (face_tree, TRUE);
-    
-    bboxes = NULL;
-    gts_surface_foreach_edge (s2, (GtsFunc) build_list_boundary, &bboxes);
-    if (bboxes != NULL) {
-      boundary_tree = gts_bb_tree_new (bboxes);
-      g_slist_free (bboxes);
-
-      gts_bb_tree_surface_boundary_distance (boundary_tree,
-	       s1, 
-	       (GtsBBoxDistFunc) gts_point_segment_distance,
-	       delta, boundary_range);
-      gts_bb_tree_destroy (boundary_tree, TRUE);
-    }
-    else
-      gts_range_reset (boundary_range);
-  }
-  else {
-    gts_range_reset (face_range);
-    gts_range_reset (boundary_range);
-  }
-}
-
-static void surface_boundary (GtsEdge * e, gpointer * data)
-{
-  GSList ** list = data[0];
-
-  if (gts_edge_is_boundary (e, data[1]))
-    *list = g_slist_prepend (*list, e);
-}
-
-/**
- * gts_surface_boundary:
- * @surface: a #GtsSurface.
- *
- * Returns: a list of #GtsEdge boundary of @surface.
- */
-GSList * gts_surface_boundary (GtsSurface * surface)
-{
-  GSList * list = NULL;
-  gpointer data[2];
-
-  g_return_val_if_fail (surface != NULL, NULL);
-
-  data[0] = &list;
-  data[1] = surface;
-  gts_surface_foreach_edge (surface, (GtsFunc) surface_boundary, data);
-  
-  return list;
-}
-
-struct _GtsSurfaceTraverse {
-  GtsFifo * q;
-  GtsSurface * s;
-};
-
-/**
- * gts_surface_traverse_new:
- * @s: a #GtsSurface.
- * @f: a #GtsFace belonging to @s.
- *
- * Returns: a new #GtsSurfaceTraverse, initialized to start traversing
- * from face @f of surface @s.  
- */
-GtsSurfaceTraverse * gts_surface_traverse_new (GtsSurface * s,
-					       GtsFace * f)
-{
-  GtsSurfaceTraverse * t;
-
-  g_return_val_if_fail (s != NULL, NULL);
-  g_return_val_if_fail (f != NULL, NULL);
-  g_return_val_if_fail (gts_face_has_parent_surface (f, s), NULL);
-  
-  t = g_malloc (sizeof (GtsSurfaceTraverse));
-  t->q = gts_fifo_new ();
-  t->s = s;
-  GTS_OBJECT (f)->reserved = GUINT_TO_POINTER (1);
-  gts_fifo_push (t->q, f);
-  return t;
-}
-
-static void push_neighbor (GtsFace * v, gpointer * data)
-{
-  if (!GTS_OBJECT (v)->reserved) {
-    GTS_OBJECT (v)->reserved = 
-      GUINT_TO_POINTER (GPOINTER_TO_UINT (GTS_OBJECT (data[1])->reserved) + 1);
-    gts_fifo_push (data[0], v);
-  }
-}
-
-/**
- * gts_surface_traverse_next:
- * @t: a #GtsSurfaceTraverse.
- * @level: a pointer to a guint or %NULL.
- *
- * Returns: the next face of the traversal in breadth-first order or
- * %NULL if no faces are left. If @level if not %NULL, it is filled
- * with the level of the returned face (0 for the initial face, 1 for
- * its neighbors and so on).  
- */
-GtsFace * gts_surface_traverse_next (GtsSurfaceTraverse * t,
-				     guint * level)
-{
-  GtsFace * u;
-
-  g_return_val_if_fail (t != NULL, NULL);
-
-  u = gts_fifo_pop (t->q);
-  if (u) {
-    gpointer data[2];
-
-    if (level)
-      *level = GPOINTER_TO_UINT (GTS_OBJECT (u)->reserved);
-    data[0] = t->q;
-    data[1] = u;
-    gts_face_foreach_neighbor (u, t->s, (GtsFunc) push_neighbor, data);
-  }
-  return u;
-}
-
-/**
- * gts_surface_traverse_destroy:
- * @t: a #GtsSurfaceTraverse.
- *
- * Frees all the memory allocated for @t.
- */
-void gts_surface_traverse_destroy (GtsSurfaceTraverse * t)
-{
-  g_return_if_fail (t != NULL);
-
-  gts_surface_foreach_face (t->s, (GtsFunc) gts_object_reset_reserved, NULL);
-  gts_fifo_destroy (t->q);
-  g_free (t);
-}
-
-static void traverse_manifold (GtsTriangle * t, GtsSurface * s)
-{
-  if (g_slist_length (GTS_FACE (t)->surfaces) > 1)
-    return;
-
-  gts_surface_add_face (s, GTS_FACE (t));
-  if (g_slist_length (t->e1->triangles) == 2) {
-    if (t->e1->triangles->data != t)
-      traverse_manifold (t->e1->triangles->data, s);
-    else
-      traverse_manifold (t->e1->triangles->next->data, s);
-  }
-  if (g_slist_length (t->e2->triangles) == 2) {
-    if (t->e2->triangles->data != t)
-      traverse_manifold (t->e2->triangles->data, s);
-    else
-      traverse_manifold (t->e2->triangles->next->data, s);
-  }
-  if (g_slist_length (t->e3->triangles) == 2) {
-    if (t->e3->triangles->data != t)
-      traverse_manifold (t->e3->triangles->data, s);
-    else
-      traverse_manifold (t->e3->triangles->next->data, s);
-  }
-}
-
-static void non_manifold_edges (GtsEdge * e, gpointer * data)
-{
-  GtsSurface * s = data[0];
-  GSList ** non_manifold = data[1];
-
-  if (gts_edge_face_number (e, s) > 2) {
-    GSList * i = e->triangles;
-
-    while (i) {
-      if (gts_face_has_parent_surface (i->data, s) &&
-	  !g_slist_find (*non_manifold, i->data))
-	*non_manifold = g_slist_prepend (*non_manifold, i->data);
-      i = i->next;
-    }
-  }
-}
-
-static void traverse_boundary (GtsEdge * e, gpointer * data)
-{
-  GtsSurface * orig = data[0];
-  GSList ** components = data[1];
-  GtsFace * f = gts_edge_is_boundary (e, orig);
-
-  if (f != NULL && g_slist_length (f->surfaces) == 1) {
-    GtsSurface * s = 
-      gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (orig)->klass),
-		       orig->face_class,
-		       orig->edge_class,
-		       orig->vertex_class);
-    GSList * non_manifold = NULL, * i;
-    gpointer data[2];
-
-    *components = g_slist_prepend (*components, s);
-    data[0] = s;
-    data[1] = &non_manifold;
-    traverse_manifold (GTS_TRIANGLE (f), s);
-
-    gts_surface_foreach_edge (s, (GtsFunc) non_manifold_edges, data);
-    i = non_manifold;
-    while (i) {
-      gts_surface_remove_face (s, i->data);
-      i = i->next;
-    }
-    g_slist_free (non_manifold);
-  }
-}
-
-static void traverse_remaining (GtsFace * f, gpointer * data)
-{
-  GtsSurface * orig = data[0];
-  GSList ** components = data[1];
-
-  if (g_slist_length (f->surfaces) == 1) {
-    GtsSurface * s = 
-      gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (orig)->klass),
-		       orig->face_class,
-		       orig->edge_class,
-		       orig->vertex_class);
-    GSList * non_manifold = NULL, * i;
-    gpointer data[2];
-
-    *components = g_slist_prepend (*components, s);
-    data[0] = s;
-    data[1] = &non_manifold;
-    traverse_manifold (GTS_TRIANGLE (f), s);
-
-    gts_surface_foreach_edge (s, (GtsFunc) non_manifold_edges, data);
-    i = non_manifold;
-    while (i) {
-      gts_surface_remove_face (s, i->data);
-      i = i->next;
-    }
-    g_slist_free (non_manifold);
-  }
-}
-
-/**
- * gts_surface_split:
- * @s: a #GtsSurface.
- *
- * Splits a surface into connected and manifold components.
- * 
- * Returns: a list of new #GtsSurface.
- */
-GSList * gts_surface_split (GtsSurface * s)
-{
-  gpointer data[2];
-  GSList * components = NULL;
-
-  g_return_val_if_fail (s != NULL, NULL);
-
-  data[0] = s;
-  data[1] = &components;
-
-  /* boundary components */
-  gts_surface_foreach_edge (s, (GtsFunc) traverse_boundary, data);
-
-  /* remaining components */
-  gts_surface_foreach_face (s, (GtsFunc) traverse_remaining, data);
-
-  return components;
-}
diff --git a/src_3rd/gts/triangle.c b/src_3rd/gts/triangle.c
deleted file mode 100644
index 5213a51..0000000
--- a/src_3rd/gts/triangle.c
+++ /dev/null
@@ -1,1094 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include "gts.h"
-
-static void triangle_destroy (GtsObject * object)
-{
-  GtsTriangle * triangle = GTS_TRIANGLE (object);
-  GtsEdge * e1 = triangle->e1;
-  GtsEdge * e2 = triangle->e2;
-  GtsEdge * e3 = triangle->e3;
-
-  e1->triangles = g_slist_remove (e1->triangles, triangle);
-  if (!GTS_OBJECT_DESTROYED (e1) &&
-      !gts_allow_floating_edges && e1->triangles == NULL)
-    gts_object_destroy (GTS_OBJECT (e1));
-  
-  e2->triangles = g_slist_remove (e2->triangles, triangle);
-  if (!GTS_OBJECT_DESTROYED (e2) &&
-      !gts_allow_floating_edges && e2->triangles == NULL)
-    gts_object_destroy (GTS_OBJECT (e2));
-  
-  e3->triangles = g_slist_remove (e3->triangles, triangle);
-  if (!GTS_OBJECT_DESTROYED (e3) &&
-      !gts_allow_floating_edges && e3->triangles == NULL)
-    gts_object_destroy (GTS_OBJECT (e3));
-
-  (* GTS_OBJECT_CLASS (gts_triangle_class ())->parent_class->destroy) (object);
-}
-
-static void triangle_class_init (GtsObjectClass * klass)
-{
-  klass->destroy = triangle_destroy;
-}
-
-static void triangle_init (GtsTriangle * triangle)
-{
-  triangle->e1 = triangle->e2 = triangle->e3 = NULL;
-}
-
-/**
- * gts_triangle_class:
- *
- * Returns: the #GtsTriangleClass.
- */
-GtsTriangleClass * gts_triangle_class (void)
-{
-  static GtsTriangleClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo triangle_info = {
-      "GtsTriangle",
-      sizeof (GtsTriangle),
-      sizeof (GtsTriangleClass),
-      (GtsObjectClassInitFunc) triangle_class_init,
-      (GtsObjectInitFunc) triangle_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (gts_object_class (), 
-				  &triangle_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_triangle_set:
- * @triangle: a #GtsTriangle.
- * @e1: a #GtsEdge.
- * @e2: another #GtsEdge touching @e1.
- * @e3: another #GtsEdge touching both @e1 and @e2.
- *
- * Sets the edge of @triangle to @e1, @e2 and @e3 while checking that they
- * define a valid triangle.
- */
-void gts_triangle_set (GtsTriangle * triangle, 
-		       GtsEdge * e1, 
-		       GtsEdge * e2,
-		       GtsEdge * e3)
-{
-  g_return_if_fail (e1 != NULL);
-  g_return_if_fail (e2 != NULL);
-  g_return_if_fail (e3 != NULL);
-  g_return_if_fail (e1 != e2 && e1 != e3 && e2 != e3);
-
-  triangle->e1 = e1;
-  triangle->e2 = e2;
-  triangle->e3 = e3;
-
-  if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1)
-    g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), 
-					   GTS_SEGMENT (e1)->v2, 
-					   GTS_SEGMENT (e2)->v2));
-  else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1)
-    g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), 
-					   GTS_SEGMENT (e1)->v1, 
-					   GTS_SEGMENT (e2)->v2));
-  else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2)
-    g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), 
-					   GTS_SEGMENT (e1)->v1, 
-					   GTS_SEGMENT (e2)->v1));
-  else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2)
-    g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), 
-					   GTS_SEGMENT (e1)->v2, 
-					   GTS_SEGMENT (e2)->v1));
-  else
-    g_assert_not_reached ();
-
-  e1->triangles = g_slist_prepend (e1->triangles, triangle);
-  e2->triangles = g_slist_prepend (e2->triangles, triangle);
-  e3->triangles = g_slist_prepend (e3->triangles, triangle);
-}
-
-/**
- * gts_triangle_new:
- * @klass: a #GtsTriangleClass.
- * @e1: a #GtsEdge.
- * @e2: another #GtsEdge touching @e1.
- * @e3: another #GtsEdge touching both @e1 and @e2.
- *
- * Returns: a new #GtsTriangle having @e1, @e2 and @e3 as edges.
- */
-GtsTriangle * gts_triangle_new (GtsTriangleClass * klass,
-				GtsEdge * e1,
-				GtsEdge * e2,
-				GtsEdge * e3)
-{
-  GtsTriangle * t;
-
-  t = GTS_TRIANGLE (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  gts_triangle_set (t, e1, e2, e3);
-  
-  return t;
-}
-
-/**
- * gts_triangle_vertex_opposite:
- * @t: a #GtsTriangle.
- * @e: a #GtsEdge used by @t.
- *
- * This function fails if @e is not an edge of @t.
- * 
- * Returns: a #GtsVertex, vertex of @t which does not belong to @e.
- */
-GtsVertex * gts_triangle_vertex_opposite (GtsTriangle * t, GtsEdge * e)
-{
-  g_return_val_if_fail (t != NULL, NULL);
-  g_return_val_if_fail (e != NULL, NULL);
-
-  if (t->e1 == e) {
-    GtsVertex * v = GTS_SEGMENT (t->e2)->v1;
-    if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2)
-      return v;
-    return GTS_SEGMENT (t->e2)->v2;
-  }
-  if (t->e2 == e) {
-    GtsVertex * v = GTS_SEGMENT (t->e1)->v1;
-    if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2)
-      return v;
-    return GTS_SEGMENT (t->e1)->v2;
-  }
-  if (t->e3 == e) {
-    GtsVertex * v = GTS_SEGMENT (t->e2)->v1;
-    if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2)
-      return v;
-    return GTS_SEGMENT (t->e2)->v2;
-  }
-  g_assert_not_reached ();
-  return NULL;
-}
-
-/**
- * gts_triangle_edge_opposite:
- * @t: a #GtsTriangle.
- * @v: a #GtsVertex of @t.
- *
- * Returns: the edge of @t opposite @v or %NULL if @v is not a vertice of @t.
- */
-GtsEdge * gts_triangle_edge_opposite (GtsTriangle * t, GtsVertex * v)
-{
-  GtsSegment * s1, * s2, * s3;
-
-  g_return_val_if_fail (t != NULL, NULL);
-  g_return_val_if_fail (v != NULL, NULL);
-
-  s1 = GTS_SEGMENT (t->e1);
-  s2 = GTS_SEGMENT (t->e2);
-
-  if (s1->v1 != v && s1->v2 != v) {
-    if (s2->v1 != v && s2->v2 != v)
-      return NULL;
-    return t->e1;
-  }
-  if (s2->v1 != v && s2->v2 != v)
-    return t->e2;
-  s3 = GTS_SEGMENT (t->e3);
-  g_assert (s3->v1 != v && s3->v2 != v);
-  return t->e3;
-}
-
-/**
- * gts_triangles_angle:
- * @t1: a #GtsTriangle.
- * @t2: a #GtsTriangle.
- *
- * Returns: the value (in radians) of the angle between @t1 and @t2.
- */
-gdouble gts_triangles_angle (GtsTriangle * t1,
-			     GtsTriangle * t2)
-{
-  gdouble nx1, ny1, nz1, nx2, ny2, nz2;
-  gdouble pvx, pvy, pvz;
-  gdouble theta;
-
-  g_return_val_if_fail (t1 != NULL && t2 != NULL, 0.0);
-
-  gts_triangle_normal (t1, &nx1, &ny1, &nz1);
-  gts_triangle_normal (t2, &nx2, &ny2, &nz2);
-
-  pvx = ny1*nz2 - nz1*ny2;
-  pvy = nz1*nx2 - nx1*nz2;
-  pvz = nx1*ny2 - ny1*nx2;
-
-  theta = atan2 (sqrt (pvx*pvx + pvy*pvy + pvz*pvz), 
-		 nx1*nx2 + ny1*ny2 + nz1*nz2) - M_PI;
-  return theta < - M_PI ? theta + 2.*M_PI : theta;
-}
-
-/**
- * gts_triangles_are_compatible:
- * @t1: a #GtsTriangle.
- * @t2: a #GtsTriangle.
- * @e: a #GtsEdge used by both @t1 and @t2.
- *
- * Checks if @t1 and @t2 have compatible orientations i.e. if @t1 and
- * @t2 can be part of the same surface without conflict in the surface
- * normal orientation.
- *
- * Returns: %TRUE if @t1 and @t2 are compatible, %FALSE otherwise.
- */
-gboolean gts_triangles_are_compatible (GtsTriangle * t1, 
-				       GtsTriangle * t2,
-				       GtsEdge * e)
-{
-  GtsEdge * e1 = NULL, * e2 = NULL;
-
-  g_return_val_if_fail (t1 != NULL, FALSE);
-  g_return_val_if_fail (t2 != NULL, FALSE);
-  g_return_val_if_fail (e != NULL, FALSE);
-
-  if (t1->e1 == e) e1 = t1->e2;
-  else if (t1->e2 == e) e1 = t1->e3;
-  else if (t1->e3 == e) e1 = t1->e1;
-  else
-    g_assert_not_reached ();
-  if (t2->e1 == e) e2 = t2->e2;
-  else if (t2->e2 == e) e2 = t2->e3;
-  else if (t2->e3 == e) e2 = t2->e1;
-  else
-    g_assert_not_reached ();
-  if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1 || 
-      GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2 || 
-      GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1 || 
-      GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2)
-    return FALSE;
-  return TRUE;
-}
-
-/**
- * gts_triangle_area:
- * @t: a #GtsTriangle.
- *
- * Returns: the area of the triangle @t.
- */
-gdouble gts_triangle_area (GtsTriangle * t)
-{
-  gdouble x, y, z;
-  
-  g_return_val_if_fail (t != NULL, 0.0);
-  
-  gts_triangle_normal (t, &x, &y, &z);
-  
-  return sqrt (x*x + y*y + z*z)/2.;
-}
-
-/**
- * gts_triangle_perimeter:
- * @t: a #GtsTriangle.
- *
- * Returns: the perimeter of the triangle @t.
- */
-gdouble gts_triangle_perimeter (GtsTriangle * t)
-{
-  GtsVertex * v;
-
-  g_return_val_if_fail (t != NULL, 0.0);
-
-  v = gts_triangle_vertex (t);
-  return 
-    gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), 
-			GTS_POINT (GTS_SEGMENT (t->e1)->v2)) +
-    gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), 
-			GTS_POINT (v)) +
-    gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v2), 
-			GTS_POINT (v));
-}
-
-/* perimeter of the equilateral triangle of area unity */
-#define GOLDEN_PERIMETER 4.5590141139 
-
-/**
- * gts_triangle_quality:
- * @t: a #GtsTriangle.
- *
- * The quality of a triangle is defined as the ratio of the square
- * root of its surface area to its perimeter relative to this same
- * ratio for an equilateral triangle with the same area. The quality
- * is then one for an equilateral triangle and tends to zero for a
- * very stretched triangle.
- *
- * Returns: the quality of the triangle @t.
- */
-gdouble gts_triangle_quality (GtsTriangle * t)
-{
-  gdouble perimeter;
-
-  g_return_val_if_fail (t != NULL, 0.0);
-
-  perimeter = gts_triangle_perimeter (t);
-  return perimeter > 0.0 ?
-    GOLDEN_PERIMETER*sqrt (gts_triangle_area (t))/perimeter :
-    0.0;
-}
-
-/**
- * gts_triangle_normal:
- * @t: a #GtsTriangle.
- * @x: the x coordinate of the normal.
- * @y: the y coordinate of the normal.
- * @z: the z coordinate of the normal.
- *
- * Computes the coordinates of the oriented normal of @t as the
- * cross-product of two edges, using the left-hand rule. The normal is
- * not normalized.  If this triangle is part of a closed and oriented
- * surface, the normal points to the outside of the surface.  
- */
-void gts_triangle_normal (GtsTriangle * t, 
-			  gdouble * x, 
-			  gdouble * y, 
-			  gdouble * z)
-{
-  GtsVertex * v1, * v2 = NULL, * v3 = NULL;
-  GtsPoint * p1, * p2, * p3;
-  gdouble x1, y1, z1, x2, y2, z2;
-
-  g_return_if_fail (t != NULL);
-
-  v1 = GTS_SEGMENT (t->e1)->v1;
-  if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) {
-    v2 = GTS_SEGMENT (t->e2)->v2;
-    v3 = GTS_SEGMENT (t->e1)->v2;
-  }
-  else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) {
-    v2 = GTS_SEGMENT (t->e1)->v2;
-    v3 = GTS_SEGMENT (t->e2)->v1;
-  }
-  else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) {
-    v2 = GTS_SEGMENT (t->e2)->v1;
-    v3 = GTS_SEGMENT (t->e1)->v2;
-  }
-  else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) {
-    v2 = GTS_SEGMENT (t->e1)->v2;
-    v3 = GTS_SEGMENT (t->e2)->v2;
-  }
-  else {
-    fprintf (stderr, "t: %p t->e1: %p t->e2: %p t->e3: %p t->e1->v1: %p t->e1->v2: %p t->e2->v1: %p t->e2->v2: %p t->e3->v1: %p t->e3->v2: %p\n",
-	 t, t->e1, t->e2, 
-	 t->e3, GTS_SEGMENT (t->e1)->v1, GTS_SEGMENT (t->e1)->v2, 
-	 GTS_SEGMENT (t->e2)->v1, GTS_SEGMENT (t->e2)->v2, 
-	 GTS_SEGMENT (t->e3)->v1, GTS_SEGMENT (t->e3)->v2);
-    g_assert_not_reached ();
-  }
-
-  p1 = GTS_POINT (v1);
-  p2 = GTS_POINT (v2);
-  p3 = GTS_POINT (v3);
-
-  x1 = p2->x - p1->x;
-  y1 = p2->y - p1->y;
-  z1 = p2->z - p1->z;
-
-  x2 = p3->x - p1->x;
-  y2 = p3->y - p1->y;
-  z2 = p3->z - p1->z;
-
-  *x = y1*z2 - z1*y2;
-  *y = z1*x2 - x1*z2;
-  *z = x1*y2 - y1*x2;
-}
-
-/**
- * gts_triangle_orientation:
- * @t: a #GtsTriangle.
- * 
- * Checks for the orientation of the plane (x,y) projection of a
- * triangle. See gts_point_orientation() for details. This function
- * is geometrically robust.
- *
- * Returns: a number depending on the orientation of the vertices of @t.
- */
-gdouble gts_triangle_orientation (GtsTriangle * t)
-{
-  GtsVertex * v1, * v2 = NULL, * v3 = NULL;
-
-  g_return_val_if_fail (t != NULL, 0.0);
-
-  v1 = GTS_SEGMENT (t->e1)->v1;
-  if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) {
-    v2 = GTS_SEGMENT (t->e2)->v2;
-    v3 = GTS_SEGMENT (t->e1)->v2;
-  }
-  else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) {
-    v2 = GTS_SEGMENT (t->e1)->v2;
-    v3 = GTS_SEGMENT (t->e2)->v1;
-  }
-  else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) {
-    v2 = GTS_SEGMENT (t->e2)->v1;
-    v3 = GTS_SEGMENT (t->e1)->v2;
-  }
-  else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) {
-    v2 = GTS_SEGMENT (t->e1)->v2;
-    v3 = GTS_SEGMENT (t->e2)->v2;
-  }
-  else
-    g_assert_not_reached ();
-  return gts_point_orientation (GTS_POINT (v1), 
-				GTS_POINT (v2), 
-				GTS_POINT (v3));
-}
-
-/**
- * gts_triangle_revert:
- * @t: a #GtsTriangle.
- * 
- * Changes the orientation of triangle @t, turning it inside out.
- */
-void gts_triangle_revert (GtsTriangle * t)
-{
-  GtsEdge * e;
-
-  g_return_if_fail (t != NULL);
-
-  e = t->e1;
-  t->e1 = t->e2;
-  t->e2 = e;
-}
-
-/**
- * gts_triangles_from_edges:
- * @edges: a list of #GtsEdge.
- *
- * Builds a list of unique triangles which have one of their edges in @edges.
- * 
- * Returns: the list of triangles.
- */
-GSList * gts_triangles_from_edges (GSList * edges)
-{
-  GHashTable * hash;
-  GSList * triangles = NULL, * i;
-
-  hash = g_hash_table_new (NULL, NULL);
-  i = edges;
-  while (i) {
-    GSList * j = GTS_EDGE (i->data)->triangles;
-    while (j) {
-      GtsTriangle * t = j->data;
-      if (g_hash_table_lookup (hash, t) == NULL) {
-	triangles = g_slist_prepend (triangles, t);
-	g_hash_table_insert (hash, t, i);
-      }
-      j = j->next;
-    }
-    i = i->next;
-  }
-  g_hash_table_destroy (hash);
-
-  return triangles;
-}
-
-/**
- * gts_triangle_vertices_edges:
- * @t: a #GtsTriangle.
- * @e: a #GtsEdge belonging to the edges of @t or %NULL.
- * @v1: a #GtsVertex used by @t.
- * @v2: a #GtsVertex used by @t.
- * @v3: a #GtsVertex used by @t.
- * @e1: a #GtsEdge used by @t.
- * @e2: a #GtsEdge used by @t.
- * @e3: a #GtsEdge used by @t.
- *
- * Given @t and @e, returns @v1, @v2, @v3, @e1, @e2 and @e3. @e1
- * has @v1 and @v2 as vertices, @e2 has @v2 and @v3 as vertices
- * and @e3 has @v3 and @v1 as vertices. @v1, @v2 and @v3 respects
- * the orientation of @t. If @e is not NULL, @e1 and @e are
- * identical.
- */
-void gts_triangle_vertices_edges (GtsTriangle * t, 
-				  GtsEdge * e,
-				  GtsVertex ** v1, 
-				  GtsVertex ** v2, 
-				  GtsVertex ** v3,
-				  GtsEdge ** e1,
-				  GtsEdge ** e2,
-				  GtsEdge ** e3)
-{
-  GtsEdge * ee1, * ee2;
-
-  g_return_if_fail (t != NULL);
-  
-  if (e == t->e1 || e == NULL) {
-    *e1 = ee1 = t->e1; *e2 = ee2 = t->e2; *e3 = t->e3;    
-  }
-  else if (e == t->e2) {
-    *e1 = ee1 = e; *e2 = ee2 = t->e3; *e3 = t->e1;
-  }
-  else if (e == t->e3) {
-    *e1 = ee1 = e; *e2 = ee2 = t->e1; *e3 = t->e2;
-  }
-  else {
-    g_assert_not_reached ();
-    ee1 = ee2 = NULL; /* to avoid complaints from the compiler */
-  }
-  if (GTS_SEGMENT (ee1)->v2 == GTS_SEGMENT (ee2)->v1) {
-    *v1 = GTS_SEGMENT (ee1)->v1; 
-    *v2 = GTS_SEGMENT (ee1)->v2; 
-    *v3 = GTS_SEGMENT (ee2)->v2;
-  }
-  else if (GTS_SEGMENT (ee1)->v2 == GTS_SEGMENT (ee2)->v2) {
-    *v1 = GTS_SEGMENT (ee1)->v1; 
-    *v2 = GTS_SEGMENT (ee1)->v2; 
-    *v3 = GTS_SEGMENT (ee2)->v1;
-  }
-  else if (GTS_SEGMENT (ee1)->v1 == GTS_SEGMENT (ee2)->v1) {
-    *v1 = GTS_SEGMENT (ee1)->v2; 
-    *v2 = GTS_SEGMENT (ee1)->v1; 
-    *v3 = GTS_SEGMENT (ee2)->v2;
-  }
-  else if (GTS_SEGMENT (ee1)->v1 == GTS_SEGMENT (ee2)->v2) {
-    *v1 = GTS_SEGMENT (ee1)->v2; 
-    *v2 = GTS_SEGMENT (ee1)->v1; 
-    *v3 = GTS_SEGMENT (ee2)->v1;
-  }
-  else
-    g_assert_not_reached ();
-}
-
-/* sqrt(3) */
-#define SQRT3 1.73205080757
-
-/**
- * gts_triangle_enclosing:
- * @klass: the class of the new triangle.
- * @points: a list of #GtsPoint.
- * @scale: a scaling factor (must be larger than one).
- * 
- * Builds a new triangle (including new vertices and edges) enclosing
- * the plane projection of all the points in @points. This triangle is
- * equilateral and encloses a rectangle defined by the maximum and
- * minimum x and y coordinates of the points. @scale is an homothetic
- * scaling factor. If equal to one, the triangle encloses exactly the
- * enclosing rectangle.
- * 
- * Returns: a new #GtsTriangle.  
- */
-GtsTriangle * gts_triangle_enclosing (GtsTriangleClass * klass,
-				      GSList * points, gdouble scale)
-{
-  gdouble xmax, xmin, ymax, ymin;
-  gdouble xo, yo, r;
-  GtsVertex * v1, * v2, * v3;
-  GtsEdge * e1, * e2, * e3;
-
-  if (points == NULL)
-    return NULL;
-  
-  xmax = xmin = GTS_POINT (points->data)->x;
-  ymax = ymin = GTS_POINT (points->data)->y;
-  points = points->next;
-  while (points) {
-    GtsPoint * p = points->data;
-    if (p->x > xmax) xmax = p->x;
-    else if (p->x < xmin) xmin = p->x;
-    if (p->y > ymax) ymax = p->y;
-    else if (p->y < ymin) ymin = p->y;    
-    points = points->next;
-  }
-  xo = (xmax + xmin)/2.;
-  yo = (ymax + ymin)/2.;
-  r = scale*sqrt((xmax - xo)*(xmax - xo) + (ymax - yo)*(ymax - yo));
-  if (r == 0.0) r = scale;
-  v1 = gts_vertex_new (gts_vertex_class (),
-		       xo + r*SQRT3, yo - r, 0.0);
-  v2 = gts_vertex_new (gts_vertex_class (),
-		       xo, yo + 2.*r, 0.0);
-  v3 = gts_vertex_new (gts_vertex_class (),
-		       xo - r*SQRT3, yo - r, 0.0);
-  e1 = gts_edge_new (gts_edge_class (), v1, v2);
-  e2 = gts_edge_new (gts_edge_class (), v2, v3);
-  e3 = gts_edge_new (gts_edge_class (), v3, v1);
-  return gts_triangle_new (gts_triangle_class (), e1, e2, e3);
-}
-
-/**
- * gts_triangle_neighbor_number:
- * @t: a #GtsTriangle.
- *
- * Returns: the number of triangles neighbors of @t.
- */
-guint gts_triangle_neighbor_number (GtsTriangle * t)
-{
-  GSList * i;
-  guint nn = 0;
-  GtsEdge * ee[4], ** e = ee;
-  
-  g_return_val_if_fail (t != NULL, 0);
-
-  ee[0] = t->e1; ee[1] = t->e2; ee[2] = t->e3; ee[3] = NULL;
-  while (*e) {
-    i = (*e++)->triangles;
-    while (i) {
-      GtsTriangle * t1 = i->data;
-      if (t1 != t)
-	nn++;
-      i = i->next;
-    }
-  }
-  return nn;
-}
-
-/**
- * gts_triangle_neighbors:
- * @t: a #GtsTriangle.
- *
- * Returns: a list of #GtsTriangle neighbors of @t.
- */
-GSList * gts_triangle_neighbors (GtsTriangle * t)
-{
-  GSList * i, * list = NULL;
-  GtsEdge * ee[4], ** e = ee;
-  
-  g_return_val_if_fail (t != NULL, NULL);
-
-  ee[0] = t->e1; ee[1] = t->e2; ee[2] = t->e3; ee[3] = NULL;
-  while (*e) {
-    i = (*e++)->triangles;
-    while (i) {
-      GtsTriangle * t1 = i->data;
-      if (t1 != t)
-	list = g_slist_prepend (list, t1);
-      i = i->next;
-    }
-  }
-  return list;
-}
-
-/**
- * gts_triangles_common_edge:
- * @t1: a #GtsTriangle.
- * @t2: a #GtsTriangle.
- *
- * Returns: a #GtsEdge common to both @t1 and @t2 or %NULL if @t1 and @t2
- * do not share any edge.
- */
-GtsEdge * gts_triangles_common_edge (GtsTriangle * t1,
-				     GtsTriangle * t2)
-{
-  g_return_val_if_fail (t1 != NULL, NULL);
-  g_return_val_if_fail (t2 != NULL, NULL);
-
-  if (t1->e1 == t2->e1 || t1->e1 == t2->e2 || t1->e1 == t2->e3)
-    return t1->e1;
-  if (t1->e2 == t2->e1 || t1->e2 == t2->e2 || t1->e2 == t2->e3)
-    return t1->e2;
-  if (t1->e3 == t2->e1 || t1->e3 == t2->e2 || t1->e3 == t2->e3)
-    return t1->e3;
-  return NULL;
-}
-
-/**
- * gts_triangle_is_duplicate:
- * @t: a #GtsTriangle.
- *
- * Returns: a #GtsTriangle different from @t but sharing all its edges 
- * with @t or %NULL if there is none.
- */
-GtsTriangle * gts_triangle_is_duplicate (GtsTriangle * t)
-{
-  GSList * i;
-  GtsEdge * e2, * e3;
-
-  g_return_val_if_fail (t != NULL, NULL);
-
-  e2 = t->e2;
-  e3 = t->e3;
-  i = t->e1->triangles;
-  while (i) {
-    GtsTriangle * t1 = i->data;
-    if (t1 != t && 
-	(t1->e1 == e2 || t1->e2 == e2 || t1->e3 == e2) &&
-	(t1->e1 == e3 || t1->e2 == e3 || t1->e3 == e3))
-      return t1;
-    i = i->next;
-  }
-  
-  return NULL;
-}
-
-/**
- * gts_triangle_use_edges:
- * @e1: a #GtsEdge.
- * @e2: a #GtsEdge.
- * @e3: a #GtsEdge.
- *
- * Returns: a #GtsTriangle having @e1, @e2 and @e3 as edges or %NULL if @e1,
- * @e2 and @e3 are not part of any triangle.
- */
-GtsTriangle * gts_triangle_use_edges (GtsEdge * e1,
-				      GtsEdge * e2,
-				      GtsEdge * e3)
-{
-  GSList * i;
-  
-  g_return_val_if_fail (e1 != NULL, NULL);
-  g_return_val_if_fail (e2 != NULL, NULL);
-  g_return_val_if_fail (e3 != NULL, NULL);
-
-  i = e1->triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    if ((t->e1 == e2 && (t->e2 == e3 || t->e3 == e3)) ||
-	(t->e2 == e2 && (t->e1 == e3 || t->e3 == e3)) ||
-	(t->e3 == e2 && (t->e1 == e3 || t->e2 == e3)))
-      return t;
-    i = i->next;
-  }
-  
-  return NULL;
-}
-
-/**
- * gts_triangle_is_ok:
- * @t: a #GtsTriangle.
- *
- * Returns: %TRUE if @t is a non-degenerate, non-duplicate triangle,
- * %FALSE otherwise.
- */
-gboolean gts_triangle_is_ok (GtsTriangle * t)
-{
-  g_return_val_if_fail (t != NULL, FALSE);
-  g_return_val_if_fail (t->e1 != NULL, FALSE);
-  g_return_val_if_fail (t->e2 != NULL, FALSE);
-  g_return_val_if_fail (t->e3 != NULL, FALSE);
-  g_return_val_if_fail (t->e1 != t->e2 && t->e1 != t->e3 && t->e2 != t->e3, 
-			FALSE);
-  g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1), 
-					    GTS_SEGMENT (t->e2)),
-			FALSE);
-  g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1), 
-					    GTS_SEGMENT (t->e3)), 
-			FALSE);
-  g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e2), 
-					    GTS_SEGMENT (t->e3)), 
-			FALSE);
-  g_return_val_if_fail (GTS_SEGMENT (t->e1)->v1 != GTS_SEGMENT (t->e1)->v2, 
-			FALSE);
-  g_return_val_if_fail (GTS_SEGMENT (t->e2)->v1 != GTS_SEGMENT (t->e2)->v2, 
-			FALSE);
-  g_return_val_if_fail (GTS_SEGMENT (t->e3)->v1 != GTS_SEGMENT (t->e3)->v2, 
-			FALSE);
-  g_return_val_if_fail (GTS_OBJECT (t)->reserved == NULL, FALSE);
-  g_return_val_if_fail (!gts_triangle_is_duplicate (t), FALSE);
-  return TRUE;
-}
-
-/**
- * gts_triangle_vertices:
- * @t: a #GtsTriangle.
- * @v1: a pointer on a #GtsVertex.
- * @v2: a pointer on a #GtsVertex.
- * @v3: a pointer on a #GtsVertex.
- *
- * Fills @v1, @v2 and @v3 with the oriented set of vertices, summits of @t.
- */
-void gts_triangle_vertices (GtsTriangle * t,
-			    GtsVertex ** v1, GtsVertex ** v2, GtsVertex ** v3)
-{
-  GtsSegment * e1, * e2;
-
-  g_return_if_fail (t != NULL);
-  g_return_if_fail (v1 != NULL && v2 != NULL && v3 != NULL);
-
-  e1 = GTS_SEGMENT (t->e1);
-  e2 = GTS_SEGMENT (t->e2);
-
-  if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) {
-    *v1 = GTS_SEGMENT (e1)->v1; 
-    *v2 = GTS_SEGMENT (e1)->v2; 
-    *v3 = GTS_SEGMENT (e2)->v2;
-  }
-  else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) {
-    *v1 = GTS_SEGMENT (e1)->v1; 
-    *v2 = GTS_SEGMENT (e1)->v2; 
-    *v3 = GTS_SEGMENT (e2)->v1;
-  }
-  else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) {
-    *v1 = GTS_SEGMENT (e1)->v2; 
-    *v2 = GTS_SEGMENT (e1)->v1; 
-    *v3 = GTS_SEGMENT (e2)->v2;
-  }
-  else {
-    *v1 = GTS_SEGMENT (e1)->v2; 
-    *v2 = GTS_SEGMENT (e1)->v1; 
-    *v3 = GTS_SEGMENT (e2)->v1;
-  }
-}
-
-/**
- * gts_triangle_circumcircle_center:
- * @t: a #GtsTriangle.
- * @point_class: a #GtsPointClass.
- *
- * Returns: a new #GtsPoint, center of the circumscribing circle of @t or
- * %NULL if the circumscribing circle is not defined.
- */
-GtsPoint * gts_triangle_circumcircle_center (GtsTriangle * t,
-					     GtsPointClass * point_class)
-{
-  GtsVertex * v1, * v2, * v3;
-  gdouble xa, ya, xb, yb, xc, yc;
-  gdouble xd, yd, xe, ye;
-  gdouble xad, yad, xae, yae;
-  gdouble det;
-  
-  g_return_val_if_fail (t != NULL, NULL);
-  g_return_val_if_fail (point_class != NULL, NULL);
-
-  gts_triangle_vertices (t, &v1, &v2, &v3);
-
-  xa = GTS_POINT (v1)->x; ya = GTS_POINT (v1)->y;
-  xb = GTS_POINT (v2)->x; yb = GTS_POINT (v2)->y;
-  xc = GTS_POINT (v3)->x; yc = GTS_POINT (v3)->y;
-  xd = (xa + xb)/2.; yd = (ya + yb)/2.;
-  xe = (xa + xc)/2.; ye = (ya + yc)/2.;
-  xad = xd - xa; yad = yd - ya;
-  xae = xe - xa; yae = ye - ya;
-  det = xad*yae - xae*yad;
-  if (det == 0.)
-    return NULL;
-  return gts_point_new (point_class,
-			(yae*yad*(yd - ye) + xad*yae*xd - xae*yad*xe)/det,
-			-(xae*xad*(xd - xe) + yad*xae*yd - yae*xad*ye)/det,
-			0.);
-}
-
-/* square of the maximum area ratio admissible */
-#define AREA_RATIO_MAX2 1e8
-
-static gboolean points_are_folded (GtsPoint * A,
-				   GtsPoint * B,
-				   GtsPoint * C,
-				   GtsPoint * D,
-				   gdouble max)
-{
-  GtsVector AB, AC, AD;
-  GtsVector n1, n2;
-  gdouble nn1, nn2, n1n2;
-
-  gts_vector_init (AB, A, B);
-  gts_vector_init (AC, A, C);
-  gts_vector_init (AD, A, D);
-  gts_vector_cross (n1, AB, AC);
-  gts_vector_cross (n2, AD, AB);
-
-  nn1 = gts_vector_scalar (n1, n1);
-  nn2 = gts_vector_scalar (n2, n2);
-  if (nn1 >= AREA_RATIO_MAX2*nn2 || nn2 >= AREA_RATIO_MAX2*nn1)
-    return TRUE;
-  n1n2 = gts_vector_scalar (n1, n2);
-  if (n1n2 > 0.)
-    return FALSE;
-  if (n1n2*n1n2/(nn1*nn2) > max)
-    return TRUE;
-  return FALSE;
-}
-
-static GtsVertex * triangle_use_vertices (GtsTriangle * t,
-					  GtsVertex * A, 
-					  GtsVertex * B)
-{
-  GtsVertex 
-    * v1 = GTS_SEGMENT (t->e1)->v1, 
-    * v2 = GTS_SEGMENT (t->e1)->v2, 
-    * v3 = gts_triangle_vertex (t);
-
-  if (v1 == A) {
-    if (v2 == B)
-      return v3;
-    g_assert (v3 == B);
-    return v2;
-  }
-  if (v2 == A) {
-    if (v1 == B)
-      return v3;
-    g_assert (v3 == B);
-    return v1;
-  }
-  if (v3 == A) {
-    if (v1 == B)
-      return v2;
-    g_assert (v2 == B);
-    return v1;
-  }
-  g_assert_not_reached ();
-  return NULL;
-}
-
-/**
- * gts_triangles_are_folded:
- * @triangles: a list of #GtsTriangle.
- * @A: a #GtsVertex.
- * @B: another #GtsVertex.
- * @max: the maximum value of the square of the cosine of the angle between
- * two triangles.
- *
- * Given a list of triangles sharing @A and @B as vertices, checks if any
- * two triangles in the list make an angle larger than a given value defined
- * by @max.
- * 
- * Returns: %TRUE if any pair of triangles in @triangles makes an angle larger 
- * than the maximum value, %FALSE otherwise.
- */
-gboolean gts_triangles_are_folded (GSList * triangles,
-				   GtsVertex * A, GtsVertex * B,
-				   gdouble max)
-{
-  GSList * i;
-
-  g_return_val_if_fail (A != NULL, TRUE);
-  g_return_val_if_fail (B != NULL, TRUE);
-
-  i = triangles;
-  while (i) {
-    GtsVertex * C = triangle_use_vertices (i->data, A, B);
-    GSList * j = i->next;    
-    while (j) {
-      GtsVertex * D = triangle_use_vertices (j->data, A, B);
-      if (points_are_folded (GTS_POINT (A), 
-			     GTS_POINT (B), 
-			     GTS_POINT (C), 
-			     GTS_POINT (D), 
-			     max))
-	return TRUE;
-      j = j->next;
-    }
-    i = i->next;
-  }
-  return FALSE;
-}
-
-/**
- * gts_triangle_is_stabbed:
- * @t: a #GtsTriangle.
- * @p: a #GtsPoint.
- * @orientation: a pointer or %NULL.
- *
- * Returns: one of the vertices of @t, one of the edges of @t or @t if
- * any of these are stabbed by the ray starting at @p (included) and
- * ending at (@p->x, @p->y, +infty), %NULL otherwise. If the ray is
- * contained in the plane of the triangle %NULL is also returned. If
- * @orientation is not %NULL, it is set to the value of the
- * orientation of @p relative to @t (as given by
- * gts_point_orientation_3d()).  
- */
-GtsObject * gts_triangle_is_stabbed (GtsTriangle * t, 
-				     GtsPoint * p,
-				     gdouble * orientation)
-{
-  GtsVertex * v1, * v2, * v3, * inverted = NULL;
-  GtsEdge * e1, * e2, * e3, * tmp;
-  gdouble o, o1, o2, o3;
-
-  g_return_val_if_fail (t != NULL, NULL);
-  g_return_val_if_fail (p != NULL, NULL);
-
-  gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3);
-  o = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3));
-  if (o == 0.)
-    return NULL;
-  if (o < 0.) {
-    inverted = v1;
-    v1 = v2;
-    v2 = inverted;
-    tmp = e2;
-    e2 = e3;
-    e3 = tmp;
-  }
-  o = gts_point_orientation_3d (GTS_POINT (v1),
-				GTS_POINT (v2), 
-				GTS_POINT (v3), 
-				p);
-  if (o < 0.)
-    return NULL;
-  o1 = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p);
-  if (o1 < 0.)
-    return NULL;
-  o2 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p);
-  if (o2 < 0.)
-    return NULL;
-  o3 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p);
-  if (o3 < 0.)
-    return NULL;  
-  if (orientation) *orientation = inverted ? -o : o;
-  if (o1 == 0.) {
-    if (o2 == 0.)
-      return GTS_OBJECT (v2);
-    if (o3 == 0.)
-      return GTS_OBJECT (v1);
-    return GTS_OBJECT (e1);
-  }
-  if (o2 == 0.) {
-    if (o3 == 0.)
-      return GTS_OBJECT (v3);
-    return GTS_OBJECT (e2);
-  }
-  if (o3 == 0.)
-    return GTS_OBJECT (e3);
-  return GTS_OBJECT (t);
-}
-
-/**
- * gts_triangle_interpolate_height:
- * @t: a #GtsTriangle.
- * @p: a #GtsPoint.
- *
- * Fills the z-coordinate of point @p belonging to the plane
- * projection of triangle @t with the linearly interpolated value of
- * the z-coordinates of the vertices of @t.
- */
-void gts_triangle_interpolate_height (GtsTriangle * t, GtsPoint * p)
-{
-  GtsPoint * p1, * p2, * p3;
-  gdouble x1, x2, y1, y2, det;
-
-  g_return_if_fail (t != NULL);
-  g_return_if_fail (p != NULL);
-
-  p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
-  p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-  p3 = GTS_POINT (gts_triangle_vertex (t));
-
-  x1 = p2->x - p1->x;
-  y1 = p2->y - p1->y;
-  x2 = p3->x - p1->x;
-  y2 = p3->y - p1->y;
-  det = x1*y2 - x2*y1;
-  if (det == 0.)
-    p->z = (p1->z + p2->z + p3->z)/3.;
-  else {
-    gdouble x = p->x - p1->x;
-    gdouble y = p->y - p1->y;
-    gdouble a = (x*y2 - y*x2)/det;
-    gdouble b = (y*x1 - x*y1)/det;
-
-    p->z = (1. - a - b)*p1->z + a*p2->z + b*p3->z;
-  }
-}
diff --git a/src_3rd/gts/tribox3.c b/src_3rd/gts/tribox3.c
deleted file mode 100644
index c0ea778..0000000
--- a/src_3rd/gts/tribox3.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * History:
- * 2004-10-27 Stephane Popinet: changed float to double
- */
-
-/********************************************************/
-/* AABB-triangle overlap test code                      */
-/* by Tomas Akenine-M�ller                              */
-/* Function: int triBoxOverlap(float boxcenter[3],      */
-/*          float boxhalfsize[3],float triverts[3][3]); */
-/* History:                                             */
-/*   2001-03-05: released the code in its first version */
-/*   2001-06-18: changed the order of the tests, faster */
-/*                                                      */
-/* Acknowledgement: Many thanks to Pierre Terdiman for  */
-/* suggestions and discussions on how to optimize code. */
-/* Thanks to David Hunt for finding a ">="-bug!         */
-/********************************************************/
-#include <math.h>
-#include <stdio.h>
-
-#define X 0
-#define Y 1
-#define Z 2
-
-#define CROSS(dest,v1,v2) \
-          dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
-          dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
-          dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; 
-
-#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
-
-#define SUB(dest,v1,v2) \
-          dest[0]=v1[0]-v2[0]; \
-          dest[1]=v1[1]-v2[1]; \
-          dest[2]=v1[2]-v2[2]; 
-
-#define FINDMINMAX(x0,x1,x2,min,max) \
-  min = max = x0;   \
-  if(x1<min) min=x1;\
-  if(x1>max) max=x1;\
-  if(x2<min) min=x2;\
-  if(x2>max) max=x2;
-
-int planeBoxOverlap(double normal[3], double vert[3], double maxbox[3])	// -NJMP-
-{
-  int q;
-  double vmin[3],vmax[3],v;
-  for(q=X;q<=Z;q++)
-  {
-    v=vert[q];					// -NJMP-
-    if(normal[q]>0.0f)
-    {
-      vmin[q]=-maxbox[q] - v;	// -NJMP-
-      vmax[q]= maxbox[q] - v;	// -NJMP-
-    }
-    else
-    {
-      vmin[q]= maxbox[q] - v;	// -NJMP-
-      vmax[q]=-maxbox[q] - v;	// -NJMP-
-    }
-  }
-  if(DOT(normal,vmin)>0.0f) return 0;	// -NJMP-
-  if(DOT(normal,vmax)>=0.0f) return 1;	// -NJMP-
-  
-  return 0;
-}
-
-
-/*======================== X-tests ========================*/
-#define AXISTEST_X01(a, b, fa, fb)			   \
-	p0 = a*v0[Y] - b*v0[Z];			       	   \
-	p2 = a*v2[Y] - b*v2[Z];			       	   \
-        if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
-	rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z];   \
-	if(min>rad || max<-rad) return 0;
-
-#define AXISTEST_X2(a, b, fa, fb)			   \
-	p0 = a*v0[Y] - b*v0[Z];			           \
-	p1 = a*v1[Y] - b*v1[Z];			       	   \
-        if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
-	rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z];   \
-	if(min>rad || max<-rad) return 0;
-
-/*======================== Y-tests ========================*/
-#define AXISTEST_Y02(a, b, fa, fb)			   \
-	p0 = -a*v0[X] + b*v0[Z];		      	   \
-	p2 = -a*v2[X] + b*v2[Z];	       	       	   \
-        if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
-	rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z];   \
-	if(min>rad || max<-rad) return 0;
-
-#define AXISTEST_Y1(a, b, fa, fb)			   \
-	p0 = -a*v0[X] + b*v0[Z];		      	   \
-	p1 = -a*v1[X] + b*v1[Z];	     	       	   \
-        if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
-	rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z];   \
-	if(min>rad || max<-rad) return 0;
-
-/*======================== Z-tests ========================*/
-
-#define AXISTEST_Z12(a, b, fa, fb)			   \
-	p1 = a*v1[X] - b*v1[Y];			           \
-	p2 = a*v2[X] - b*v2[Y];			       	   \
-        if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
-	rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y];   \
-	if(min>rad || max<-rad) return 0;
-
-#define AXISTEST_Z0(a, b, fa, fb)			   \
-	p0 = a*v0[X] - b*v0[Y];				   \
-	p1 = a*v1[X] - b*v1[Y];			           \
-        if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
-	rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y];   \
-	if(min>rad || max<-rad) return 0;
-
-int triBoxOverlap(double boxcenter[3],double boxhalfsize[3],double triverts[3][3])
-{
-
-  /*    use separating axis theorem to test overlap between triangle and box */
-  /*    need to test for overlap in these directions: */
-  /*    1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
-  /*       we do not even need to test these) */
-  /*    2) normal of the triangle */
-  /*    3) crossproduct(edge from tri, {x,y,z}-directin) */
-  /*       this gives 3x3=9 more tests */
-   double v0[3],v1[3],v2[3];
-//   double axis[3];
-   double min,max,p0,p1,p2,rad,fex,fey,fez;		// -NJMP- "d" local variable removed
-   double normal[3],e0[3],e1[3],e2[3];
-
-   /* This is the fastest branch on Sun */
-   /* move everything so that the boxcenter is in (0,0,0) */
-   SUB(v0,triverts[0],boxcenter);
-   SUB(v1,triverts[1],boxcenter);
-   SUB(v2,triverts[2],boxcenter);
-
-   /* compute triangle edges */
-   SUB(e0,v1,v0);      /* tri edge 0 */
-   SUB(e1,v2,v1);      /* tri edge 1 */
-   SUB(e2,v0,v2);      /* tri edge 2 */
-
-   /* Bullet 3:  */
-   /*  test the 9 tests first (this was faster) */
-   fex = fabsf(e0[X]);
-   fey = fabsf(e0[Y]);
-   fez = fabsf(e0[Z]);
-   AXISTEST_X01(e0[Z], e0[Y], fez, fey);
-   AXISTEST_Y02(e0[Z], e0[X], fez, fex);
-   AXISTEST_Z12(e0[Y], e0[X], fey, fex);
-
-   fex = fabsf(e1[X]);
-   fey = fabsf(e1[Y]);
-   fez = fabsf(e1[Z]);
-   AXISTEST_X01(e1[Z], e1[Y], fez, fey);
-   AXISTEST_Y02(e1[Z], e1[X], fez, fex);
-   AXISTEST_Z0(e1[Y], e1[X], fey, fex);
-
-   fex = fabsf(e2[X]);
-   fey = fabsf(e2[Y]);
-   fez = fabsf(e2[Z]);
-   AXISTEST_X2(e2[Z], e2[Y], fez, fey);
-   AXISTEST_Y1(e2[Z], e2[X], fez, fex);
-   AXISTEST_Z12(e2[Y], e2[X], fey, fex);
-
-   /* Bullet 1: */
-   /*  first test overlap in the {x,y,z}-directions */
-   /*  find min, max of the triangle each direction, and test for overlap in */
-   /*  that direction -- this is equivalent to testing a minimal AABB around */
-   /*  the triangle against the AABB */
-
-   /* test in X-direction */
-   FINDMINMAX(v0[X],v1[X],v2[X],min,max);
-   if(min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0;
-
-   /* test in Y-direction */
-   FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max);
-   if(min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0;
-
-   /* test in Z-direction */
-   FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max);
-   if(min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0;
-
-   /* Bullet 2: */
-   /*  test if the box intersects the plane of the triangle */
-   /*  compute plane equation of triangle: normal*x+d=0 */
-   CROSS(normal,e0,e1);
-   // -NJMP- (line removed here)
-   if(!planeBoxOverlap(normal,v0,boxhalfsize)) return 0;	// -NJMP-
-
-   return 1;   /* box and triangle overlaps */
-}
-
diff --git a/src_3rd/gts/vertex.c b/src_3rd/gts/vertex.c
deleted file mode 100644
index d312869..0000000
--- a/src_3rd/gts/vertex.c
+++ /dev/null
@@ -1,780 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <math.h>
-#include "gts.h"
-
-gboolean gts_allow_floating_vertices = FALSE;
-
-static void vertex_destroy (GtsObject * object)
-{
-  GtsVertex * vertex = GTS_VERTEX (object);
-  GSList * i;
-
-  i = vertex->segments;
-  while (i) {
-    GTS_OBJECT_SET_FLAGS (i->data, GTS_DESTROYED);
-    i = i->next;
-  }
-  i = vertex->segments;
-  while (i) {
-    GSList * next = i->next;
-    gts_object_destroy (i->data);
-    i = next;
-  }
-  g_assert (vertex->segments == NULL);
-
-  (* GTS_OBJECT_CLASS (gts_vertex_class ())->parent_class->destroy) (object);
-}
-
-static void vertex_clone (GtsObject * clone, GtsObject * object)
-{
-  (* GTS_OBJECT_CLASS (gts_vertex_class ())->parent_class->clone) (clone, 
-								   object);
-  GTS_VERTEX (clone)->segments = NULL;
-}
-
-static void vertex_class_init (GtsVertexClass * klass)
-{
-  klass->intersection_attributes = NULL;
-  GTS_OBJECT_CLASS (klass)->clone = vertex_clone;
-  GTS_OBJECT_CLASS (klass)->destroy = vertex_destroy;
-}
-
-static void vertex_init (GtsVertex * vertex)
-{
-  vertex->segments = NULL;
-}
-
-/**
- * gts_vertex_class:
- *
- * Returns: the #GtsVertexClass.
- */
-GtsVertexClass * gts_vertex_class (void)
-{
-  static GtsVertexClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo vertex_info = {
-      "GtsVertex",
-      sizeof (GtsVertex),
-      sizeof (GtsVertexClass),
-      (GtsObjectClassInitFunc) vertex_class_init,
-      (GtsObjectInitFunc) vertex_init,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_point_class ()), 
-				  &vertex_info);
-  }
-
-  return klass;
-}
-
-/**
- * gts_vertex_new:
- * @klass: a #GtsVertexClass.
- * @x: the x-coordinate of the vertex to create.
- * @y: the y-coordinate of the vertex to create.
- * @z: the y-coordinate of the vertex to create.
- *
- * Returns: a new #GtsVertex with @x, @y and @z as coordinates.
- */
-GtsVertex * gts_vertex_new (GtsVertexClass * klass,
-			    gdouble x, gdouble y, gdouble z)
-{
-  GtsVertex * v;
-
-  v = GTS_VERTEX (gts_object_new (GTS_OBJECT_CLASS (klass)));
-  gts_point_set (GTS_POINT (v), x, y, z);
-
-  return v;
-}
-
-/**
- * gts_vertex_replace:
- * @v: a #GtsVertex.
- * @with: another #GtsVertex.
- *
- * Replaces vertex @v with vertex @with. @v and @with must be
- * different.  All the #GtsSegment which have @v has one of their
- * vertices are updated.  The segments list of vertex @v is freed and
- * @v->segments is set to %NULL.  
- */
-void gts_vertex_replace (GtsVertex * v, GtsVertex * with)
-{
-  GSList * i;
-
-  g_return_if_fail (v != NULL);
-  g_return_if_fail (with != NULL);
-  g_return_if_fail (v != with);
-
-  i = v->segments;
-  while (i) {
-    GtsSegment * s = i->data;
-    if (s->v1 != with && s->v2 != with)
-      with->segments = g_slist_prepend (with->segments, s);
-    if (s->v1 == v) s->v1 = with;
-    if (s->v2 == v) s->v2 = with;
-    i = i->next;
-  }
-  g_slist_free (v->segments);
-  v->segments = NULL;
-}
-
-/**
- * gts_vertex_is_unattached:
- * @v: a #GtsVertex.
- *
- * Returns: %TRUE if @v is not the endpoint of any #GtsSegment, 
- * %FALSE otherwise.
- */
-gboolean gts_vertex_is_unattached (GtsVertex * v)
-{
-  g_return_val_if_fail (v != NULL, FALSE);
-  if (v->segments == NULL)
-    return TRUE;
-  return FALSE;
-}
-
-/**
- * gts_vertices_are_connected:
- * @v1: a #GtsVertex.
- * @v2: another #GtsVertex.
- *
- * Returns: if @v1 and @v2 are the vertices of the same #GtsSegment
- * this segment else %NULL.
- */
-GtsSegment * gts_vertices_are_connected (GtsVertex * v1, GtsVertex * v2)
-{
-  GSList * i;
-  
-  g_return_val_if_fail (v1 != NULL, FALSE);
-  g_return_val_if_fail (v2 != NULL, FALSE);
-  
-  i = v1->segments;
-  while (i) {
-    GtsSegment * s = i->data;
-
-    if (s->v1 == v2 || s->v2 == v2)
-      return s;
-    i = i->next;
-  }
-  return NULL;
-}
-
-/**
- * gts_vertices_from_segments:
- * @segments: a list of #GtsSegment.
- *
- * Returns: a list of #GtsVertex, vertices of a #GtsSegment in @segments.
- * Each element in the list is unique (no duplicates).
- */
-GSList * gts_vertices_from_segments (GSList * segments)
-{
-  GHashTable * hash;
-  GSList * vertices = NULL, * i;
-  
-  hash = g_hash_table_new (NULL, NULL);
-  i = segments;
-  while (i) {
-    GtsSegment * s = i->data;
-    if (g_hash_table_lookup (hash, s->v1) == NULL) {
-      vertices = g_slist_prepend (vertices, s->v1);
-      g_hash_table_insert (hash, s->v1, s);
-    }
-    if (g_hash_table_lookup (hash, s->v2) == NULL) {
-      vertices = g_slist_prepend (vertices, s->v2);
-      g_hash_table_insert (hash, s->v2, s);
-    }
-    i = i->next;
-  }
-  g_hash_table_destroy (hash);
-  return vertices;
-}
-
-/**
- * gts_vertex_triangles:
- * @v: a #GtsVertex.
- * @list: a list of #GtsTriangle.
- *
- * Adds all the #GtsTriangle which share @v as a vertex and do not
- * already belong to @list.
- *
- * Returns: the new list of unique #GtsTriangle which share @v as a
- * vertex.  
- */
-GSList * gts_vertex_triangles (GtsVertex * v, 
-			       GSList * list)
-{
-  GSList * i;
-
-  g_return_val_if_fail (v != NULL, NULL);
-
-  i = v->segments;
-  while (i) {
-    GtsSegment * s = i->data;
-    if (GTS_IS_EDGE (s)) {
-      GSList * j = GTS_EDGE (s)->triangles;
-      while (j) {
-	if (!g_slist_find (list, j->data))
-	  list = g_slist_prepend (list, j->data);
-	j = j->next;
-      }
-    }
-    i = i->next;
-  }
-  return list;
-}
-
-/**
- * gts_vertex_faces:
- * @v: a #GtsVertex.
- * @surface: a #GtsSurface or %NULL.
- * @list: a list of #GtsFace.
- *
- * Adds all the #GtsFace belonging to @surface (if not %NULL) which share 
- * @v as a vertex and do not already belong to @list.
- *
- * Returns: the new list of unique #GtsFace belonging to @surface 
- * which share @v as a vertex.
- */
-GSList * gts_vertex_faces (GtsVertex * v, 
-			   GtsSurface * surface, 
-			   GSList * list)
-{
-  GSList * i;
-
-  g_return_val_if_fail (v != NULL, NULL);
-
-  i = v->segments;
-  while (i) {
-    GtsSegment * s = i->data;
-    if (GTS_IS_EDGE (s)) {
-      GSList * j = GTS_EDGE (s)->triangles;
-      while (j) {
-	GtsTriangle * t = j->data;
-	if (GTS_IS_FACE (t) 
-	    && 
-	    (!surface || gts_face_has_parent_surface (GTS_FACE (t), surface)) 
-	    &&
-	    !g_slist_find (list, t))
-	  list = g_slist_prepend (list, t);
-	j = j->next;
-      }
-    }
-    i = i->next;
-  }
-  return list;
-}
-
-/**
- * gts_vertex_neighbors:
- * @v: a #GtsVertex.
- * @list: a list of #GtsVertex.
- * @surface: a #GtsSurface or %NULL.
- *
- * Adds to @list all the #GtsVertex connected to @v by a #GtsSegment and not
- * already in @list. If @surface is not %NULL only the vertices connected to
- * @v by an edge belonging to @surface are considered.
- *
- * Returns: the new list of unique #GtsVertex.
- */
-GSList * gts_vertex_neighbors (GtsVertex * v, 
-			       GSList * list,
-			       GtsSurface * surface)
-{
-  GSList * i;
-
-  g_return_val_if_fail (v != NULL, NULL);
-
-  i = v->segments;
-  while (i) {
-    GtsSegment * s = i->data;
-    GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1;
-    if (v1 != v && 
-	(!surface || 
-	 (GTS_IS_EDGE (s) && 
-	  gts_edge_has_parent_surface (GTS_EDGE (s), surface))) &&
-	!g_slist_find (list, v1))
-      list = g_slist_prepend (list, v1);
-    i = i->next;
-  }
-  return list;
-}
-
-/**
- * gts_vertex_is_boundary:
- * @v: a #GtsVertex.
- * @surface: a #GtsSurface or %NULL.
- * 
- * Returns: %TRUE if @v is used by a #GtsEdge boundary of @surface as
- * determined by gts_edge_is_boundary(), %FALSE otherwise.
- */
-gboolean gts_vertex_is_boundary (GtsVertex * v, GtsSurface * surface)
-{
-  GSList * i;
-
-  g_return_val_if_fail (v != NULL, FALSE);
-  
-  i = v->segments;
-  while (i) {
-    if (GTS_IS_EDGE (i->data) && 
-	gts_edge_is_boundary (i->data, surface))
-      return TRUE;
-    i = i->next;
-  }
-
-  return FALSE;
-}
-
-/**
- * gts_vertices_merge:
- * @vertices: a list of #GtsVertex.
- * @epsilon: half the size of the bounding box to consider for each vertex.
- * @check: function called for each pair of vertices about to be merged
- * or %NULL.
- *
- * For each vertex v in @vertices look if there are any vertex of
- * @vertices contained in a box centered on v of size 2*@epsilon. If
- * there are and if @check is not %NULL and returns %TRUE, replace
- * them with v (using gts_vertex_replace()), destroy them and remove
- * them from list.  This is done efficiently using Kd-Trees.
- *
- * Returns: the updated list of vertices.  
- */
-GList * gts_vertices_merge (GList * vertices, 
-			    gdouble epsilon,
-			    gboolean (* check) (GtsVertex *, GtsVertex *))
-{
-  GPtrArray * array;
-  GList * i;
-  GNode * kdtree;
-
-  g_return_val_if_fail (vertices != NULL, 0);
-
-  array = g_ptr_array_new ();
-  i = vertices;
-  while (i) {
-    g_ptr_array_add (array, i->data);
-    i = i->next;
-  }
-  kdtree = gts_kdtree_new (array, NULL);
-  g_ptr_array_free (array, TRUE);
-  
-  i = vertices;
-  while (i) {
-    GtsVertex * v = i->data;
-    if (!GTS_OBJECT (v)->reserved) { /* Do something only if v is active */
-      GtsBBox * bbox;
-      GSList * selected, * j;
-
-      /* build bounding box */
-      bbox = gts_bbox_new (gts_bbox_class (),
-			   v, 
-			   GTS_POINT (v)->x - epsilon,
-			   GTS_POINT (v)->y - epsilon,
-			   GTS_POINT (v)->z - epsilon,
-			   GTS_POINT (v)->x + epsilon,
-			   GTS_POINT (v)->y + epsilon,
-			   GTS_POINT (v)->z + epsilon);
-
-      /* select vertices which are inside bbox using kdtree */
-      j = selected = gts_kdtree_range (kdtree, bbox, NULL);
-      while (j) {
-	GtsVertex * sv = j->data;
-	if (sv != v && !GTS_OBJECT (sv)->reserved && (!check || (*check) (sv, v))) {
-	  /* sv is not v and is active */
-	  gts_vertex_replace (sv, v);
-	  GTS_OBJECT (sv)->reserved = sv; /* mark sv as inactive */
-	}
-	j = j->next;
-      }
-      g_slist_free (selected);
-      gts_object_destroy (GTS_OBJECT (bbox));
-    }
-    i = i->next;
-  }
-
-  gts_kdtree_destroy (kdtree);
-
-  /* destroy inactive vertices and removes them from list */
-
-  /* we want to control vertex destruction */
-  gts_allow_floating_vertices = TRUE;
-
-  i = vertices;
-  while (i) {
-    GtsVertex * v = i->data;
-    GList * next = i->next;
-    if (GTS_OBJECT (v)->reserved) { /* v is inactive */
-      gts_object_destroy (GTS_OBJECT (v));
-      vertices = g_list_remove_link (vertices, i);
-      g_list_free_1 (i);
-    }
-    i = next;
-  }
-  gts_allow_floating_vertices = FALSE; 
-
-  return vertices;
-}
-
-/* returns the list of edges belonging to @surface turning around @v */
-static GSList * edge_fan_list (GtsVertex * v,
-			       GtsSurface * surface,
-			       GtsFace * f, 
-			       GtsEdge * e,
-			       GtsFace * first)
-{
-  GSList * i = e->triangles;
-  GtsFace * neighbor = NULL;
-  GtsEdge * next = NULL, * enext = NULL;
-
-  while (i) {
-    GtsFace * f1 = i->data;
-    if (GTS_IS_FACE (f1) &&
-	f1 != f &&
-	gts_face_has_parent_surface (f1, surface)) {
-      g_return_val_if_fail (neighbor == NULL, NULL); /* non-manifold edge */
-      neighbor = f1;
-    }
-    i = i->next;
-  }
-  if (neighbor == NULL || neighbor == first) /* end of fan */
-    return NULL;
-
-  if (GTS_TRIANGLE (neighbor)->e1 == e) {
-    next = GTS_TRIANGLE (neighbor)->e2;
-    enext = GTS_TRIANGLE (neighbor)->e3;
-  }
-  else if (GTS_TRIANGLE (neighbor)->e2 == e) {
-    next = GTS_TRIANGLE (neighbor)->e3;
-    enext = GTS_TRIANGLE (neighbor)->e1;
-  }
-  else if (GTS_TRIANGLE (neighbor)->e3 == e) {
-    next = GTS_TRIANGLE (neighbor)->e1;
-    enext = GTS_TRIANGLE (neighbor)->e2;
-  }
-  else
-    g_assert_not_reached ();
-
-  /* checking for correct orientation */
-  g_return_val_if_fail (GTS_SEGMENT (enext)->v1 == v ||
-			GTS_SEGMENT (enext)->v2 == v, NULL);
-
-  return g_slist_prepend (edge_fan_list (v, surface, neighbor, enext, first), 
-			  next);
-}
-
-/**
- * gts_vertex_fan_oriented:
- * @v: a #GtsVertex.
- * @surface: a #GtsSurface.
- *
- * Returns: a list of #GtsEdge describing in counterclockwise order the 
- * boundary of the fan of summit @v, the faces of the fan belonging to 
- * @surface.
- */
-GSList * gts_vertex_fan_oriented (GtsVertex * v, GtsSurface * surface)
-{
-  GtsFace * f = NULL;
-  guint d = 2;
-  GSList * i;
-  GtsVertex * v1, * v2, * v3;
-  GtsEdge * e1, * e2, * e3;
-
-  g_return_val_if_fail (v != NULL, NULL);
-  g_return_val_if_fail (surface != NULL, NULL);
-
-  i = v->segments;
-  while (i) {
-    GtsEdge * e = i->data;
-    if (GTS_IS_EDGE (e)) {
-      GSList * j = e->triangles;
-      GtsFace * f1 = NULL;
-      guint degree = 0;
-      while (j) {
-	if (GTS_IS_FACE (j->data) &&
-	    gts_face_has_parent_surface (j->data, surface)) {
-	  f1 = j->data;
-	  degree++;
-	}
-	j = j->next;
-      }
-      if (f1 != NULL) {
-	g_return_val_if_fail (degree <= 2, NULL); /* non-manifold edge */
-	if (degree == 1) {
-	  gts_triangle_vertices_edges (GTS_TRIANGLE (f1), NULL,
-				       &v1, &v2, &v3, &e1, &e2, &e3);
-	  if (v == v2) {
-	    e2 = e3;
-	    e3 = e1;
-	  }
-	  else if (v == v3) {
-	    e3 = e2;
-	    e2 = e1;
-	  }
-	  if (e3 != e) {
-	    d = 1;
-	    f = f1;
-	  }
-	}
-	else if (degree <= d)
-	  f = f1;
-      }
-    }
-    i = i->next;
-  }
-
-  if (f == NULL)
-    return NULL;
-
-  gts_triangle_vertices_edges (GTS_TRIANGLE (f), NULL,
-			       &v1, &v2, &v3, &e1, &e2, &e3);
-  if (v == v2) {
-    e2 = e3;
-    e3 = e1;
-  }
-  else if (v == v3) {
-    e3 = e2;
-    e2 = e1;
-  }
-
-  return g_slist_prepend (edge_fan_list (v, surface, f, e3, f), e2);
-}
-
-#define edge_use_vertex(e, v) (GTS_SEGMENT(e)->v1 == v ||\
-			       GTS_SEGMENT(e)->v2 == v)
-
-static GtsEdge * replace_vertex (GtsTriangle * t, 
-				 GtsEdge * e1,
-				 GtsVertex * v, 
-				 GtsVertex * with)
-{
-  GtsEdge * e = NULL;
-
-  if (t->e1 != e1 && edge_use_vertex (t->e1, v))
-    e = t->e1;
-  else if (t->e2 != e1 && edge_use_vertex (t->e2, v))
-    e = t->e2;
-  else if (t->e3 != e1 && edge_use_vertex (t->e3, v))
-    e = t->e3;
-  else
-    return NULL;
-
-  if (with != v) {
-    GtsSegment * s = GTS_SEGMENT (e);
-    if (s->v1 == v) s->v1 = with;
-    if (s->v2 == v) s->v2 = with;
-    with->segments = g_slist_prepend (with->segments, s);
-    v->segments = g_slist_remove (v->segments, s);
-  }
-
-  return e;
-}
-
-static void triangle_next (GtsEdge * e, GtsVertex * v, GtsVertex * with)
-{
-  GSList * i;
-
-  if (e == NULL)
-    return;
-    
-  i = e->triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    if (GTS_OBJECT (t)->reserved) {
-      GTS_OBJECT (t)->reserved = NULL;
-      triangle_next (replace_vertex (t, e, v, with), v, with);
-    }
-    i = i->next;
-  }
-}
-
-/** 
- * gts_vertex_is_contact: 
- * @v: a #GtsVertex.  
- * @sever: if %TRUE and if @v is a contact vertex between two or more
- * sets of connected triangles replaces it with as many vertices,
- * clones of @v.
- *
- * Returns: the number of sets of connected triangles sharing @v as a
- * contact vertex.  
- */
-guint gts_vertex_is_contact (GtsVertex * v, gboolean sever)
-{
-  GSList * triangles, * i;
-  GtsVertex * with = v;
-  guint ncomponent = 0;
-
-  g_return_val_if_fail (v != NULL, 0);
-
-  triangles = gts_vertex_triangles (v, NULL);
-  i = triangles;
-  while (i) {
-    GTS_OBJECT (i->data)->reserved = i;
-    i = i->next;
-  }
-
-  i = triangles;
-  while (i) {
-    GtsTriangle * t = i->data;
-    if (GTS_OBJECT (t)->reserved) {
-      GtsEdge * e;
-      if (ncomponent && sever)
-	with = GTS_VERTEX (gts_object_clone (GTS_OBJECT (v)));
-      GTS_OBJECT (t)->reserved = NULL;
-      e = replace_vertex (t, NULL, v, with);
-      triangle_next (e, v, with);
-      triangle_next (replace_vertex (t, e, v, with), v, with);
-      ncomponent++;
-    }
-    i = i->next;
-  }
-  g_slist_free (triangles);
-
-  return ncomponent;
-}
-
-/* GtsVertexNormal: Object */
-
-static void vertex_normal_attributes (GtsVertex * v,
-				      GtsObject * e,
-				      GtsObject * t)
-{
-  g_return_if_fail (GTS_IS_EDGE (e));
-  g_return_if_fail (GTS_IS_TRIANGLE (t));
-
-  if (GTS_IS_VERTEX_NORMAL (GTS_SEGMENT (e)->v1) &&
-      GTS_IS_VERTEX_NORMAL (GTS_SEGMENT (e)->v2)) {
-    GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (e)->v1);
-    GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (e)->v2);
-    GtsPoint * p = GTS_POINT (v);
-    gdouble a, b, lambda;
-    guint i;
-
-    a = p2->x - p1->x; b = p->x - p1->x;
-    if (fabs (p2->y - p1->y) > fabs (a)) {
-      a = p2->y - p1->y; b = p->y - p1->y;      
-    }
-    if (fabs (p2->z - p1->z) > fabs (a)) {
-      a = p2->z - p1->z; b = p->z - p1->z;      
-    }
-    lambda = a != 0. ? b/a : 0.;
-    for (i = 0; i < 3; i++)
-      GTS_VERTEX_NORMAL (v)->n[i] = 
-	(1. - lambda)*GTS_VERTEX_NORMAL (GTS_SEGMENT (e)->v1)->n[i] +
-	lambda*GTS_VERTEX_NORMAL (GTS_SEGMENT (e)->v2)->n[i];
-  }
-  else {
-    GtsVertex * v1, * v2, * v3;
-
-    gts_triangle_vertices (GTS_TRIANGLE (t), &v1, &v2, &v3);
-    if (GTS_IS_VERTEX_NORMAL (v1) && 
-	GTS_IS_VERTEX_NORMAL (v2) &&
-	GTS_IS_VERTEX_NORMAL (v3)) {
-      GtsVector a1, a2, a3, det;
-      guint i, j = 0;
-      gdouble l1, l2;
-
-      gts_vector_init (a1, GTS_POINT (v1), GTS_POINT (v));
-      gts_vector_init (a2, GTS_POINT (v1), GTS_POINT (v2));
-      gts_vector_init (a3, GTS_POINT (v1), GTS_POINT (v3));
-      gts_vector_cross (det, a2, a3);
-      if (fabs (det[1]) > fabs (det[0])) j = 1;
-      if (fabs (det[2]) > fabs (det[j])) j = 2;
-      if (det[j] == 0.) {
-	g_warning ("vertex_normal_attributes: det[%d] == 0.", j);
-	return;
-      }
-      switch (j) {
-      case 0: 
-	l1 = (a1[1]*a3[2] - a1[2]*a3[1])/det[0]; 
-	l2 = (a1[2]*a2[1] - a1[1]*a2[2])/det[0]; 
-	break;
-      case 1:
-	l1 = (a1[2]*a3[0] - a1[0]*a3[2])/det[1];
-	l2 = (a1[0]*a2[2] - a1[2]*a2[0])/det[1];
-	break;
-      case 2:
-	l1 = (a1[0]*a3[1] - a1[1]*a3[0])/det[2];
-	l2 = (a1[1]*a2[0] - a1[0]*a2[1])/det[2];
-	break;
-      default:
-	l1 = l2 = 0.;
-      }
-      for (i = 0; i < 3; i++)
-	GTS_VERTEX_NORMAL (v)->n[i] = 
-	  GTS_VERTEX_NORMAL (v1)->n[i]*(1. - l1 - l2) +
-	  GTS_VERTEX_NORMAL (v2)->n[i]*l1 +
-	  GTS_VERTEX_NORMAL (v3)->n[i]*l2;
-    }
-  }
-}
-
-static void gts_vertex_normal_class_init (GtsVertexClass * klass)
-{
-  klass->intersection_attributes = vertex_normal_attributes;
-}
-
-GtsVertexClass * gts_vertex_normal_class (void)
-{
-  static GtsVertexClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo gts_vertex_normal_info = {
-      "GtsVertexNormal",
-      sizeof (GtsVertexNormal),
-      sizeof (GtsVertexClass),
-      (GtsObjectClassInitFunc) gts_vertex_normal_class_init,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()),
-				  &gts_vertex_normal_info);
-  }
-
-  return klass;
-}
-
-/* GtsColorVertex: Object */
-
-GtsVertexClass * gts_color_vertex_class (void)
-{
-  static GtsVertexClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo gts_color_vertex_info = {
-      "GtsColorVertex",
-      sizeof (GtsColorVertex),
-      sizeof (GtsVertexClass),
-      (GtsObjectClassInitFunc) NULL,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()),
-				  &gts_color_vertex_info);
-  }
-
-  return klass;
-}
-
diff --git a/src_3rd/gts/vopt.c b/src_3rd/gts/vopt.c
deleted file mode 100644
index d772af9..0000000
--- a/src_3rd/gts/vopt.c
+++ /dev/null
@@ -1,521 +0,0 @@
-/* GTS - Library for the manipulation of triangulated surfaces
- * Copyright (C) 1999 St�phane Popinet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gts.h"
-
-/* #define DEBUG_VOPT */
-
-/* compute the normal (nx, ny, nz) as the cross-product of the first two 
-   oriented edges and the norm nt = |t| as (v1xv2).v3 */
-static void triangle_normal (GtsTriangle * t, 
-			     gdouble * nx, 
-			     gdouble * ny, 
-			     gdouble * nz,
-			     gdouble * nt)
-{
-  GtsPoint * p1, * p2 = NULL, * p3 = NULL;
-  gdouble x1, y1, z1, x2, y2, z2;
-
-  g_return_if_fail (t != NULL);
-
-  p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
-  if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) {
-    p2 = GTS_POINT (GTS_SEGMENT (t->e2)->v2);
-    p3 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-  }
-  else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) {
-    p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-    p3 = GTS_POINT (GTS_SEGMENT (t->e2)->v1);
-  }
-  else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) {
-    p2 = GTS_POINT (GTS_SEGMENT (t->e2)->v1);
-    p3 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-  }
-  else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) {
-    p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
-    p3 = GTS_POINT (GTS_SEGMENT (t->e2)->v2);
-  }
-  else
-    g_assert_not_reached ();
-
-  x1 = p2->x - p1->x;
-  y1 = p2->y - p1->y;
-  z1 = p2->z - p1->z;
-
-  x2 = p3->x - p1->x;
-  y2 = p3->y - p1->y;
-  z2 = p3->z - p1->z;
-
-  *nt = ((p1->y*p2->z - p1->z*p2->y)*p3->x + 
-	 (p1->z*p2->x - p1->x*p2->z)*p3->y + 
-	 (p1->x*p2->y - p1->y*p2->x)*p3->z);
-  *nx = y1*z2 - z1*y2;
-  *ny = z1*x2 - x1*z2;
-  *nz = x1*y2 - y1*x2;
-}
-
-static void boundary_preservation (GtsEdge * edge,
-				   GtsFace * f,
-				   GtsVector e1, GtsVector e2,
-				   GtsMatrix * H, GtsVector c)
-{
-  GtsTriangle * t = GTS_TRIANGLE (f);
-  GtsEdge * edge2;
-  GtsVertex * v1 = GTS_SEGMENT (edge)->v1, * v2 = GTS_SEGMENT (edge)->v2;
-  GtsPoint * p1, * p2;
-  GtsVector e, e3;
-
-  /* find orientation of segment */
-  edge2 = edge == t->e1 ? t->e2 : edge == t->e2 ? t->e3 : t->e1;
-  if (v2 != GTS_SEGMENT (edge2)->v1 && v2 != GTS_SEGMENT (edge2)->v2) {
-    v2 = v1; v1 = GTS_SEGMENT (edge)->v2;
-  }
-  p1 = GTS_POINT (v1);
-  p2 = GTS_POINT (v2);
-
-  e[0] = p2->x - p1->x;
-  e[1] = p2->y - p1->y;
-  e[2] = p2->z - p1->z;
-
-  e1[0] += e[0];
-  e1[1] += e[1];
-  e1[2] += e[2];
-
-  e3[0] = p2->y*p1->z - p2->z*p1->y;
-  e3[1] = p2->z*p1->x - p2->x*p1->z;
-  e3[2] = p2->x*p1->y - p2->y*p1->x;
-
-  e2[0] += e3[0];
-  e2[1] += e3[1];
-  e2[2] += e3[2];
-
-  H[0][0] += e[1]*e[1] + e[2]*e[2];
-  H[0][1] -= e[0]*e[1];
-  H[0][2] -= e[0]*e[2];
-  H[1][0] = H[0][1];
-  H[1][1] += e[0]*e[0] + e[2]*e[2];
-  H[1][2] -= e[1]*e[2];
-  H[2][0] = H[0][2];
-  H[2][1] = H[1][2];
-  H[2][2] += e[0]*e[0] + e[1]*e[1];
-
-  c[0] += e[1]*e3[2] - e[2]*e3[1];
-  c[1] += e[2]*e3[0] - e[0]*e3[2];
-  c[2] += e[0]*e3[1] - e[1]*e3[0];
-}
-
-static gdouble boundary_cost (GtsEdge * edge, 
-			      GtsFace * f,
-			      GtsVertex * v)
-{
-  GtsTriangle * t = GTS_TRIANGLE (f);
-  GtsEdge * edge2;
-  GtsVertex * v1 = GTS_SEGMENT (edge)->v1, * v2 = GTS_SEGMENT (edge)->v2;
-  GtsPoint * p1, * p2;
-  GtsVector e;
-  GtsPoint * p = GTS_POINT (v);
-
-  /* find orientation of segment */
-  edge2 = edge == t->e1 ? t->e2 : edge == t->e2 ? t->e3 : t->e1;
-  if (v2 != GTS_SEGMENT (edge2)->v1 && v2 != GTS_SEGMENT (edge2)->v2) {
-    v2 = v1; v1 = GTS_SEGMENT (edge)->v2;
-  }
-  p1 = GTS_POINT (v1);
-  p2 = GTS_POINT (v2);  
-
-  e[0] = (p2->y - p1->y)*(p->z - p2->z) - (p2->z - p1->z)*(p->y - p2->y);
-  e[1] = (p2->z - p1->z)*(p->x - p2->x) - (p2->x - p1->x)*(p->z - p2->z);
-  e[2] = (p2->x - p1->x)*(p->y - p2->y) - (p2->y - p1->y)*(p->x - p2->x);
-
-  return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
-}
-
-static gdouble edge_boundary_cost (GtsEdge * e, GtsVertex * v)
-{
-  gdouble cost = 0.;
-  GSList * i;
-
-  i = GTS_SEGMENT (e)->v1->segments;
-  while (i) {
-    GtsFace * f;
-    if (GTS_IS_EDGE (i->data) && 
-	(f = gts_edge_is_boundary (i->data, NULL)))
-      cost += boundary_cost (i->data, f, v);
-    i = i->next;
-  }
-  i = GTS_SEGMENT (e)->v2->segments;
-  while (i) {
-    GtsFace * f;
-    if (i->data != e && 
-	GTS_IS_EDGE (i->data) && 
-	(f = gts_edge_is_boundary (i->data, NULL)))
-      cost += boundary_cost (i->data, f, v);
-    i = i->next;
-  }
-
-  return cost/4.;
-}
-
-static gdouble edge_volume_cost (GtsEdge * e, GtsVertex * v)
-{
-  GSList * i, * triangles;
-  gdouble n1, n2, n3, nt;
-  gdouble cost = 0.0, a;
-
-  triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL);
-  triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles);
-
-  i = triangles;
-  while (i) {
-    if (GTS_IS_FACE (i->data)) {
-      triangle_normal (i->data, &n1, &n2, &n3, &nt);
-      a = GTS_POINT (v)->x*n1 + 
-	GTS_POINT (v)->y*n2 + 
-	GTS_POINT (v)->z*n3 - nt;
-      cost += a*a;
-    }
-    i = i->next;
-  }
-  g_slist_free (triangles);
-
-  return cost/36.;
-}
-
-static gdouble edge_shape_cost (GtsEdge * e, GtsVertex * v)
-{
-  GSList * list, * i;
-  GtsVertex 
-    * v1 = GTS_SEGMENT (e)->v1,
-    * v2 = GTS_SEGMENT (e)->v2;
-  gdouble cost = 0.;
-
-  list = gts_vertex_neighbors (v1, NULL, NULL);
-  list = gts_vertex_neighbors (v2, list, NULL);
-  i = list;
-  while (i) {
-    GtsPoint * p = i->data;
-    if (p != GTS_POINT (v1) && p != GTS_POINT (v2))
-      cost += gts_point_distance2 (p, GTS_POINT (v));
-    i = i->next;
-  }
-  g_slist_free (list);
-
-  return cost;
-}
-
-/**
- * gts_volume_optimized_vertex:
- * @edge: a #GtsEdge.
- * @klass: a #GtsVertexClass to be used for the new vertex.
- * @params: a #GtsVolumeOptimizedParms.
- *
- * Returns: a #GtsVertex which can be used to replace @edge for an
- * edge collapse operation. The position of the vertex is optimized in
- * order to minimize the changes in area and volume for the surface
- * using @edge. The volume enclosed by the surface is locally
- * preserved. For more details see "Fast and memory efficient
- * polygonal simplification" (1998) and "Evaluation of memoryless
- * simplification" (1999) by Lindstrom and Turk.  
- */
-GtsVertex * gts_volume_optimized_vertex (GtsEdge * edge,
-					 GtsVertexClass * klass,
-					 GtsVolumeOptimizedParams * params)
-{
-  GSList * triangles, * i;
-  gdouble sn1 = 0., sn2 = 0., sn3 = 0.;
-  gdouble sn11 = 0., sn22 = 0., sn33 = 0.;
-  gdouble sn12 = 0., sn13 = 0., sn23 = 0.;
-  gdouble st = 0., stn1 = 0., stn2 = 0., stn3 = 0.;
-  gdouble n1, n2, n3, nt;
-  GtsMatrix * A, * Ai;
-  GtsVector A1, b;
-  GtsVector e1 = {0., 0., 0.}, e2 = {0., 0., 0.};
-  GtsMatrix * Hb;
-  GtsVector cb = {0., 0., 0.};
-  GtsVertex * v;
-  GtsVertex * v1, * v2;
-  guint n = 0, nb = 0;
-#ifdef DEBUG_VOPT
-  guint nold = 0;
-#endif
-
-  g_return_val_if_fail (edge != NULL, NULL);
-  g_return_val_if_fail (klass != NULL, NULL);
-  g_return_val_if_fail (params != NULL, NULL);
-
-  A = gts_matrix_zero (NULL);
-  Hb = gts_matrix_zero (NULL);
-  v1 = GTS_SEGMENT (edge)->v1;
-  v2 = GTS_SEGMENT (edge)->v2;
-
-  /* boundary preservation */
-  i = v1->segments;
-  while (i) {
-    GtsEdge * edge1 = i->data;
-    GtsFace * f;
-    if (GTS_IS_EDGE (edge1) &&
-	(f = gts_edge_is_boundary (edge1, NULL))) {
-      boundary_preservation (edge1, f, e1, e2, Hb, cb);
-      nb++;
-    }
-    i = i->next;
-  }
-  i = v2->segments;
-  while (i) {
-    GtsEdge * edge1 = i->data;
-    GtsFace * f;
-    if (edge1 != edge && 
-	GTS_IS_EDGE (edge1) &&
-	(f = gts_edge_is_boundary (edge1, NULL))) {
-      boundary_preservation (edge1, f, e1, e2, Hb, cb);
-      nb++;
-    }
-    i = i->next;
-  }
-  if (nb > 0) {
-    GtsMatrix * H = gts_matrix_new (
-	       e1[2]*e1[2] + e1[1]*e1[1], - e1[0]*e1[1], - e1[0]*e1[2], 0.,
-	       - e1[0]*e1[1], e1[2]*e1[2] + e1[0]*e1[0], - e1[1]*e1[2], 0.,
-	       - e1[0]*e1[2], - e1[1]*e1[2], e1[1]*e1[1] + e1[0]*e1[0], 0.,
-	       0., 0., 0., 0.);
-    GtsVector c;
-
-    c[0] = e1[1]*e2[2] - e1[2]*e2[1];
-    c[1] = e1[2]*e2[0] - e1[0]*e2[2];
-    c[2] = e1[0]*e2[1] - e1[1]*e2[0];
-    n = gts_matrix_quadratic_optimization (A, b, n, H, c);
-    gts_matrix_destroy (H);
-  }
-
-  g_assert (n <= 2);
-
-#ifdef DEBUG_VOPT
-  if (n != nold) {
-    fprintf (stderr, "--- boundary preservation ---\n");
-    gts_matrix_print (A, stderr);
-    gts_vector_print (b, stderr);
-    nold = n;
-  }
-#endif
-
-  /* volume preservation */
-  triangles = gts_vertex_triangles (v1, NULL);
-  triangles = gts_vertex_triangles (v2, triangles);
-
-  i = triangles;
-  while (i) {
-    if (GTS_IS_FACE (i->data)) {
-      triangle_normal (i->data, &n1, &n2, &n3, &nt);
-      sn1 += n1; sn2 += n2; sn3 += n3;
-      sn11 += n1*n1; sn22 += n2*n2; sn33 += n3*n3;
-      sn12 += n1*n2; sn13 += n1*n3; sn23 += n2*n3;
-      st += nt; stn1 += nt*n1; stn2 += nt*n2; stn3 += nt*n3;
-    }
-    i = i->next;
-  }
-  g_slist_free (triangles);
-
-  A1[0] = sn1; A1[1] = sn2; A1[2] = sn3;
-  n = gts_matrix_compatible_row (A, b, n, A1, st);
-
-#ifdef DEBUG_VOPT
-  if (n != nold) {
-    fprintf (stderr, "--- volume preservation ---\n");
-    gts_matrix_print (A, stderr);
-    gts_vector_print (b, stderr);
-    nold = n;
-  }
-#endif
-
-#if 1 /* Weighted average of volume and boundary optimization */
-  if (n < 3) {
-    /* volume optimization and boundary optimization */
-    GtsMatrix * H = gts_matrix_new (sn11, sn12, sn13, 0.,
-				    sn12, sn22, sn23, 0.,
-				    sn13, sn23, sn33, 0.,
-				    0., 0., 0., 0.);
-    GtsVector c;
-    gdouble le = 9.*params->boundary_weight*
-      gts_point_distance2 (GTS_POINT (v1), 
-			   GTS_POINT (v2));
-    guint i, j;
-
-    c[0] = - stn1; c[1] = - stn2; c[2] = - stn3;
-    if (nb > 0)
-      for (i = 0; i < 3; i++) {
-	for (j = 0; j < 3; j++)
-	  H[i][j] = params->volume_weight*H[i][j] + le*Hb[i][j];
-	c[i] = params->volume_weight*c[i] + le*cb[i];
-      }
-    n = gts_matrix_quadratic_optimization (A, b, n, H, c);
-    gts_matrix_destroy (H);
-  }
-
-#ifdef DEBUG_VOPT
-  if (n != nold) {
-    fprintf (stderr, "--- volume and boundary optimization ---\n");
-    gts_matrix_print (A, stderr);
-    gts_vector_print (b, stderr);
-    nold = n;
-  }
-#endif
-
-  if (n < 3) {
-    /* triangle shape optimization */
-    gdouble nv = 0.0;
-    GtsMatrix * H;
-    GtsVector c = {0., 0., 0.};
-    GSList * list, * i;
-
-    list = gts_vertex_neighbors (v1, NULL, NULL);
-    list = gts_vertex_neighbors (v2, list, NULL);
-
-    i = list;
-    while (i) {
-      GtsPoint * p1 = i->data;
-      if (p1 != GTS_POINT (v1) && p1 != GTS_POINT (v2)) {
-	nv += 1.0;
-	c[0] -= p1->x;
-	c[1] -= p1->y;
-	c[2] -= p1->z;
-      }
-      i = i->next;
-    }
-    g_slist_free (list);
-    
-    H = gts_matrix_new (nv, 0., 0., 0.,
-			0., nv, 0., 0.,
-			0., 0., nv, 0.,
-			0., 0., 0., 0.);
-    n = gts_matrix_quadratic_optimization (A, b, n, H, c);
-    gts_matrix_destroy (H);
-  }
-
-#ifdef DEBUG_VOPT
-  if (n != nold) {
-    fprintf (stderr, "--- triangle shape optimization ---\n");
-    gts_matrix_print (A, stderr);
-    gts_vector_print (b, stderr);
-    nold = n;
-  }
-#endif
-#else /* Weighted average of volume, boundary and shape optimization */
-  if (n < 3) {
-    /* volume optimization, boundary and shape optimization */
-    GtsMatrix * H; 
-    GtsVector c;
-    gdouble l2 = gts_point_distance2 (GTS_POINT (v1), 
-				      GTS_POINT (v2));
-    gdouble wv = params->volume_weight/32.;
-    gdouble wb = params->boundary_weight/4.*l2;
-    gdouble ws = params->shape_weight*l2*l2;
-    
-    gdouble nv = 0.0;
-    GtsVector cs = {0., 0., 0.};
-    GSList * list, * i;
-
-    list = gts_vertex_neighbors (v1, NULL, NULL);
-    list = gts_vertex_neighbors (v2, list, NULL);
-
-    i = list;
-    while (i) {
-      GtsPoint * p1 = i->data;
-      if (p1 != GTS_POINT (v1) && p1 != GTS_POINT (v2)) {
-	nv += 1.0;
-	cs[0] -= p1->x;
-	cs[1] -= p1->y;
-	cs[2] -= p1->z;
-      }
-      i = i->next;
-    }
-    g_slist_free (list);
-
-    H = gts_matrix_new (wv*sn11 + wb*Hb[0][0] + ws*nv, 
-			wv*sn12 + wb*Hb[0][1], 
-			wv*sn13 + wb*Hb[0][2],
-			wv*sn12 + wb*Hb[1][0], 
-			wv*sn22 + wb*Hb[1][1] + ws*nv, 
-			wv*sn23 + wb*Hb[1][2],
-			wv*sn13 + wb*Hb[2][0], 
-			wv*sn23 + wb*Hb[2][1], 
-			wv*sn33 + wb*Hb[2][2] + ws*nv);
-
-    c[0] = - wv*stn1 + wb*cb[0] + ws*cs[0];
-    c[1] = - wv*stn2 + wb*cb[1] + ws*cs[1];
-    c[2] = - wv*stn3 + wb*cb[2] + ws*cs[2];
-
-    n = gts_matrix_quadratic_optimization (A, b, n, H, c);
-    gts_matrix_destroy (H);
-  }
-
-#ifdef DEBUG_VOPT
-  if (n != nold) {
-    fprintf (stderr, "--- volume, boundary and shape optimization ---\n");
-    gts_matrix_print (A, stderr);
-    gts_vector_print (b, stderr);
-    nold = n;
-  }
-#endif
-#endif /* Weighted average of volume, boundary and shape optimization */
-
-  g_assert (n == 3);
-  g_assert ((Ai = gts_matrix3_inverse (A)));
-
-  v = gts_vertex_new (klass,
-		      Ai[0][0]*b[0] + Ai[0][1]*b[1] + Ai[0][2]*b[2],
-		      Ai[1][0]*b[0] + Ai[1][1]*b[1] + Ai[1][2]*b[2],
-		      Ai[2][0]*b[0] + Ai[2][1]*b[1] + Ai[2][2]*b[2]);
-
-  gts_matrix_destroy (A);
-  gts_matrix_destroy (Ai);
-  gts_matrix_destroy (Hb);
-  
-  return v;
-}
-
-/**
- * gts_volume_optimized_cost:
- * @e: a #GtsEdge.
- * @params: a #GtsVolumeOptimizedParams.
- * 
- * Returns: the cost for the collapse of @e as minimized by the function
- * gts_volume_optimized_vertex().
- */
-gdouble gts_volume_optimized_cost (GtsEdge * e, 
-				   GtsVolumeOptimizedParams * params)
-{
-  GtsVertex * v;
-  gdouble cost;
-  gdouble length2;
-
-  g_return_val_if_fail (e != NULL, G_MAXDOUBLE);
-  g_return_val_if_fail (params != NULL, G_MAXDOUBLE);
-
-  v = gts_volume_optimized_vertex (e, gts_vertex_class (), params);
-
-  length2 = gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), 
-				 GTS_POINT (GTS_SEGMENT (e)->v2));
-  cost = 
-    params->volume_weight*edge_volume_cost (e, v) +
-    params->boundary_weight*length2*edge_boundary_cost (e, v) +
-    params->shape_weight*length2*length2*edge_shape_cost (e, v);
-  gts_object_destroy (GTS_OBJECT (v));
-
-  return cost;
-}
diff --git a/src_3rd/liblihata/parser.c b/src_3rd/liblihata/parser.c
index 631b430..779af88 100644
--- a/src_3rd/liblihata/parser.c
+++ b/src_3rd/liblihata/parser.c
@@ -328,9 +328,10 @@ lht_err_t lht_parser_char(lht_parse_t *ctx, int c)
 					if (is_text(sp->type))
 						tstrip_trailing_ws(ctx);
 					goto got_string;
+				case '=':
+					sp->explicit_name = 1; /* for the case of {key}={} */
 				case ' ':
 				case '\t':
-				case '=':
 					break; /* ignore whitespace between name and value */
 				case '{':
 					if (is_text(sp->type)) { /* for a text value brace is protection */
diff --git a/src_3rd/liblihata/regression/ref/text.dref b/src_3rd/liblihata/regression/ref/text.dref
index dc7dd6b..6ca0cf3 100644
--- a/src_3rd/liblihata/regression/ref/text.dref
+++ b/src_3rd/liblihata/regression/ref/text.dref
@@ -10,5 +10,6 @@ li:{root} [root] FIRST te:{key1} LAST te:{}
  te:{} {anon3}
  te:{empty} {}
  te:{empty2} {}
+ te:{empty3} {}
  te:{} {}
  te:{} {}
diff --git a/src_3rd/liblihata/regression/ref/text.eref b/src_3rd/liblihata/regression/ref/text.eref
index 7e9b3e4..a39561a 100644
--- a/src_3rd/liblihata/regression/ref/text.eref
+++ b/src_3rd/liblihata/regression/ref/text.eref
@@ -10,6 +10,7 @@ list root
  text '' = 'anon3'
  text 'empty' = ''
  text 'empty2' = ''
+ text 'empty3' = ''
  text '' = ''
  text '' = ''
 *EOF*
diff --git a/src_3rd/liblihata/regression/text.lht b/src_3rd/liblihata/regression/text.lht
index a4cb503..d67d2b7 100644
--- a/src_3rd/liblihata/regression/text.lht
+++ b/src_3rd/liblihata/regression/text.lht
@@ -10,6 +10,7 @@ li:root = {
 	anon3;
 	empty={}
 	empty2=
+	{empty3}={}
 	{} {}
 	=
 }
diff --git a/src_3rd/qparse/example.c b/src_3rd/qparse/example.c
index 19d5a20..66b48db 100644
--- a/src_3rd/qparse/example.c
+++ b/src_3rd/qparse/example.c
@@ -17,7 +17,7 @@ int main()
 
 		/* split and print fields */
 		printf("Splitting '%s':\n", s);
-		argc = qparse(s, &argv);
+		argc = qparse2(s, &argv, QPARSE_DOUBLE_QUOTE | QPARSE_SINGLE_QUOTE);
 		for(n = 0; n < argc; n++)
 			printf(" [%d] '%s'\n", n, argv[n]);
 		qparse_free(argc, &argv);
diff --git a/src_3rd/qparse/qparse.c b/src_3rd/qparse/qparse.c
index 4466226..12fa2c9 100644
--- a/src_3rd/qparse/qparse.c
+++ b/src_3rd/qparse/qparse.c
@@ -1,6 +1,6 @@
 /*
     libgpmi - General Package/Module Interface - qparse package
-    Copyright (C) 2006-2007 Tibor 'Igor2' Palinkas
+    Copyright (C) 2006-2007, 2017 Tibor 'Igor2' Palinkas
   
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -23,7 +23,8 @@
 
 typedef enum qp_state_e {
 	qp_normal,
-	qp_dquote
+	qp_dquote,
+	qp_squote
 } qp_state_t;
 
 #define qpush(chr) \
@@ -43,6 +44,7 @@ typedef enum qp_state_e {
 		case 't': qpush('\t'); break; \
 		case 'b': qpush('\b'); break; \
 		case '"': qpush('"'); break; \
+		case '\'': qpush('\''); break; \
 		case ' ': qpush(' '); break; \
 		case '\0': break; \
 		default: \
@@ -63,8 +65,7 @@ typedef enum qp_state_e {
 		buff_used = 0; \
 	}
 
-
-int qparse(const char *input, char **argv_ret[])
+int qparse2(const char *input, char **argv_ret[], flags_t flg)
 {
 	int argc;
 	int allocated;
@@ -92,7 +93,16 @@ int qparse(const char *input, char **argv_ret[])
 						qbackslash(*s);
 						break;
 					case '"':
-						state = qp_dquote;
+						if (flg & QPARSE_DOUBLE_QUOTE)
+							state = qp_dquote;
+						else
+							qpush(*s);
+						break;
+					case '\'':
+						if (flg & QPARSE_SINGLE_QUOTE)
+							state = qp_squote;
+						else
+							qpush(*s);
 						break;
 					case ' ':
 					case '\t':
@@ -105,6 +115,7 @@ int qparse(const char *input, char **argv_ret[])
 				}
 				/* End of qp_normal */
 				break;
+
 			case qp_dquote:
 				switch (*s) {
 					case '\\':
@@ -119,6 +130,21 @@ int qparse(const char *input, char **argv_ret[])
 				}
 				/* End of qp_dquote */
 				break;
+
+			case qp_squote:
+				switch (*s) {
+					case '\\':
+						s++;
+						qbackslash(*s);
+						break;
+					case '\'':
+						state = qp_normal;
+						break;
+					default:
+						qpush(*s);
+				}
+				/* End of qp_dquote */
+				break;
 		}
 	}
 
@@ -131,6 +157,12 @@ int qparse(const char *input, char **argv_ret[])
 	return argc;
 }
 
+int qparse(const char *input, char **argv_ret[])
+{
+	return qparse2(input, argv_ret, QPARSE_DOUBLE_QUOTE);
+}
+
+
 void qparse_free(int argc, char **argv_ret[])
 {
 	int n;
diff --git a/src_3rd/qparse/qparse.h b/src_3rd/qparse/qparse.h
index d5f830e..0adc301 100644
--- a/src_3rd/qparse/qparse.h
+++ b/src_3rd/qparse/qparse.h
@@ -9,3 +9,12 @@ void qparse_free(int argc, char **argv_ret[]);
 
 /* for C89 - that doesn't have strdup()*/
 char *qparse_strdup(const char *s);
+
+/* More advanced API with more control over the format */
+typedef enum {
+	QPARSE_DOUBLE_QUOTE = 1,
+	QPARSE_SINGLE_QUOTE = 2
+} flags_t;
+
+int qparse2(const char *input, char **argv_ret[], flags_t flg);
+
diff --git a/src_plugins/Common_enabled.tmpasm b/src_plugins/Common_enabled.tmpasm
index be8dbe4..367ad7d 100644
--- a/src_plugins/Common_enabled.tmpasm
+++ b/src_plugins/Common_enabled.tmpasm
@@ -64,7 +64,6 @@ switch /local/pcb/mod/CONF
 		put /local/pcb/mod/CONFOUT /local/pcb/mod/CONF
 		sub {/local/pcb/mod/CONFOUT} {.h$} {_fields.h}
 		append /local/pcb/CLEANFILES /local/pcb/mod/CONFOUT
-		append /local/pcb/CLEANFILES ?/local/pcb/mod/CLEANFILES
 		append /local/pcb/RULES [@
 # conf generation for @/local/pcb/mod@ '@/local/pcb/mod/CONF@'
 @/local/pcb/mod/CONFOUT@: @/local/pcb/mod/CONF@
@@ -73,6 +72,8 @@ switch /local/pcb/mod/CONF
 		end
 end
 
+append /local/pcb/CLEANFILES ?/local/pcb/mod/CLEANFILES
+
 # explicit rules: .sphash -> .c
 # Space separated list of .sphash input files
 # Optional: aux data fileds:   $(PLUGDIR)/query/consts.sphash::long:int:val;
@@ -117,5 +118,6 @@ put /local/pcb/mod/CFLAGS {}
 put /local/pcb/mod/YACC {}
 put /local/pcb/mod/LEX {}
 put /local/pcb/mod/SPHASH {}
+put /local/pcb/mod/CLEANFILES {}
 put /local/pcb/mod {}
 
diff --git a/src_plugins/Plugin.tmpasm b/src_plugins/Plugin.tmpasm
index cd5fd39..cf3734d 100644
--- a/src_plugins/Plugin.tmpasm
+++ b/src_plugins/Plugin.tmpasm
@@ -20,7 +20,7 @@ include {../scconfig/Makefile.comp_var.inc}
 append /local/pcb/all   [@ $(PLUGIDIR)/@/local/pcb/mod at .so @]
 
 append /local/pcb/rules/install_ [@
-	$(CPC) "`pwd`/$(PLUGDIR)/@/local/pcb/mod@/@/local/pcb/mod at .so" "$(LIBDIR)/plugins/@/local/pcb/mod at .so"@]
+	$(SCCBOX) $(HOW) "$(PLUGDIR)/@/local/pcb/mod@/@/local/pcb/mod at .so" "$(LIBDIR)/plugins/@/local/pcb/mod at .so"@]
 
 append /local/pcb/CLEANFILES [@ $(PLUGDIR)/@/local/pcb/mod@/@/local/pcb/mod at .so $(PLUGIDIR)/@/local/pcb/mod at .so @/local/pcb/mod/OBJS@  @/local/pcb/mod/OBJS_C99@ @]
 
diff --git a/src_plugins/autoplace/autoplace.c b/src_plugins/autoplace/autoplace.c
index 66bc6a4..e7edfec 100644
--- a/src_plugins/autoplace/autoplace.c
+++ b/src_plugins/autoplace/autoplace.c
@@ -141,11 +141,13 @@ typedef struct {
  */
 static void UpdateXY(pcb_netlist_t *Nets)
 {
-	pcb_layergrp_id_t SLayer, CLayer;
+	pcb_layergrp_id_t SLayer = -1, CLayer = -1;
 	pcb_cardinal_t i, j;
 	/* find layer groups of the component side and solder side */
-	SLayer = pcb_layer_get_group(pcb_solder_silk_layer);
-	CLayer = pcb_layer_get_group(pcb_component_silk_layer);
+
+	pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &SLayer, 1);
+	pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &CLayer, 1);
+
 	/* update all nets */
 	for (i = 0; i < Nets->NetN; i++) {
 		for (j = 0; j < Nets->Net[i].ConnectionN; j++) {
diff --git a/src_plugins/autoroute/autoroute.c b/src_plugins/autoroute/autoroute.c
index 9033ee9..cee2350 100644
--- a/src_plugins/autoroute/autoroute.c
+++ b/src_plugins/autoroute/autoroute.c
@@ -76,6 +76,7 @@
 #include "layer.h"
 #include "compat_nls.h"
 #include "vtptr.h"
+#include "layer.h"
 #include "obj_all.h"
 
 #include "obj_line_draw.h"
@@ -630,7 +631,7 @@ static routebox_t *AddPad(vtptr_t layergroupboxes[], pcb_element_t *element, pcb
 	routebox_t **rbpp;
 	int layergroup = (PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, pad) ? back : front);
 	assert(0 <= layergroup && layergroup < pcb_max_group);
-	assert(PCB->LayerGroups.Number[layergroup] > 0);
+	assert(PCB->LayerGroups.grp[layergroup].len > 0);
 	rbpp = (routebox_t **) vtptr_alloc_append(&layergroupboxes[layergroup], 1);
 	assert(rbpp);
 	*rbpp = (routebox_t *) malloc(sizeof(**rbpp));
@@ -664,7 +665,7 @@ static routebox_t *AddLine(vtptr_t layergroupboxes[], int layergroup, pcb_line_t
 	routebox_t **rbpp;
 	assert(layergroupboxes && line);
 	assert(0 <= layergroup && layergroup < pcb_max_group);
-	assert(PCB->LayerGroups.Number[layergroup] > 0);
+	assert(PCB->LayerGroups.grp[layergroup].len > 0);
 
 	rbpp = (routebox_t **) vtptr_alloc_append(&layergroupboxes[layergroup], 1);
 	*rbpp = (routebox_t *) malloc(sizeof(**rbpp));
@@ -708,7 +709,7 @@ static routebox_t *AddIrregularObstacle(vtptr_t layergroupboxes[],
 	assert(layergroupboxes && parent);
 	assert(X1 <= X2 && Y1 <= Y2);
 	assert(0 <= layergroup && layergroup < pcb_max_group);
-	assert(PCB->LayerGroups.Number[layergroup] > 0);
+	assert(PCB->LayerGroups.grp[layergroup].len > 0);
 
 	rbpp = (routebox_t **) vtptr_alloc_append(&layergroupboxes[layergroup], 1);
 	*rbpp = (routebox_t *) malloc(sizeof(**rbpp));
@@ -858,20 +859,27 @@ static routedata_t *CreateRouteData()
 	/* check which layers are active first */
 	routing_layers = 0;
 	for (group = 0; group < pcb_max_group; group++) {
-		for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
-			/* layer must be 1) not silk (ie, < pcb_max_copper_layer) and 2) on */
-			if ((PCB->LayerGroups.Entries[group][i] < pcb_max_copper_layer) && PCB->Data->Layer[PCB->LayerGroups.Entries[group][i]].On) {
+		for (i = 0; i < PCB->LayerGroups.grp[group].len; i++) {
+			pcb_layer_id_t lid = PCB->LayerGroups.grp[group].lid[i];
+			/* layer must be 1) copper and 2) on */
+			if ((pcb_layer_flags(lid) & PCB_LYT_COPPER) && PCB->Data->Layer[lid].On) {
 				routing_layers++;
 				is_layer_group_active[group] = pcb_true;
 				break;
 			}
 			else
 				is_layer_group_active[group] = pcb_false;
+		}
 	}
 	/* if via visibility is turned off, don't use them */
 	AutoRouteParameters.use_vias = routing_layers > 1 && PCB->ViaOn;
-	front = pcb_layer_get_group(pcb_component_silk_layer);
-	back = pcb_layer_get_group(pcb_solder_silk_layer);
+
+	back = front = -1;
+	if (pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &back, 1) <= 0)
+		return NULL;
+	if (pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &front, 1) <= 0)
+		return NULL;
+
 	/* determine preferred routing direction on each group */
 	for (i = 0; i < pcb_max_group; i++) {
 		if (i != back && i != front) {
@@ -914,7 +922,7 @@ static routedata_t *CreateRouteData()
 	/* initialize pointer vectors */
 	for (i = 0; i < pcb_max_group; i++) {
 		vtptr_init(&layergroupboxes[i]);
-		GROUP_LOOP(PCB->Data, i);
+		PCB_COPPER_GROUP_LOOP(PCB->Data, i);
 		{
 			if (linelist_length(&layer->Line) || arclist_length(&layer->Arc))
 				usedGroup[i] = pcb_true;
@@ -1063,8 +1071,14 @@ static routedata_t *CreateRouteData()
 	}
 	PCB_END_LOOP;
 
-	for (i = 0; i < pcb_max_copper_layer; i++) {
-		pcb_layergrp_id_t layergroup = pcb_layer_get_group(i);
+	for (i = 0; i < pcb_max_layer; i++) {
+		pcb_layergrp_id_t layergroup;
+
+		if (!(pcb_layer_flags(i) & PCB_LYT_COPPER))
+			continue;
+
+		layergroup = pcb_layer_get_group(i);
+
 		/* add all (non-rat) lines */
 		PCB_LINE_LOOP(LAYER_PTR(i));
 		{
@@ -1315,7 +1329,8 @@ static pcb_box_t bloat_routebox(routebox_t * rb)
 static void showbox(pcb_box_t b, pcb_dimension_t thickness, int group)
 {
 	pcb_line_t *line;
-	pcb_layer_t *SLayer = LAYER_PTR(group);
+	pcb_layer_t *csl, *SLayer = LAYER_PTR(group);
+	pcb_layer_id_t cs_id;
 	if (showboxen < -1)
 		return;
 	if (showboxen != -1 && showboxen != group)
@@ -1333,19 +1348,22 @@ static void showbox(pcb_box_t b, pcb_dimension_t thickness, int group)
 	}
 
 #if 1
-	if (b.Y1 == b.Y2 || b.X1 == b.X2)
-		thickness = 5;
-	line = pcb_line_new(LAYER_PTR(pcb_component_silk_layer), b.X1, b.Y1, b.X2, b.Y1, thickness, 0, pcb_flag_make(0));
-	pcb_undo_add_obj_to_create(PCB_TYPE_LINE, LAYER_PTR(pcb_component_silk_layer), line, line);
-	if (b.Y1 != b.Y2) {
-		line = pcb_line_new(LAYER_PTR(pcb_component_silk_layer), b.X1, b.Y2, b.X2, b.Y2, thickness, 0, pcb_flag_make(0));
-		pcb_undo_add_obj_to_create(PCB_TYPE_LINE, LAYER_PTR(pcb_component_silk_layer), line, line);
-	}
-	line = pcb_line_new(LAYER_PTR(pcb_component_silk_layer), b.X1, b.Y1, b.X1, b.Y2, thickness, 0, pcb_flag_make(0));
-	pcb_undo_add_obj_to_create(PCB_TYPE_LINE, LAYER_PTR(pcb_component_silk_layer), line, line);
-	if (b.X1 != b.X2) {
-		line = pcb_line_new(LAYER_PTR(pcb_component_silk_layer), b.X2, b.Y1, b.X2, b.Y2, thickness, 0, pcb_flag_make(0));
-		pcb_undo_add_obj_to_create(PCB_TYPE_LINE, LAYER_PTR(pcb_component_silk_layer), line, line);
+	if (pcb_layer_find(PCB_LYT_TOP | PCB_LYT_SILK, &cs_id, 1) > 0)  {
+		csl = LAYER_PTR(cs_id);
+		if (b.Y1 == b.Y2 || b.X1 == b.X2)
+			thickness = 5;
+		line = pcb_line_new(csl, b.X1, b.Y1, b.X2, b.Y1, thickness, 0, pcb_flag_make(0));
+		pcb_undo_add_obj_to_create(csl, line, line);
+		if (b.Y1 != b.Y2) {
+			line = pcb_line_new(csl, b.X1, b.Y2, b.X2, b.Y2, thickness, 0, pcb_flag_make(0));
+			pcb_undo_add_obj_to_create(PCB_TYPE_LINE, csl, line, line);
+		}
+		line = pcb_line_new(csl, b.X1, b.Y1, b.X1, b.Y2, thickness, 0, pcb_flag_make(0));
+		pcb_undo_add_obj_to_create(PCB_TYPE_LINE, csl, line, line);
+		if (b.X1 != b.X2) {
+			line = pcb_line_new(csl, b.X2, b.Y1, b.X2, b.Y2, thickness, 0, pcb_flag_make(0));
+			pcb_undo_add_obj_to_create(PCB_TYPE_LINE, csl, line, line);
+		}
 	}
 #endif
 }
@@ -1385,7 +1403,9 @@ static void showedge(edge_t * e)
 #if defined(ROUTE_DEBUG)
 static void showroutebox(routebox_t * rb)
 {
-	showbox(rb->sbox, rb->flags.source ? 20 : (rb->flags.target ? 10 : 1), rb->flags.is_via ? pcb_component_silk_layer : rb->group);
+	pcb_layerid_t cs_id;
+	if (pcb_layer_find(PCB_LYT_TOP | PCB_LYT_SILK, &cs_id, 1) > 0)
+		showbox(rb->sbox, rb->flags.source ? 20 : (rb->flags.target ? 10 : 1), rb->flags.is_via ? LAYER_PTR(cs_id) : rb->group);
 }
 #endif
 
@@ -2981,7 +3001,7 @@ RD_DrawLine(routedata_t * rd,
 	pcb_r_insert_entry(rd->layergrouptree[rb->group], &rb->box, 1);
 
 	if (conf_core.editor.live_routing) {
-		pcb_layer_t *layer = LAYER_PTR(PCB->LayerGroups.Entries[rb->group][0]);
+		pcb_layer_t *layer = LAYER_PTR(PCB->LayerGroups.grp[rb->group].lid[0]);
 		pcb_line_t *line = pcb_line_new(layer, qX1, qY1, qX2, qY2,
 																					2 * qhthick, 0, pcb_flag_make(0));
 		rb->livedraw_obj.line = line;
@@ -4075,7 +4095,7 @@ pcb_bool no_expansion_boxes(routedata_t * rd)
 static void ripout_livedraw_obj(routebox_t * rb)
 {
 	if (rb->type == LINE && rb->livedraw_obj.line) {
-		pcb_layer_t *layer = LAYER_PTR(PCB->LayerGroups.Entries[rb->group][0]);
+		pcb_layer_t *layer = LAYER_PTR(PCB->LayerGroups.grp[rb->group].lid[0]);
 		EraseLine(rb->livedraw_obj.line);
 		pcb_destroy_object(PCB->Data, PCB_TYPE_LINE, layer, rb->livedraw_obj.line, NULL);
 		rb->livedraw_obj.line = NULL;
@@ -4436,10 +4456,10 @@ pcb_bool IronDownAllUnfixedPaths(routedata_t * rd)
 		{
 			if (!p->flags.fixed) {
 				/* find first on layer in this group */
-				assert(PCB->LayerGroups.Number[p->group] > 0);
+				assert(PCB->LayerGroups.grp[p->group].len > 0);
 				assert(is_layer_group_active[p->group]);
-				for (i = 0, layer = NULL; i < PCB->LayerGroups.Number[p->group]; i++) {
-					layer = LAYER_PTR(PCB->LayerGroups.Entries[p->group][i]);
+				for (i = 0, layer = NULL; i < PCB->LayerGroups.grp[p->group].len; i++) {
+					layer = LAYER_PTR(PCB->LayerGroups.grp[p->group].lid[i]);
 					if (layer->On)
 						break;
 				}
@@ -4559,6 +4579,10 @@ pcb_bool AutoRoute(pcb_bool selected)
 		return (pcb_false);
 	pcb_save_find_flag(PCB_FLAG_DRC);
 	rd = CreateRouteData();
+	if (rd == NULL) {
+		pcb_message(PCB_MSG_ERROR, "Failed to initialize data; might be missing\n" "top or bottom copper layer.\n");
+		return (pcb_false);
+	}
 
 	if (1) {
 		routebox_t *net, *rb, *last;
diff --git a/src_plugins/boardflip/boardflip.c b/src_plugins/boardflip/boardflip.c
index 465af74..3b48846 100644
--- a/src_plugins/boardflip/boardflip.c
+++ b/src_plugins/boardflip/boardflip.c
@@ -67,7 +67,7 @@ static int boardflip(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 	if (argc > 0 && pcb_strcasecmp(argv[0], "sides") == 0)
 		sides = 1;
 	printf("argc %d argv %s sides %d\n", argc, argc > 0 ? argv[0] : "", sides);
-	LAYER_LOOP(PCB->Data, pcb_max_copper_layer + 2);
+	LAYER_LOOP(PCB->Data, pcb_max_layer);
 	{
 		PCB_LINE_LOOP(layer);
 		{
diff --git a/src_plugins/diag/diag.c b/src_plugins/diag/diag.c
index 97e7c3f..2451bc7 100644
--- a/src_plugins/diag/diag.c
+++ b/src_plugins/diag/diag.c
@@ -151,12 +151,12 @@ static int pcb_act_DumpLayers(int argc, const char **argv, pcb_coord_t x, pcb_co
 	pcb_layergrp_id_t garr[128]; /* WARNING: this assumes we won't have more than 128 layers */
 
 
-	printf("Max: theoretical=%d current_board=%d\n", PCB_MAX_LAYER+2, pcb_max_copper_layer);
+	printf("Max: theoretical=%d current_board=%d\n", PCB_MAX_LAYER+2, pcb_max_layer);
 	used = pcb_layer_list_any(PCB_LYT_ANYTHING | PCB_LYT_ANYWHERE | PCB_LYT_VIRTUAL, arr, sizeof(arr)/sizeof(arr[0]));
 	for(n = 0; n < used; n++) {
 		pcb_layer_id_t layer_id = arr[n];
 		pcb_layergrp_id_t grp = pcb_layer_get_group(layer_id);
-		printf(" [%lx] %04x group=%d %s\n", layer_id, pcb_layer_flags(layer_id), grp, pcb_layer_name(layer_id));
+		printf(" [%lx] %04x group=%ld %s\n", layer_id, pcb_layer_flags(layer_id), grp, pcb_layer_name(layer_id));
 	}
 
 	/* query by logical layer: any bottom copper */
@@ -171,10 +171,10 @@ static int pcb_act_DumpLayers(int argc, const char **argv, pcb_coord_t x, pcb_co
 	used = pcb_layer_group_list(PCB_LYT_COPPER, garr, sizeof(garr)/sizeof(garr[0]));
 	printf("All %d groups containing copper layers are:\n", used);
 	for(g = 0; g < used; g++) {
-		int group_id = garr[g];
-		printf(" group %d\n", group_id);
-		for(n = 0; n < PCB->LayerGroups.Number[group_id]; n++) {
-			int layer_id = PCB->LayerGroups.Entries[group_id][n];
+		pcb_layergrp_id_t group_id = garr[g];
+		printf(" group %ld (%d layers)\n", group_id, PCB->LayerGroups.grp[group_id].len);
+		for(n = 0; n < PCB->LayerGroups.grp[group_id].len; n++) {
+			pcb_layer_id_t layer_id = PCB->LayerGroups.grp[group_id].lid[n];
 			printf("  [%lx] %s\n", layer_id, PCB->Data->Layer[layer_id].Name);
 		}
 	}
diff --git a/src_plugins/djopt/djopt.c b/src_plugins/djopt/djopt.c
index 00bb577..f800f83 100644
--- a/src_plugins/djopt/djopt.c
+++ b/src_plugins/djopt/djopt.c
@@ -469,7 +469,7 @@ static void new_line(corner_s * s, corner_s * e, int layer, pcb_line_t * example
 {
 	line_s *ls;
 
-	if (layer >= pcb_max_copper_layer)
+	if (!(pcb_layer_flags(layer) & PCB_LYT_COPPER))
 		dj_abort("layer %d\n", layer);
 
 	if (example == NULL)
@@ -1737,11 +1737,14 @@ static int vianudge()
 			counts[c->lines[i]->layer]++;
 			directions[c->lines[i]->layer] |= o;
 		}
-		for (o = 0, i = 0; i < pcb_max_copper_layer; i++)
+		for (o = 0, i = 0; i < pcb_max_layer; i++) {
+			if (!(pcb_layer_flags(i) & PCB_LYT_COPPER))
+				continue;
 			if (counts[i] == 1) {
 				o = directions[i];
 				break;
 			}
+		}
 		switch (o) {
 		case LEFT:
 		case RIGHT:
@@ -1754,10 +1757,12 @@ static int vianudge()
 		default:
 			continue;
 		}
-		for (i = 0; i < pcb_max_copper_layer; i++)
+		for (i = 0; i < pcb_max_layer; i++) {
+			if (!(pcb_layer_flags(i) & PCB_LYT_COPPER))
+				continue;
 			if (counts[i] && directions[i] != o && directions[i] != oboth)
 				goto vianudge_continue;
-
+		}
 		c2 = 0;
 		for (i = 0; i < c->n_lines; i++) {
 			int ll = line_length(c->lines[i]);
@@ -2288,7 +2293,9 @@ static void pinsnap()
 			}
 
 			dprintf("%s x %#mS-%#mS y %#mS-%#mS\n", corner_name(c), left, right, bottom, top);
-			for (l = 0; l <= pcb_max_copper_layer; l++) {
+			for (l = 0; l <= pcb_max_layer; l++) {
+				if (!(pcb_layer_flags(l) & PCB_LYT_COPPER))
+					continue;
 				best_dist[l] = close * 2;
 				best_c[l] = 0;
 			}
@@ -2321,10 +2328,10 @@ static void pinsnap()
 					}
 				}
 				if (!got_one && c->n_lines == (c->pad ? 1 : 0)) {
-					for (l = 0; l <= pcb_max_copper_layer; l++)
+					for (l = 0; l <= pcb_max_layer; l++)
 						if (best_c[l])
 							dprintf("best[%d] = %s\n", l, corner_name(best_c[l]));
-					for (l = 0; l <= pcb_max_copper_layer; l++)
+					for (l = 0; l <= pcb_max_layer; l++)
 						if (best_c[l]) {
 							dprintf("move %s to %s\n", corner_name(best_c[l]), corner_name(c));
 							connect_corners(best_c[l], c);
@@ -2461,29 +2468,30 @@ static void padcleaner()
 static void grok_layer_groups()
 {
 	int i, j, f;
-	pcb_layer_group_t *l = &(PCB->LayerGroups);
+	pcb_layer_stack_t *l = &(PCB->LayerGroups);
 
 	solder_layer = component_layer = -1;
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		layer_type[i] = 0;
 		layer_groupings[i] = 0;
 	}
 	for (i = 0; i < pcb_max_group; i++) {
 		f = 0;
-		for (j = 0; j < l->Number[i]; j++) {
-			if (l->Entries[i][j] == pcb_solder_silk_layer)
+		for (j = 0; j < l->grp[i].len; j++) {
+			unsigned int lflg = pcb_layer_flags(l->grp[i].lid[j]);
+			if (lflg & PCB_LYT_BOTTOM)
 				f |= LT_SOLDER;
-			if (l->Entries[i][j] == pcb_component_silk_layer)
+			if (lflg & PCB_LYT_TOP)
 				f |= LT_COMPONENT;
 		}
-		for (j = 0; j < l->Number[i]; j++) {
-			if (l->Entries[i][j] < pcb_max_copper_layer) {
-				layer_type[l->Entries[i][j]] |= f;
-				layer_groupings[l->Entries[i][j]] = i;
+		for (j = 0; j < l->grp[i].len; j++) {
+			if (l->grp[i].lid[j] < pcb_max_layer) {
+				layer_type[l->grp[i].lid[j]] |= f;
+				layer_groupings[l->grp[i].lid[j]] = i;
 				if (solder_layer == -1 && f == LT_SOLDER)
-					solder_layer = l->Entries[i][j];
+					solder_layer = l->grp[i].lid[j];
 				if (component_layer == -1 && f == LT_COMPONENT)
-					component_layer = l->Entries[i][j];
+					component_layer = l->grp[i].lid[j];
 			}
 		}
 	}
@@ -2605,9 +2613,12 @@ static int pcb_act_DJopt(int argc, const char **argv, pcb_coord_t x, pcb_coord_t
 		return 0;
 	}
 
-	for (layn = 0; layn < pcb_max_copper_layer; layn++) {
+	for (layn = 0; layn < pcb_max_layer; layn++) {
 		pcb_layer_t *layer = LAYER_PTR(layn);
 
+		if (!(pcb_layer_flags(layn) & PCB_LYT_COPPER))
+			continue;
+
 		PCB_LINE_LOOP(layer);
 		{
 			line_s *ls;
diff --git a/src_plugins/draw_csect/Makefile b/src_plugins/draw_csect/Makefile
new file mode 100644
index 0000000..25ea1bd
--- /dev/null
+++ b/src_plugins/draw_csect/Makefile
@@ -0,0 +1,6 @@
+all:
+	cd ../../src && $(MAKE) mod_draw_csect
+
+clean:
+	rm *.o *.so 2>/dev/null ; true
+
diff --git a/src_plugins/draw_csect/Plug.tmpasm b/src_plugins/draw_csect/Plug.tmpasm
new file mode 100644
index 0000000..2f8e122
--- /dev/null
+++ b/src_plugins/draw_csect/Plug.tmpasm
@@ -0,0 +1,10 @@
+put /local/pcb/mod {draw_csect}
+append /local/pcb/mod/OBJS [@
+	$(PLUGDIR)/draw_csect/draw_csect.o
+@]
+
+switch /local/pcb/draw_csect/controls
+	case {buildin}   include /local/pcb/tmpasm/buildin; end;
+	case {plugin}    include /local/pcb/tmpasm/plugin; end;
+	case {disable}   include /local/pcb/tmpasm/disable; end;
+end
diff --git a/src_plugins/draw_csect/README b/src_plugins/draw_csect/README
new file mode 100644
index 0000000..9d57049
--- /dev/null
+++ b/src_plugins/draw_csect/README
@@ -0,0 +1,5 @@
+Draw cross section and layer map.
+
+#state: WIP
+#default: buildin
+#implements: (feature)
diff --git a/src_plugins/draw_csect/draw_csect.c b/src_plugins/draw_csect/draw_csect.c
new file mode 100644
index 0000000..32b5b34
--- /dev/null
+++ b/src_plugins/draw_csect/draw_csect.c
@@ -0,0 +1,709 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* draw cross section */
+#include "config.h"
+
+
+#include "board.h"
+#include "data.h"
+#include "draw.h"
+#include "plugins.h"
+#include "stub_draw_csect.h"
+#include "compat_misc.h"
+#include "hid_actions.h"
+
+#include "obj_text_draw.h"
+#include "obj_line_draw.h"
+
+static const char *COLOR_ANNOT = "#000000";
+static const char *COLOR_BG = "#f0f0f0";
+
+static const char *COLOR_COPPER = "#C05020";
+static const char *COLOR_SUBSTRATE = "#E0D090";
+static const char *COLOR_SILK = "#000000";
+static const char *COLOR_MASK = "#30d030";
+static const char *COLOR_PASTE = "#60e0e0";
+static const char *COLOR_MISC = "#e0e000";
+static const char *COLOR_OUTLINE = "#000000";
+
+static pcb_layer_id_t drag_lid = -1;
+static pcb_layergrp_id_t drag_gid = -1, drag_gid_subst = -1;
+
+#define GROUP_WIDTH_MM 75
+
+/* Draw a text at x;y sized scale percentage */
+static pcb_text_t *dtext(int x, int y, int scale, int dir, const char *txt)
+{
+	static pcb_text_t t;
+
+	t.X = PCB_MM_TO_COORD(x);
+	t.Y = PCB_MM_TO_COORD(y);
+	t.TextString = (char *)txt;
+	t.Direction = dir;
+	t.Scale = scale;
+	t.Flags = pcb_no_flags();
+	DrawTextLowLevel(&t, 0);
+	return &t;
+}
+
+/* Draw a text at x;y sized scale percentage */
+static pcb_text_t *dtext_(pcb_coord_t x, pcb_coord_t y, int scale, int dir, const char *txt, pcb_coord_t th)
+{
+	static pcb_text_t t;
+
+	t.X = x;
+	t.Y = y;
+	t.TextString = (char *)txt;
+	t.Direction = dir;
+	t.Scale = scale;
+	t.Flags = pcb_no_flags();
+	DrawTextLowLevel(&t, th);
+	return &t;
+}
+
+/* Draw a text at x;y with a background */
+static pcb_text_t *dtext_bg(pcb_hid_gc_t gc, int x, int y, int scale, int dir, const char *txt, const char *bgcolor, const char *fgcolor)
+{
+	static pcb_text_t t;
+
+	t.X = PCB_MM_TO_COORD(x);
+	t.Y = PCB_MM_TO_COORD(y);
+	t.TextString = (char *)txt;
+	t.Direction = dir;
+	t.Scale = scale;
+	t.Flags = pcb_no_flags();
+
+	pcb_gui->set_color(gc, bgcolor);
+	DrawTextLowLevel(&t, 1000000);
+
+	pcb_gui->set_color(gc, fgcolor);
+	DrawTextLowLevel(&t, 0);
+
+	return &t;
+}
+
+/* draw a line of a specific thickness */
+static void dline(int x1, int y1, int x2, int y2, float thick)
+{
+	pcb_line_t l;
+	l.Point1.X = PCB_MM_TO_COORD(x1);
+	l.Point1.Y = PCB_MM_TO_COORD(y1);
+	l.Point2.X = PCB_MM_TO_COORD(x2);
+	l.Point2.Y = PCB_MM_TO_COORD(y2);
+	l.Thickness = PCB_MM_TO_COORD(thick);
+	_draw_line(&l);
+}
+
+/* draw a line of a specific thickness */
+static void dline_(pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2, float thick)
+{
+	pcb_line_t l;
+	l.Point1.X = x1;
+	l.Point1.Y = y1;
+	l.Point2.X = x2;
+	l.Point2.Y = y2;
+	l.Thickness = PCB_MM_TO_COORD(thick);
+	_draw_line(&l);
+}
+
+
+/* draw a line clipped with two imaginary vertical lines at cx1 and cx2 */
+static void dline_vclip(int x1, int y1, int x2, int y2, float thick, int cx1, int cx2)
+{
+	if (cx2 < cx1) { /* make sure cx2 > cx1 */
+		int tmp;
+		tmp = cx1;
+		cx1 = cx2;
+		cx2 = tmp;
+	}
+
+	if (x2 == x1) { /* do not clip vertical lines */
+		if ((x1 >= cx1) && (x1 <= cx2))
+			dline(x1, y1, x2, y2, thick);
+		return;
+	}
+
+	if (x2 < x1) { /* make sure x2 > x1 */
+		int tmp;
+		tmp = x1;
+		x1 = x2;
+		x2 = tmp;
+		tmp = y1;
+		y1 = y2;
+		y2 = tmp;
+	}
+
+	/* clip */
+	if (x2 > cx2) {
+		y2 = (double)(cx2 - x1) / (double)(x2 - x1) * (double)(y2 - y1) + y1;
+		x2 = cx2;
+	}
+	if (x1 < cx1) {
+		y1 = (double)(cx1 - x1) / (double)(x2 - x1) * (double)(y2 - y1) + y1;
+		x1 = cx1;
+	}
+
+	dline(x1, y1, x2, y2, thick);
+}
+
+
+/* Draw a 45-deg hactched box wihtout the rectangle;
+   if step > 0 use \ hatching, else use / */
+static void hatch_box(int x1, int y1, int x2, int y2, float thick, int step)
+{
+	int n, h = y2 - y1;
+
+	if (step > 0)
+		for(n = x1 - h; n <= x2; n += step)
+			dline_vclip(n, y1, n+h, y2, thick,  x1, x2);
+	else
+		for(n = x2; n >= x1-h; n += step)
+			dline_vclip(n+h, y1, n, y2, thick,  x1, x2);
+}
+
+enum {
+	OMIT_NONE = 0,
+	OMIT_TOP = 1,
+	OMIT_BOTTOM = 2,
+	OMIT_LEFT = 4,
+	OMIT_RIGHT = 8
+};
+
+/* draw a hatched rectangle; to turn off hatching in a directon set the
+   corresponding step to 0 */
+static void dhrect(int x1, int y1, int x2, int y2, float thick_rect, float thick_hatch, int step_fwd, int step_back, unsigned omit)
+{
+	if (!(omit & OMIT_TOP))
+		dline(x1, y1, x2, y1, thick_rect);
+	if (!(omit & OMIT_RIGHT))
+		dline(x2, y1, x2, y2, thick_rect);
+	if (!(omit & OMIT_BOTTOM))
+		dline(x1, y2, x2, y2, thick_rect);
+	if (!(omit & OMIT_LEFT))
+		dline(x1, y1, x1, y2, thick_rect);
+
+	if (step_fwd > 0)
+		hatch_box(x1, y1, x2, y2, thick_hatch, +step_fwd);
+
+	if (step_back > 0)
+		hatch_box(x1, y1, x2, y2, thick_hatch, -step_back);
+}
+
+static pcb_box_t btn_addgrp, btn_delgrp;
+static pcb_box_t layer_crd[PCB_MAX_LAYER];
+static pcb_box_t group_crd[PCB_MAX_LAYERGRP];
+static char layer_valid[PCB_MAX_LAYER];
+static char group_valid[PCB_MAX_LAYERGRP];
+
+static void reg_layer_coords(pcb_layer_id_t lid, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2)
+{
+	if ((lid < 0) || (lid >= PCB_MAX_LAYER))
+		return;
+	layer_crd[lid].X1 = x1;
+	layer_crd[lid].Y1 = y1;
+	layer_crd[lid].X2 = x2;
+	layer_crd[lid].Y2 = y2;
+	layer_valid[lid] = 1;
+}
+
+static void reg_group_coords(pcb_layergrp_id_t gid, pcb_coord_t y1, pcb_coord_t y2)
+{
+	if ((gid < 0) || (gid >= PCB_MAX_LAYER))
+		return;
+	group_crd[gid].Y1 = y1;
+	group_crd[gid].Y2 = y2;
+	group_valid[gid] = 1;
+}
+
+static void reset_layer_coords(void)
+{
+	memset(layer_valid, 0, sizeof(layer_valid));
+	memset(group_valid, 0, sizeof(group_valid));
+}
+
+static pcb_layer_id_t get_layer_coords(pcb_coord_t x, pcb_coord_t y)
+{
+	pcb_layer_id_t n;
+
+	for(n = 0; n < PCB_MAX_LAYER; n++) {
+		if (!layer_valid[n]) continue;
+		if ((layer_crd[n].X1 <= x) && (layer_crd[n].Y1 <= y) &&
+		    (layer_crd[n].X2 >= x) && (layer_crd[n].Y2 >= y))
+			return n;
+	}
+	return -1;
+}
+
+static pcb_layergrp_id_t get_group_coords(pcb_coord_t y, pcb_coord_t *y1, pcb_coord_t *y2)
+{
+	pcb_layergrp_id_t n;
+
+	for(n = 0; n < PCB_MAX_LAYERGRP; n++) {
+		if (!group_valid[n]) continue;
+		if ((group_crd[n].Y1 <= y) && (group_crd[n].Y2 >= y)) {
+			*y1 = group_crd[n].Y1;
+			*y2 = group_crd[n].Y2;
+			return n;
+		}
+	}
+	return -1;
+}
+
+static pcb_coord_t create_button(pcb_hid_gc_t gc, int x, int y, const char *label, pcb_box_t *box)
+{
+	pcb_text_t *t;
+	t = dtext_bg(gc, x, y, 200, 0, label, COLOR_BG, COLOR_ANNOT);
+	pcb_text_bbox(&PCB->Font, t);
+	dhrect(PCB_COORD_TO_MM(t->BoundingBox.X1), y, PCB_COORD_TO_MM(t->BoundingBox.X2)+1, y+4, 0.25, 0, 0, 0, OMIT_NONE);
+	box->X1 = t->BoundingBox.X1;
+	box->Y1 = PCB_MM_TO_COORD(y);
+	box->X2 = t->BoundingBox.X2+PCB_MM_TO_COORD(1);
+	box->Y2 = PCB_MM_TO_COORD(y+4);
+	return PCB_COORD_TO_MM(box->X2);
+}
+
+static int is_button(int x, int y, const pcb_box_t *box)
+{
+	return (x >= box->X1) && (x <= box->X2) && (y >= box->Y1) && (y <= box->Y2);
+}
+
+static pcb_hid_gc_t csect_gc;
+
+/* Draw the cross-section layer */
+static void draw_csect(pcb_hid_gc_t gc)
+{
+	pcb_layergrp_id_t gid;
+	int ystart = 10, x, y, last_copper_step = 5, has_outline = 0;
+
+	reset_layer_coords();
+	csect_gc = gc;
+
+	pcb_gui->set_color(gc, COLOR_ANNOT);
+	dtext(0, 0, 500, 0, "Board cross section");
+
+	/* draw physical layers */
+	y = ystart;
+	for(gid = 0; gid < pcb_max_group; gid++) {
+		int i, stepf = 0, stepb = 0, th;
+		pcb_layer_group_t *g = PCB->LayerGroups.grp + gid;
+		const char *color = "#ff0000";
+
+		if ((!g->valid) || (gid == drag_gid)  || (gid == drag_gid_subst))
+			continue;
+		else if (g->type & PCB_LYT_COPPER) {
+			last_copper_step = -last_copper_step;
+			if (last_copper_step > 0)
+				stepf = last_copper_step;
+			else
+				stepb = -last_copper_step;
+			th = 5;
+			color = COLOR_COPPER;
+		}
+		else if (g->type & PCB_LYT_SUBSTRATE) {
+			stepf = stepb = 7;
+			th = 10;
+			color = COLOR_SUBSTRATE;
+		}
+		else if (g->type & PCB_LYT_SILK) {
+			th = 5;
+			color = COLOR_SILK;
+			stepb = 3;
+		}
+		else if (g->type & PCB_LYT_MASK) {
+			th = 5;
+			color = COLOR_MASK;
+			stepb = 9;
+		}
+		else if (g->type & PCB_LYT_PASTE) {
+			th = 5;
+			color = COLOR_PASTE;
+			stepf = 9;
+		}
+		else if (g->type & PCB_LYT_MISC) {
+			th = 5;
+			color = COLOR_MISC;
+			stepf = 3;
+		}
+		else if (g->type & PCB_LYT_OUTLINE) {
+			has_outline = 1;
+			continue;
+		}
+		else
+			continue;
+
+		pcb_gui->set_color(gc, color);
+		dhrect(0, y, GROUP_WIDTH_MM, y+th,  1, 0.5,  stepf, stepb, OMIT_LEFT | OMIT_RIGHT);
+		dtext_bg(gc, 5, y, 200, 0, g->name, COLOR_BG, COLOR_ANNOT);
+		reg_group_coords(gid, PCB_MM_TO_COORD(y), PCB_MM_TO_COORD(y+th));
+
+
+		/* draw layer names */
+		if (g->type & PCB_LYT_COPPER) {
+			x = GROUP_WIDTH_MM + 3;
+			for(i = 0; i < g->len; i++) {
+				pcb_text_t *t;
+				pcb_layer_id_t lid = g->lid[i];
+				pcb_layer_t *l = &PCB->Data->Layer[lid];
+				if (lid == drag_lid)
+					continue;
+				t = dtext_bg(gc, x, y, 200, 0, l->Name, COLOR_BG, l->Color);
+				pcb_text_bbox(&PCB->Font, t);
+				x += PCB_COORD_TO_MM(t->BoundingBox.X2 - t->BoundingBox.X1) + 3;
+				dhrect(PCB_COORD_TO_MM(t->BoundingBox.X1), y, PCB_COORD_TO_MM(t->BoundingBox.X2)+1, y+4, 0.25, 0, 0, 0, OMIT_NONE);
+				reg_layer_coords(lid, t->BoundingBox.X1, PCB_MM_TO_COORD(y), t->BoundingBox.X2+PCB_MM_TO_COORD(1), PCB_MM_TO_COORD(y+4));
+			}
+		}
+
+		/* increment y */
+		y += th + 1;
+	}
+
+	/* draw global/special layers */
+	if (has_outline) {
+		pcb_gui->set_color(gc, COLOR_OUTLINE);
+		dline(0, ystart, 0, y+10, 1);
+		dtext_bg(gc, 1, y+7, 200, 0, "outline", COLOR_BG, COLOR_ANNOT);
+	}
+
+	y+=7;
+	x=20;
+	x = 2 + create_button(gc, x, y, "Add copper group", &btn_addgrp);
+	x = 2 + create_button(gc, x, y, "Del copper group", &btn_delgrp);
+}
+
+static pcb_coord_t ox, oy, lx, ly, cx, cy, gy1, gy2;
+static int lvalid, gvalid, dgvalid, drag_addgrp, drag_delgrp;
+static pcb_layergrp_id_t gactive = -1;
+
+typedef enum {
+	MARK_GRP_FRAME,
+	MARK_GRP_MIDDLE,
+	MARK_GRP_TOP
+} mark_grp_loc_t;
+
+static void mark_grp(pcb_coord_t y, unsigned int accept_mask, mark_grp_loc_t loc)
+{
+	pcb_coord_t y1, y2, x0 = -PCB_MM_TO_COORD(5);
+	pcb_layergrp_id_t g;
+
+	g = get_group_coords(y, &y1, &y2);
+
+	if ((y1 == gy1) && (y2 == gy2) && gvalid)
+		return;
+	if (gvalid) {
+		switch(loc) {
+			case MARK_GRP_FRAME:
+				dline_(x0, gy1, PCB_MM_TO_COORD(200), gy1, 0.1);
+				dline_(x0, gy2, PCB_MM_TO_COORD(200), gy2, 0.1);
+				break;
+			case MARK_GRP_MIDDLE:
+				dline_(x0, (gy1+gy2)/2, PCB_MM_TO_COORD(200), (gy1+gy2)/2, 0.1);
+				break;
+			case MARK_GRP_TOP:
+				dline_(x0, gy1, PCB_MM_TO_COORD(200), gy1, 0.1);
+		}
+		gvalid = 0;
+	}
+
+	if ((g >= 0) && ((pcb_layergrp_flags(g) & accept_mask) == accept_mask)) {
+		gy1 = y1;
+		gy2 = y2;
+		gactive = g;
+		gvalid = 1;
+		switch(loc) {
+			case MARK_GRP_FRAME:
+				dline_(x0, y1, PCB_MM_TO_COORD(200), y1, 0.1);
+				dline_(x0, y2, PCB_MM_TO_COORD(200), y2, 0.1);
+				break;
+			case MARK_GRP_MIDDLE:
+				dline_(x0, (y1+y2)/2, PCB_MM_TO_COORD(200), (y1+y2)/2, 0.1);
+				break;
+			case MARK_GRP_TOP:
+				dline_(x0, y1, PCB_MM_TO_COORD(200), y1, 0.1);
+				break;
+		}
+	}
+	else
+		gactive = -1;
+}
+
+static void draw_hover_label(int *valid, const char *str)
+{
+	int x0 = PCB_MM_TO_COORD(2.5); /* compensate for the mouse cursor (sort of random) */
+	if ((lx != cx) || (ly != cy)) {
+		if (*valid)
+			dtext_(lx+x0, ly, 250, 0, str, PCB_MM_TO_COORD(0.01));
+		dtext_(cx+x0, cy, 250, 0, str, PCB_MM_TO_COORD(0.01));
+		lx = cx;
+		ly = cy;
+		*valid = 1;
+	}
+}
+
+static void draw_csect_overlay(pcb_hid_t *hid, const pcb_hid_expose_ctx_t *ctx)
+{
+	if ((drag_lid >= 0) || (drag_addgrp) || (drag_delgrp) || (drag_gid >= 0)) {
+		pcb_hid_t *old_gui = pcb_gui;
+		pcb_gui = hid;
+		Output.fgGC = pcb_gui->make_gc();
+
+		pcb_gui->set_color(Output.fgGC, "#000000");
+		pcb_gui->set_draw_xor(Output.fgGC, 1);
+
+		/* draw the actual operation */
+		if (drag_addgrp) {
+			mark_grp(cy, PCB_LYT_SUBSTRATE, MARK_GRP_MIDDLE);
+			draw_hover_label(&lvalid, "INSERT");
+		}
+		if (drag_delgrp) {
+			mark_grp(cy, PCB_LYT_COPPER | PCB_LYT_INTERN, MARK_GRP_FRAME);
+			draw_hover_label(&lvalid, "DEL");
+		}
+		else if (drag_lid >= 0) {
+			pcb_layer_t *l = &PCB->Data->Layer[drag_lid];
+			draw_hover_label(&lvalid, l->Name);
+			mark_grp(cy, PCB_LYT_COPPER, MARK_GRP_FRAME);
+		}
+		else if (drag_gid >= 0) {
+			pcb_layer_group_t *g = &PCB->LayerGroups.grp[drag_gid];
+			const char *name = g->name == NULL ? "<unnamed group>" : g->name;
+			draw_hover_label(&dgvalid, name);
+			mark_grp(cy, PCB_LYT_COPPER | PCB_LYT_INTERN, MARK_GRP_TOP);
+			if (gactive < 0)
+				mark_grp(cy, PCB_LYT_COPPER | PCB_LYT_BOTTOM, MARK_GRP_TOP);
+			if (gactive < 0)
+				mark_grp(cy, PCB_LYT_SUBSTRATE, MARK_GRP_TOP);
+		}
+
+		pcb_gui->destroy_gc(Output.fgGC);
+		pcb_gui = old_gui;
+	}
+}
+
+static void do_move_grp()
+{
+	unsigned int tflg;
+
+	if ((gactive < 0) || (gactive == drag_gid+1))
+		return;
+
+	tflg = pcb_layergrp_flags(gactive);
+
+	pcb_layergrp_move(&PCB->LayerGroups, drag_gid, gactive);
+
+	if (drag_gid_subst >= 0) {
+		if ((drag_gid < drag_gid_subst) && (gactive > drag_gid))
+			drag_gid_subst--; /* the move shifted this down one slot */
+
+		if (gactive < drag_gid_subst)
+			drag_gid_subst++; /* the move shifted this up one slot */
+
+		if (tflg & PCB_LYT_COPPER) {
+			if (tflg & PCB_LYT_BOTTOM)
+				pcb_layergrp_move(&PCB->LayerGroups, drag_gid_subst, gactive);
+			else
+				pcb_layergrp_move(&PCB->LayerGroups, drag_gid_subst, gactive+1);
+		}
+		else if (tflg & PCB_LYT_SUBSTRATE) {
+			if (gactive < drag_gid)
+				pcb_layergrp_move(&PCB->LayerGroups, drag_gid_subst, gactive);
+			else
+				pcb_layergrp_move(&PCB->LayerGroups, drag_gid_subst, gactive-1);
+		}
+	}
+}
+
+
+static pcb_bool mouse_csect(void *widget, pcb_hid_mouse_ev_t kind, pcb_coord_t x, pcb_coord_t y)
+{
+	pcb_bool res = 0;
+	switch(kind) {
+		case PCB_HID_MOUSE_PRESS:
+			if (is_button(x, y, &btn_addgrp)) {
+				drag_addgrp = 1;
+				res = 1;
+				break;
+			}
+
+			if (is_button(x, y, &btn_delgrp)) {
+				drag_delgrp = 1;
+				res = 1;
+				break;
+			}
+
+			drag_lid = get_layer_coords(x, y);
+			if (drag_lid >= 0) {
+				ox = x;
+				oy = y;
+				lvalid = 0;
+				res = 1;
+				break;
+			}
+			
+			if ((x > 0) && (x < PCB_MM_TO_COORD(GROUP_WIDTH_MM))) {
+				pcb_coord_t tmp;
+				pcb_layergrp_id_t gid;
+				gid = get_group_coords(y, &tmp, &tmp);
+				if ((gid >= 0) && (pcb_layergrp_flags(gid) & PCB_LYT_COPPER) && (pcb_layergrp_flags(gid) & PCB_LYT_INTERN)) {
+					gvalid = 0;
+					drag_gid = gid;
+					/* temporary workaround for the restricted setup */
+					if (pcb_layergrp_flags(gid - 1) & PCB_LYT_SUBSTRATE)
+						drag_gid_subst = gid - 1;
+					else if ((pcb_layergrp_flags(gid - 1) & PCB_LYT_OUTLINE) && (pcb_layergrp_flags(gid - 2) & PCB_LYT_SUBSTRATE))
+						drag_gid_subst = gid - 2;
+					res = 1;
+				}
+			}
+			break;
+		case PCB_HID_MOUSE_RELEASE:
+			if (drag_addgrp) {
+				if (gactive >= 0) {
+					pcb_layer_group_t *g;
+					g = pcb_layergrp_insert_after(&PCB->LayerGroups, gactive);
+					g->name = NULL;
+					g->type = PCB_LYT_INTERN | PCB_LYT_SUBSTRATE;
+					g->valid = 1;
+					g = pcb_layergrp_insert_after(&PCB->LayerGroups, gactive);
+					g->name = pcb_strdup("Intern");
+					g->type = PCB_LYT_INTERN | PCB_LYT_COPPER;
+					g->valid = 1;
+				}
+				drag_addgrp = 0;
+				gactive = -1;
+				res = 1;
+				lvalid = gvalid = 0;
+			}
+			else if (drag_delgrp) {
+				if (gactive >= 0) {
+					pcb_layergrp_del(&PCB->LayerGroups, gactive, 1);
+					if (pcb_layergrp_flags(gactive) & PCB_LYT_SUBSTRATE)
+						pcb_layergrp_del(&PCB->LayerGroups, gactive, 1);
+					else if (pcb_layergrp_flags(gactive-1) & PCB_LYT_SUBSTRATE)
+						pcb_layergrp_del(&PCB->LayerGroups, gactive-1, 1);
+				}
+				drag_delgrp = 0;
+				gactive = -1;
+				res = 1;
+				lvalid = gvalid = 0;
+			}
+			else if (drag_lid >= 0) {
+				if (gactive >= 0) {
+					pcb_layer_t *l = &PCB->Data->Layer[drag_lid];
+					if (l->grp != gactive) {
+						pcb_layer_move_to_group(drag_lid, gactive);
+						pcb_message(PCB_MSG_INFO, "moved layer %s to group %d\n", l->Name, gactive);
+					}
+				}
+				else
+					pcb_message(PCB_MSG_ERROR, "Can not move copper layer onto non-copper layer group\n");
+				res = 1;
+				drag_lid = -1;
+				lvalid = gvalid = 0;
+				gactive = -1;
+			}
+			else if (drag_gid > 0) {
+				do_move_grp();
+				res = 1;
+				drag_gid = -1;
+				drag_gid_subst = -1;
+				lvalid = gvalid = 0;
+			}
+			break;
+		case PCB_HID_MOUSE_MOTION:
+			cx = x;
+			cy = y;
+			break;
+	}
+	return res;
+}
+
+
+
+
+static const char pcb_acts_dump_csect[] = "DumpCsect()";
+static const char pcb_acth_dump_csect[] = "Print the cross-section of the board (layer stack)";
+
+static int pcb_act_dump_csect(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	pcb_layergrp_id_t gid;
+
+	for(gid = 0; gid < pcb_max_group; gid++) {
+		int i;
+		const char *type_gfx;
+		pcb_layer_group_t *g = PCB->LayerGroups.grp + gid;
+
+		if (!g->valid) {
+			if (g->len <= 0)
+				continue;
+			type_gfx = "old";
+		}
+		else if (g->type & PCB_LYT_VIRTUAL) continue;
+		else if (g->type & PCB_LYT_COPPER) type_gfx = "====";
+		else if (g->type & PCB_LYT_SUBSTRATE) type_gfx = "xxxx";
+		else if (g->type & PCB_LYT_SILK) type_gfx = "silk";
+		else if (g->type & PCB_LYT_MASK) type_gfx = "mask";
+		else if (g->type & PCB_LYT_PASTE) type_gfx = "pst.";
+		else if (g->type & PCB_LYT_MISC) type_gfx = "misc";
+		else if (g->type & PCB_LYT_OUTLINE) type_gfx = "||||";
+		else type_gfx = "????";
+
+		printf("%s {%ld} %s\n", type_gfx, gid, g->name);
+		for(i = 0; i < g->len; i++) {
+			pcb_layer_id_t lid = g->lid[i];
+			pcb_layer_t *l = &PCB->Data->Layer[lid];
+			printf("      [%ld] %s\n", lid, l->Name);
+			if (l->grp != gid)
+				printf("         *** broken layer-to-group cross reference: %ld\n", l->grp);
+		}
+	}
+	return 0;
+}
+
+static const char *draw_csect_cookie = "draw_csect";
+
+pcb_hid_action_t draw_csect_action_list[] = {
+	{"DumpCsect", 0, pcb_act_dump_csect,
+	 pcb_acth_dump_csect, pcb_acts_dump_csect}
+};
+
+
+PCB_REGISTER_ACTIONS(draw_csect_action_list, draw_csect_cookie)
+
+static void hid_draw_csect_uninit(void)
+{
+	pcb_hid_remove_actions_by_cookie(draw_csect_cookie);
+}
+
+#include "dolists.h"
+
+pcb_uninit_t hid_draw_csect_init(void)
+{
+	PCB_REGISTER_ACTIONS(draw_csect_action_list, draw_csect_cookie)
+
+	pcb_stub_draw_csect = draw_csect;
+	pcb_stub_draw_csect_mouse_ev = mouse_csect;
+	pcb_stub_draw_csect_overlay = draw_csect_overlay;
+
+	return hid_draw_csect_uninit;
+}
diff --git a/src_plugins/draw_fab/draw_fab.c b/src_plugins/draw_fab/draw_fab.c
index cad2d69..94dfa18 100644
--- a/src_plugins/draw_fab/draw_fab.c
+++ b/src_plugins/draw_fab/draw_fab.c
@@ -171,7 +171,7 @@ static int DrawFab_overhang(void)
 static void DrawFab(pcb_hid_gc_t gc)
 {
 	DrillInfoTypePtr AllDrills;
-	int i, n, yoff, total_drills = 0, ds = 0;
+	int i, n, yoff, total_drills = 0, ds = 0, found;
 	char utcTime[64];
 	AllDrills = GetDrillInfo(PCB->Data);
 	RoundDrillInfo(AllDrills, PCB_MIL_TO_COORD(1));
@@ -242,16 +242,14 @@ static void DrawFab(pcb_hid_gc_t gc)
 		strcpy(utcTime, "<date>");
 
 	yoff = -TEXT_LINE;
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for (found = 0, i = 0; i < pcb_max_layer; i++) {
 		pcb_layer_t *l = LAYER_PTR(i);
-		if (l->Name && (linelist_length(&l->Line) || arclist_length(&l->Arc))) {
-			if (strcmp("route", l->Name) == 0)
-				break;
-			if (strcmp("outline", l->Name) == 0)
-				break;
+		if ((pcb_layer_flags(i) & PCB_LYT_OUTLINE) && (linelist_length(&l->Line) || arclist_length(&l->Arc))) {
+			found = 1;
+			break;
 		}
 	}
-	if (i == pcb_max_copper_layer) {
+	if (!found) {
 		pcb_gui->set_line_width(gc, PCB_MIL_TO_COORD(10));
 		pcb_gui->draw_line(gc, 0, 0, PCB->MaxWidth, 0);
 		pcb_gui->draw_line(gc, 0, 0, 0, PCB->MaxHeight);
diff --git a/src_plugins/export_bboard/bboard.c b/src_plugins/export_bboard/bboard.c
index 6e9d0db..c6a3ca7 100644
--- a/src_plugins/export_bboard/bboard.c
+++ b/src_plugins/export_bboard/bboard.c
@@ -43,6 +43,7 @@
 #include "error.h"
 #include "buffer.h"
 #include "layer.h"
+#include "layer_grp.h"
 #include "plugins.h"
 #include "compat_misc.h"
 #include "compat_fs.h"
@@ -480,7 +481,7 @@ static void bboard_do_export(pcb_hid_attr_val_t * options)
 	int i;
 	int clr_r, clr_g, clr_b;
 	pcb_layer_t *layer;
-
+	pcb_layergrp_id_t gtop, gbottom;
 
 	if (!options) {
 		bboard_get_export_options(0);
@@ -498,10 +499,13 @@ static void bboard_do_export(pcb_hid_attr_val_t * options)
 
 	memset(group_data, 0, sizeof(group_data));
 
-	group_data[pcb_layer_get_group(pcb_max_copper_layer + PCB_SOLDER_SIDE)].solder = 1;
-	group_data[pcb_layer_get_group(pcb_max_copper_layer + PCB_COMPONENT_SIDE)].component = 1;
+	if (pcb_layer_group_list(PCB_LYT_COPPER | PCB_LYT_BOTTOM, &gbottom, 1) > 0)
+		group_data[gbottom].solder = 1;
+
+	if (pcb_layer_group_list(PCB_LYT_COPPER | PCB_LYT_TOP, &gtop, 1) > 0)
+		group_data[gtop].component = 1;
 
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		layer = PCB->Data->Layer + i;
 		if (linelist_length(&layer->Line) > 0)
 			group_data[pcb_layer_get_group(i)].draw = 1;
@@ -524,8 +528,11 @@ static void bboard_do_export(pcb_hid_attr_val_t * options)
 	PCB_END_LOOP;
 
 	/* draw all wires from all valid layers */
-	for (i = pcb_max_copper_layer - 1; i >= 0; i--) {
-		if (bboard_validate_layer(pcb_layer_flags(i), pcb_layer_get_group(i), options[HA_skipsolder].int_value)) {
+	for (i = pcb_max_layer; i >= 0; i--) {
+		unsigned int flg = pcb_layer_flags(i);
+		if (flg & PCB_LYT_SILK)
+			continue;
+		if (bboard_validate_layer(flg, pcb_layer_get_group(i), options[HA_skipsolder].int_value)) {
 			bboard_get_layer_color(&(PCB->Data->Layer[i]), &clr_r, &clr_g, &clr_b);
 			bboard_set_color_cairo(clr_r, clr_g, clr_b);
 			PCB_LINE_LOOP(&(PCB->Data->Layer[i]));
@@ -566,6 +573,11 @@ static void bboard_set_crosshair(int x, int y, int action)
 
 static pcb_hid_t bboard_hid;
 
+void hid_export_bboard_uninit()
+{
+	pcb_hid_remove_attributes_by_cookie(bboard_cookie);
+}
+
 
 pcb_uninit_t hid_export_bboard_init()
 {
@@ -586,6 +598,6 @@ pcb_uninit_t hid_export_bboard_init()
 	pcb_hid_register_hid(&bboard_hid);
 
 	pcb_hid_register_attributes(bboard_options, sizeof(bboard_options) / sizeof(bboard_options[0]), bboard_cookie, 0);
-	return NULL;
+	return hid_export_bboard_uninit;
 }
 
diff --git a/src_plugins/export_dsn/README b/src_plugins/export_dsn/README
index cf2339d..7169c08 100644
--- a/src_plugins/export_dsn/README
+++ b/src_plugins/export_dsn/README
@@ -1,5 +1,5 @@
 Export specctra .dsn files
 
-#state: Work-in-progress
-#default: disable
+#state: works
+#default: enabled
 #implements: export
diff --git a/src_plugins/export_dsn/dsn.c b/src_plugins/export_dsn/dsn.c
index 04e607e..9737bfe 100644
--- a/src_plugins/export_dsn/dsn.c
+++ b/src_plugins/export_dsn/dsn.c
@@ -148,13 +148,14 @@ static GList *layerlist = NULL;  /* contain routing layers */
 
 static void print_structure(FILE * fp)
 {
-	int group, top_group, bot_group, top_layer, bot_layer;
+	pcb_layergrp_id_t group, top_group, bot_group;
+	pcb_layer_id_t top_layer, bot_layer;
 
-	pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_SILK, &top_group, 1);
-	pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_SILK, &bot_group, 1);
+	pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &top_group, 1);
+	pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &bot_group, 1);
 
-	top_layer = PCB->LayerGroups.Entries[top_group][0];
-	bot_layer = PCB->LayerGroups.Entries[bot_group][0];
+	top_layer = PCB->LayerGroups.grp[top_group].lid[0];
+	bot_layer = PCB->LayerGroups.grp[bot_group].lid[0];
 
 
 	g_list_free(layerlist);				/* might be around from the last export */
@@ -163,38 +164,43 @@ static void print_structure(FILE * fp)
 		layerlist = g_list_append(layerlist, &PCB->Data->Layer[top_layer]);
 	}
 	else {
-		pcb_gui->log("WARNING! DSN export does not include the top layer. "
+		pcb_message(PCB_MSG_WARNING, "WARNING! DSN export does not include the top layer. "
 						 "Router will consider an inner layer to be the \"top\" layer.\n");
 	}
 
 	for (group = 0; group < pcb_max_group; group++) {
 		pcb_layer_t *first_layer;
+		unsigned int gflg = pcb_layergrp_flags(group);
+
+		if (gflg & PCB_LYT_SILK)
+			continue;
+
 		if (group == top_group || group == bot_group)
 			continue;
 
-		if (PCB->LayerGroups.Number[group] < 1)
+		if (PCB->LayerGroups.grp[group].len < 1)
 			continue;
 
-		first_layer = &PCB->Data->Layer[PCB->LayerGroups.Entries[group][0]];
+		first_layer = &PCB->Data->Layer[PCB->LayerGroups.grp[group].lid[0]];
 		if (!first_layer->On)
 			continue;
 
 		layerlist = g_list_append(layerlist, first_layer);
 
 		if (group < top_group) {
-			pcb_gui->log("WARNING! DSN export moved layer group with the \"%s\" layer "
+			pcb_message(PCB_MSG_WARNING, "WARNING! DSN export moved layer group with the \"%s\" layer "
 							 "after the top layer group.  DSN files must have the top " "layer first.\n", first_layer->Name);
 		}
 
 		if (group > bot_group) {
-			pcb_gui->log("WARNING! DSN export moved layer group with the \"%s\" layer "
+			pcb_message(PCB_MSG_WARNING, "WARNING! DSN export moved layer group with the \"%s\" layer "
 							 "before the bottom layer group.  DSN files must have the " "bottom layer last.\n", first_layer->Name);
 		}
 
-		GROUP_LOOP(PCB->Data, group);
+		PCB_COPPER_GROUP_LOOP(PCB->Data, group);
 		{
 			if (entry > 0) {
-				pcb_gui->log("WARNING! DSN export squashed layer \"%s\" into layer "
+				pcb_message(PCB_MSG_WARNING, "WARNING! DSN export squashed layer \"%s\" into layer "
 								 "\"%s\", DSN files do not have layer groups.", layer->Name, first_layer->Name);
 			}
 		}
@@ -205,7 +211,7 @@ static void print_structure(FILE * fp)
 		layerlist = g_list_append(layerlist, &PCB->Data->Layer[bot_layer]);
 	}
 	else {
-		pcb_gui->log("WARNING! DSN export does not include the bottom layer. "
+		pcb_message(PCB_MSG_WARNING, "WARNING! DSN export does not include the bottom layer. "
 						 "Router will consider an inner layer to be the \"bottom\" layer.\n");
 	}
 
@@ -214,6 +220,10 @@ static void print_structure(FILE * fp)
 	for (GList * iter = layerlist; iter; iter = g_list_next(iter)) {
 		pcb_layer_t *layer = iter->data;
 		char *layeropts = pcb_strdup("(type signal)");
+		
+		if (!(pcb_layer_flags(pcb_layer_id(PCB->Data, layer)) & PCB_LYT_COPPER))
+			continue;
+		
 		/* see if layer has same name as a net and make it a power layer */
 		/* loop thru all nets */
 		for (int ni = 0; ni < PCB->NetlistLib[PCB_NETLIST_EDITED].MenuN; ni++) {
@@ -481,7 +491,7 @@ static int PrintSPECCTRA(void)
 	/* Print out the dsn .dsn file. */
 	fp = fopen(dsn_filename, "w");
 	if (!fp) {
-		pcb_gui->log("Cannot open file %s for writing\n", dsn_filename);
+		pcb_message(PCB_MSG_WARNING, "Cannot open file %s for writing\n", dsn_filename);
 		return 1;
 	}
 
@@ -569,7 +579,7 @@ static void dsn_parse_arguments(int *argc, char ***argv)
 
 static void hid_dsn_uninit()
 {
-
+	pcb_hid_remove_attributes_by_cookie(dsn_cookie);
 }
 
 #include "dolists.h"
diff --git a/src_plugins/export_dxf/dxf.c b/src_plugins/export_dxf/dxf.c
index d2b1775..1c3c3fa 100644
--- a/src_plugins/export_dxf/dxf.c
+++ b/src_plugins/export_dxf/dxf.c
@@ -741,7 +741,7 @@ static int dxf_lastY;
  * \brief Find a group for a given layer ??.
  */
 static pcb_layergrp_id_t dxf_group_for_layer(int l) {
-	if ((l < pcb_max_copper_layer + 2) && (l >= 0)) {
+	if ((l < pcb_max_layer) && (l >= 0)) {
 		return pcb_layer_get_group(l);
 	}
 	/* else something unique */
@@ -4226,7 +4226,7 @@ static void dxf_do_export(pcb_hid_attr_val_t * options)
 	const char *dxf_fnbase;
 	int i;
 	static int saved_layer_stack[PCB_MAX_LAYER];
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 	int save_ons[PCB_MAX_LAYER + 2];
 
 #if DEBUG
@@ -4294,24 +4294,24 @@ static void dxf_do_export(pcb_hid_attr_val_t * options)
 	pcb_hid_save_and_show_layer_ons(save_ons);
 
 	memcpy(saved_layer_stack, pcb_layer_stack, sizeof(pcb_layer_stack));
-	qsort(pcb_layer_stack, pcb_max_copper_layer, sizeof(pcb_layer_stack[0]), dxf_layer_sort);
+	qsort(pcb_layer_stack, pcb_max_layer, sizeof(pcb_layer_stack[0]), dxf_layer_sort);
 	linewidth = -1;
 	lastcap = -1;
 	lastgroup = -1;
 	lastcolor = -1;
-	region.X1 = 0;
-	region.Y1 = 0;
-	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 	pagecount = 1;
 /*  dxf_init_apertures ();*/
 	lastgroup = -1;
 	c_layerapps = 0;
 	dxf_finding_apertures = 1;
-	pcb_hid_expose_callback(&dxf_hid, &region, 0);
+	pcb_hid_expose_all(&dxf_hid, &ctx);
 	c_layerapps = 0;
 	dxf_finding_apertures = 0;
-	pcb_hid_expose_callback(&dxf_hid, &region, 0);
+	pcb_hid_expose_all(&dxf_hid, &ctx);
 	memcpy(pcb_layer_stack, saved_layer_stack, sizeof(pcb_layer_stack));
 	dxf_maybe_close_file();
 	pcb_hid_restore_layer_ons(save_ons);
@@ -5909,6 +5909,10 @@ static void dxf_progress(int dxf_so_far, int dxf_total, const char *dxf_message)
 
 const char *dxf_cookie = "dxf exporter";
 
+void hid_export_dxf_uninit()
+{
+	pcb_hid_remove_attributes_by_cookie(dxf_cookie);
+}
 
 /*!
  * \brief Call this as soon as possible from main().
@@ -5956,8 +5960,7 @@ pcb_uninit_t hid_export_dxf_init()
 
 	pcb_hid_register_attributes(dxf_options, sizeof(dxf_options) / sizeof(dxf_options[0]), dxf_cookie, 0);
 
-/*	return hid_dxf_uninit();*/
-	return NULL;
+	return hid_export_dxf_uninit;
 }
 
 
diff --git a/src_plugins/export_fidocadj/Makefile b/src_plugins/export_fidocadj/Makefile
new file mode 100644
index 0000000..c3c35b6
--- /dev/null
+++ b/src_plugins/export_fidocadj/Makefile
@@ -0,0 +1,5 @@
+all:
+	cd ../../src && $(MAKE) mod_export_fidocadj
+
+clean:
+	rm *.o *.so 2>/dev/null ; true
diff --git a/src_plugins/export_fidocadj/Plug.tmpasm b/src_plugins/export_fidocadj/Plug.tmpasm
new file mode 100644
index 0000000..12e2e57
--- /dev/null
+++ b/src_plugins/export_fidocadj/Plug.tmpasm
@@ -0,0 +1,16 @@
+put /local/pcb/mod {export_fidocadj}
+put /local/pcb/mod/OBJS [@ $(PLUGDIR)/export_fidocadj/fidocadj.o @]
+
+switch /local/pcb/export_fidocadj/controls
+	case {disable} end;
+	default
+		put /local/pcb/mod/LDFLAGS         libs/gui/gd/ldflags
+		put /local/pcb/mod/CFLAGS          libs/gui/gd/cflags
+		end
+end
+
+switch /local/pcb/export_fidocadj/controls
+	case {buildin}   include /local/pcb/tmpasm/buildin; end;
+	case {plugin}    include /local/pcb/tmpasm/plugin; end;
+	case {disable}   include /local/pcb/tmpasm/disable; end;
+end
diff --git a/src_plugins/export_fidocadj/README b/src_plugins/export_fidocadj/README
new file mode 100644
index 0000000..d9c8faa
--- /dev/null
+++ b/src_plugins/export_fidocadj/README
@@ -0,0 +1,5 @@
+Export to FidoCadJ format (.fcd)
+
+#state: WIP
+#default: disable
+#implements: export
diff --git a/src_plugins/export_fidocadj/fidocadj.c b/src_plugins/export_fidocadj/fidocadj.c
new file mode 100644
index 0000000..c1a08fc
--- /dev/null
+++ b/src_plugins/export_fidocadj/fidocadj.c
@@ -0,0 +1,337 @@
+ /*
+  *                            COPYRIGHT
+  *
+  *  PCB, interactive printed circuit board design
+  *  Copyright (C) 2017 Tibor 'Igor2' Palinkas
+  *
+  *  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 General Public License for more details.
+  *
+  *  You should have received a copy of the GNU General Public License
+  *  along with this program; if not, write to the Free Software
+  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  *
+  */
+
+/*
+ *  Based on the png exporter by Dan McMahill
+ */
+
+#include "config.h"
+#include "conf_core.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+
+#include "genht/htsi.h"
+
+#include "math_helper.h"
+#include "board.h"
+#include "data.h"
+#include "plugins.h"
+#include "pcb-printf.h"
+#include "compat_misc.h"
+#include "plug_io.h"
+
+#include "hid.h"
+#include "hid_nogui.h"
+#include "hid_draw_helpers.h"
+
+#include "hid_init.h"
+#include "hid_attrib.h"
+#include "hid_color.h"
+#include "hid_helper.h"
+#include "hid_flags.h"
+
+
+static pcb_hid_t fidocadj_hid;
+
+const char *fidocadj_cookie = "fidocadj HID";
+
+pcb_hid_attribute_t fidocadj_attribute_list[] = {
+	/* other HIDs expect this to be first.  */
+
+	{"outfile", "Output file name",
+	 HID_String, 0, 0, {0, 0, 0}, 0, 0},
+#define HA_fidocadjfile 0
+
+	{"libfile", "path to PCB.fcl",
+	 HID_String, 0, 0, {0, 0, 0}, 0, 0},
+#define HA_libfile 1
+};
+
+#define NUM_OPTIONS (sizeof(fidocadj_attribute_list)/sizeof(fidocadj_attribute_list[0]))
+
+PCB_REGISTER_ATTRIBUTES(fidocadj_attribute_list, fidocadj_cookie)
+
+static pcb_hid_attr_val_t fidocadj_values[NUM_OPTIONS];
+
+static pcb_hid_attribute_t *fidocadj_get_export_options(int *n)
+{
+	static char *last_made_filename = 0;
+	const char *suffix = ".fcd";
+
+	if (PCB)
+		pcb_derive_default_filename(PCB->Filename, &fidocadj_attribute_list[HA_fidocadjfile], suffix, &last_made_filename);
+
+	if (n)
+		*n = NUM_OPTIONS;
+	return fidocadj_attribute_list;
+}
+
+/* index PCB.fcl so we have a list of known fidocadj footprints */
+static int load_lib(htsi_t *ht, const char *fn)
+{
+	FILE *f;
+	char line[1024];
+	f = fopen(fn, "r");
+	if (f == NULL) {
+		pcb_message(PCB_MSG_ERROR, "Can't open fidocadj PCB library file '%s' for read\n", fn);
+		return -1;
+	}
+	*line = '\0';
+	fgets(line, sizeof(line), f);
+	if (pcb_strncasecmp(line, "[FIDOLIB PCB Footprints]", 24) != 0) {
+		pcb_message(PCB_MSG_ERROR, "'%s' doesn't have the fidocadj lib header\n", fn);
+		fclose(f);
+		return -1;
+	}
+	while(fgets(line, sizeof(line), f) != NULL) {
+		char *end, *s = line;
+
+		if (*line != '[')
+			continue;
+
+		s++;
+		end = strchr(s, ' ');
+		if (end != NULL) {
+			*end = '\0';
+			htsi_set(ht, pcb_strdup(s), 1);
+		}
+	}
+	fclose(f);
+	return 0;
+}
+
+static long int crd(pcb_coord_t c)
+{
+	return pcb_round((double)PCB_COORD_TO_MIL(c) / 5.0);
+}
+
+static int layer_map(unsigned int lflg, int *fidoly_next, int *warned, const char *lyname)
+{
+	if (lflg & PCB_LYT_COPPER) {
+		if (lflg & PCB_LYT_BOTTOM)
+			return 1;
+		if (lflg & PCB_LYT_TOP)
+			return 2;
+	}
+	if (lflg & PCB_LYT_SILK)
+		return 3;
+
+	(*fidoly_next)++;
+	if (*fidoly_next > 15) {
+		if (!*warned)
+			pcb_message(PCB_MSG_ERROR, "FidoCadJ can't handle this many layers - layer %s is not exported\n", lyname);
+		*warned = 1;
+		return -1;
+	}
+	return *fidoly_next;
+}
+
+static void write_custom_element(FILE *f, pcb_element_t *e)
+{
+	pcb_message(PCB_MSG_ERROR, "Can't export custom footprint for %s yet\n", e->Name[PCB_ELEMNAME_IDX_REFDES].TextString);
+}
+
+static void fidocadj_do_export(pcb_hid_attr_val_t * options)
+{
+	FILE *f;
+	const char *filename, *libfile;
+	int n, fidoly_next, have_lib;
+	pcb_layer_id_t lid;
+	int layer_warned = 0, hole_warned = 0;
+	htsi_t lib_names; /* hash of names found in the library, if have_lib is 1 */
+
+	if (!options) {
+		fidocadj_get_export_options(0);
+		for (n = 0; n < NUM_OPTIONS; n++)
+			fidocadj_values[n] = fidocadj_attribute_list[n].default_val;
+		options = fidocadj_values;
+	}
+
+	libfile = options[HA_libfile].str_value;
+	if ((libfile != NULL) && (*libfile != '\0')) {
+		htsi_init(&lib_names, strhash, strkeyeq);
+		have_lib = 1;
+		if (load_lib(&lib_names, libfile) != 0)
+			goto free_lib;
+	}
+	else
+		have_lib = 0;
+
+	filename = options[HA_fidocadjfile].str_value;
+	if (!filename)
+		filename = "pcb-rnd-default.fcd";
+
+	f = fopen(filename, "w");
+	if (!f) {
+		perror(filename);
+		return;
+	}
+
+	fprintf(f, "[FIDOCAD]\n");
+
+	fidoly_next = 3;
+	for(lid = 0; lid < pcb_max_layer; lid++) {
+		pcb_layer_t *ly = PCB->Data->Layer+lid;
+		unsigned int lflg = pcb_layer_flags(lid);
+		int fidoly = layer_map(lflg, &fidoly_next, &layer_warned, ly->Name);
+
+		if (fidoly < 0)
+			continue;
+
+		PCB_LINE_LOOP(ly) {
+			fprintf(f, "PL %ld %ld %ld %ld %ld %d\n",
+				crd(line->Point1.X), crd(line->Point1.Y),
+				crd(line->Point2.X), crd(line->Point2.Y),
+				crd(line->Thickness), fidoly);
+		}
+		PCB_END_LOOP;
+
+		PCB_ARC_LOOP(ly) {
+#warning TODO: fprintf() some curve using arc->*
+			;
+		}
+		PCB_END_LOOP;
+
+		PCB_POLY_LOOP(ly) {
+			pcb_vnode_t *v;
+			pcb_pline_t *pl = polygon->Clipped->contours;
+
+			if (polygon->HoleIndexN > 0) {
+				if (!hole_warned)
+					pcb_message(PCB_MSG_ERROR, "FidoCadJ can't handle holes in polygons, ignoring holes for this export - some of the polygons will look different\n");
+				hole_warned = 1;
+			}
+
+			fprintf(f, "PP %ld %ld", crd(pl->head.point[0]), crd(pl->head.point[1]));
+			v = pl->head.next;
+			do {
+				fprintf(f, " %ld %ld", crd(v->point[0]), crd(v->point[1]));
+			} while ((v = v->next) != pl->head.next);
+			fprintf(f, " %d\n", fidoly);
+		}
+		PCB_END_LOOP;
+
+		PCB_TEXT_LOOP(ly) {
+			char *s;
+			pcb_coord_t x0 = text->X, sx = text->BoundingBox.X2 - text->BoundingBox.X1;
+			pcb_coord_t y0 = text->Y, sy = text->BoundingBox.Y2 - text->BoundingBox.Y1;
+			switch(text->Direction) {
+				case 0: x0 += sx; break;
+				case 1: y0 += sy; break;
+				case 2: x0 -= sx; break;
+				case 3: y0 -= sy; break;
+			}
+			fprintf(f, "TY %ld %ld %ld %ld %d 0 %d * ",
+				crd(x0), crd(y0), crd(sx), crd(sy),
+				text->Direction, fidoly);
+			for(s = text->TextString; *s != '\0'; s++) {
+				if (*s == ' ')
+					fprintf(f, "++");
+				else
+					fputc(*s, f);
+			}
+			fputc('\n', f);
+		}
+		PCB_END_LOOP;
+	}
+
+	PCB_VIA_LOOP(PCB->Data) {
+		fprintf(f, "pa %ld %ld", crd(via->X), crd(via->Y));
+		if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, via)) {
+			if (!((PCB_FLAG_SQUARE_GET(via) == 0) || (PCB_FLAG_SQUARE_GET(via) == 1))) {
+#warning TODO: find out the orientation
+				fprintf(f, "%ld %ld %ld 2\n", crd(via->Thickness), crd(via->Thickness*2), crd(via->DrillingHole)); /* rounded corner rectangle */
+			}
+			else
+				fprintf(f, "%ld %ld %ld 1\n", crd(via->Thickness), crd(via->Thickness), crd(via->DrillingHole)); /* rectangle with sharp corners */
+		}
+		else
+			fprintf(f, "%ld %ld %ld 0\n", crd(via->Thickness), crd(via->Thickness), crd(via->DrillingHole)); /* circular */
+	}
+	PCB_END_LOOP;
+
+	PCB_ELEMENT_LOOP(PCB->Data) {
+		const char *fp = element->Name[PCB_ELEMNAME_IDX_DESCRIPTION].TextString;
+		if (have_lib && (htsi_get(&lib_names, fp)))
+			fprintf(f, "MC %ld %ld %d 0 %s\n", crd(element->MarkX), crd(element->MarkY), 0, fp);
+		else
+			write_custom_element(f, element);
+	}
+	PCB_END_LOOP;
+
+
+	fclose(f);
+
+	free_lib:;
+	if (have_lib) {
+		htsi_entry_t *e;
+		for (e = htsi_first(&lib_names); e; e = htsi_next(&lib_names, e))
+			free(e->key);
+
+		htsi_uninit(&lib_names);
+	}
+}
+
+static void fidocadj_parse_arguments(int *argc, char ***argv)
+{
+	pcb_hid_register_attributes(fidocadj_attribute_list, sizeof(fidocadj_attribute_list) / sizeof(fidocadj_attribute_list[0]), fidocadj_cookie, 0);
+	pcb_hid_parse_command_line(argc, argv);
+}
+
+static int fidocadj_usage(const char *topic)
+{
+	fprintf(stderr, "\nfidocadj exporter command line arguments:\n\n");
+	pcb_hid_usage(fidocadj_attribute_list, sizeof(fidocadj_attribute_list) / sizeof(fidocadj_attribute_list[0]));
+	fprintf(stderr, "\nUsage: pcb-rnd [generic_options] -x fidocadj foo.pcb [fidocadj options]\n\n");
+	return 0;
+}
+
+#include "dolists.h"
+
+pcb_uninit_t hid_export_fidocadj_init()
+{
+	memset(&fidocadj_hid, 0, sizeof(pcb_hid_t));
+
+	pcb_hid_nogui_init(&fidocadj_hid);
+	pcb_dhlp_draw_helpers_init(&fidocadj_hid);
+
+	fidocadj_hid.struct_size = sizeof(pcb_hid_t);
+	fidocadj_hid.name = "fidocadj";
+	fidocadj_hid.description = "export board in FidoCadJ .fcd format";
+	fidocadj_hid.exporter = 1;
+
+	fidocadj_hid.get_export_options = fidocadj_get_export_options;
+	fidocadj_hid.do_export = fidocadj_do_export;
+	fidocadj_hid.parse_arguments = fidocadj_parse_arguments;
+
+	fidocadj_hid.usage = fidocadj_usage;
+
+	pcb_hid_register_hid(&fidocadj_hid);
+
+	return NULL;
+}
diff --git a/src_plugins/export_gcode/gcode.c b/src_plugins/export_gcode/gcode.c
index 2197ec3..5624f95 100644
--- a/src_plugins/export_gcode/gcode.c
+++ b/src_plugins/export_gcode/gcode.c
@@ -257,8 +257,10 @@ void gcode_choose_groups()
 	/* Set entire array to 0 (don't export any layer groups by default */
 	memset(gcode_export_group, 0, sizeof(gcode_export_group));
 
-	for (n = 0; n < pcb_max_copper_layer; n++) {
+	for (n = 0; n < pcb_max_layer; n++) {
 		unsigned int flags = pcb_layer_flags(n);
+		if (flags & PCB_LYT_SILK)
+			continue;
 		layer = &PCB->Data->Layer[n];
 
 		if (!PCB_LAYER_IS_EMPTY(layer)) {
@@ -333,18 +335,18 @@ static void gcode_finish_png()
 
 void gcode_start_png_export()
 {
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 
-	region.X1 = 0;
-	region.Y1 = 0;
-	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 
 	linewidth = -1;
 	lastbrush = (gdImagePtr) ((void *) -1);
 	lastcolor = -1;
 
-	pcb_hid_expose_callback(&gcode_hid, &region, 0);
+	pcb_hid_expose_all(&gcode_hid, &ctx);
 }
 
 static void gcode_do_export(pcb_hid_attr_val_t * options)
@@ -407,9 +409,9 @@ static void gcode_do_export(pcb_hid_attr_val_t * options)
 			gcode_cur_group = i;
 
 			/* magic */
-			idx = (i >= 0 && i < pcb_max_group) ? PCB->LayerGroups.Entries[i][0] : i;
+			idx = (i >= 0 && i < pcb_max_group) ? PCB->LayerGroups.grp[i].lid[0] : i;
 			printf("idx=%d %s\n", idx, name);
-			is_solder = (pcb_layer_get_group(idx) == pcb_layer_get_group(pcb_solder_silk_layer)) ? 1 : 0;
+			is_solder = (pcb_layergrp_flags(pcb_layer_get_group(idx)) & PCB_LYT_BOTTOM) ? 1 : 0;
 			save_drill = is_solder;		/* save drills for one layer only */
 			gcode_start_png(gcode_basename, name);
 			pcb_hid_save_and_show_layer_ons(save_ons);
diff --git a/src_plugins/export_gerber/gerber.c b/src_plugins/export_gerber/gerber.c
index 9645aa5..154f2e4 100644
--- a/src_plugins/export_gerber/gerber.c
+++ b/src_plugins/export_gerber/gerber.c
@@ -299,6 +299,8 @@ static const char *name_style_names[] = {
 	"first",
 #define NAME_STYLE_EAGLE 3
 	"eagle",
+#define NAME_STYLE_HACKVANA 4
+	"hackvana",
 	NULL
 };
 
@@ -361,7 +363,7 @@ static pcb_hid_attribute_t *gerber_get_export_options(int *n)
 
 static pcb_layergrp_id_t group_for_layer(int l)
 {
-	if (l < pcb_max_copper_layer + 2 && l >= 0)
+	if (l < pcb_max_layer && l >= 0)
 		return pcb_layer_get_group(l);
 	/* else something unique */
 	return pcb_max_group + 3 + l;
@@ -390,14 +392,19 @@ static void maybe_close_f(FILE * f)
 
 static pcb_box_t region;
 
+#define fmatch(flags, bits) (((flags) & (bits)) == (bits))
+
 /* Very similar to pcb_layer_to_file_name() but appends only a
    three-character suffix compatible with Eagle's defaults.  */
 static void assign_eagle_file_suffix(char *dest, pcb_layer_id_t lid, unsigned int flags)
 {
 	const char *suff = "out";
 
-#define fmatch(flags, bits) (((flags) & (bits)) == (bits))
-	if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_SILK))
+	if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_COPPER))
+		suff = "cmp";
+	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_COPPER))
+		suff = "sol";
+	else if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_SILK))
 		suff = "plc";
 	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_SILK))
 		suff = "pls";
@@ -421,10 +428,6 @@ static void assign_eagle_file_suffix(char *dest, pcb_layer_id_t lid, unsigned in
 		suff = "ast";
 	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_ASSY))
 		suff = "asb";
-	else if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_COPPER))
-		suff = "cmp";
-	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_COPPER))
-		suff = "sol";
 	else if (fmatch(flags, PCB_LYT_OUTLINE))
 		suff = "oln";
 	else {
@@ -433,10 +436,58 @@ static void assign_eagle_file_suffix(char *dest, pcb_layer_id_t lid, unsigned in
 		sprintf(buf, "ly%ld", group);
 		suff = buf;
 	}
-#undef fmatch
 	strcpy(dest, suff);
 }
 
+/* Very similar to layer_type_to_file_name() but appends only a
+   three-character suffix compatible with Hackvana's naming requirements  */
+static void assign_hackvana_file_suffix(char *dest, pcb_layer_id_t lid, unsigned int flags)
+{
+	char *suff;
+
+	if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_COPPER))
+		suff = "gtl";
+	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_COPPER))
+		suff = "gbl";
+	else if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_SILK))
+		suff = "gto";
+	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_SILK))
+		suff = "gbo";
+	else if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_MASK))
+		suff = "gts";
+	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_MASK))
+		suff = "gbs";
+	else if (fmatch(flags, PCB_LYT_PDRILL))
+		suff = "drl";
+	else if (fmatch(flags, PCB_LYT_UDRILL))
+		suff = "_NPTH.drl";
+	else if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_PASTE))
+		suff = "gtp";
+	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_PASTE))
+		suff = "gbp";
+	else if (fmatch(flags, PCB_LYT_INVIS))
+		suff = "inv";
+	else if (fmatch(flags, PCB_LYT_FAB))
+		suff = "fab";
+	else if (fmatch(flags, PCB_LYT_TOP | PCB_LYT_ASSY))
+		suff = "ast";
+	else if (fmatch(flags, PCB_LYT_BOTTOM | PCB_LYT_ASSY))
+		suff = "asb";
+	else if (fmatch(flags, PCB_LYT_OUTLINE))
+		suff = "gm1";
+	else {
+		static char buf[20];
+		pcb_layergrp_id_t group = pcb_layer_lookup_group(lid);
+		sprintf(buf, "g%ld", group);
+		suff = buf;
+	}
+	strcpy(dest, suff);
+}
+
+
+#undef fmatch
+
+
 static void assign_file_suffix(char *dest, pcb_layer_id_t lid, unsigned int flags)
 {
 	int fns_style;
@@ -456,6 +507,9 @@ static void assign_file_suffix(char *dest, pcb_layer_id_t lid, unsigned int flag
 	case NAME_STYLE_EAGLE:
 		assign_eagle_file_suffix(dest, lid, flags);
 		return;
+	case NAME_STYLE_HACKVANA:
+		assign_hackvana_file_suffix(dest, lid, flags);
+		return;
 	}
 
 	if ((flags & PCB_LYT_PDRILL) || (flags & PCB_LYT_UDRILL))
@@ -470,6 +524,7 @@ static void gerber_do_export(pcb_hid_attr_val_t * options)
 	int i;
 	static int saved_layer_stack[PCB_MAX_LAYER];
 	int save_ons[PCB_MAX_LAYER + 2];
+	pcb_hid_expose_ctx_t ctx;
 
 	conf_force_set_bool(conf_core.editor.thin_draw, 0);
 	conf_force_set_bool(conf_core.editor.thin_draw_poly, 0);
@@ -492,14 +547,12 @@ static void gerber_do_export(pcb_hid_attr_val_t * options)
 	copy_outline_mode = options[HA_copy_outline].int_value;
 	name_style = options[HA_name_style].int_value;
 
+#warning layer TODO: this assumes there is only one outline layer; instead of this, just use a boolthat says whether we had an outline layer and redo the search
 	outline_layer = NULL;
 
-	for (i = 0; i < pcb_max_copper_layer; i++) {
-		pcb_layer_t *layer = PCB->Data->Layer + i;
-		if (strcmp(layer->Name, "outline") == 0 || strcmp(layer->Name, "route") == 0) {
-			outline_layer = layer;
-		}
-	}
+	for (i = 0; i < pcb_max_layer; i++)
+		if (pcb_layer_flags(i) & PCB_LYT_OUTLINE)
+			outline_layer = PCB->Data->Layer + i;
 
 	i = strlen(fnbase);
 	filename = (char *) realloc(filename, i + 40);
@@ -510,16 +563,16 @@ static void gerber_do_export(pcb_hid_attr_val_t * options)
 	pcb_hid_save_and_show_layer_ons(save_ons);
 
 	memcpy(saved_layer_stack, pcb_layer_stack, sizeof(pcb_layer_stack));
-	qsort(pcb_layer_stack, pcb_max_copper_layer, sizeof(pcb_layer_stack[0]), layer_sort);
+	qsort(pcb_layer_stack, pcb_max_layer, sizeof(pcb_layer_stack[0]), layer_sort);
 	linewidth = -1;
 	lastcap = -1;
 	lastgroup = -1;
 	lastcolor = -1;
 
-	region.X1 = 0;
-	region.Y1 = 0;
-	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 
 	pagecount = 1;
 	resetApertures();
@@ -527,11 +580,11 @@ static void gerber_do_export(pcb_hid_attr_val_t * options)
 	lastgroup = -1;
 	layer_list_idx = 0;
 	finding_apertures = 1;
-	pcb_hid_expose_callback(&gerber_hid, &region, 0);
+	pcb_hid_expose_all(&gerber_hid, &ctx);
 
 	layer_list_idx = 0;
 	finding_apertures = 0;
-	pcb_hid_expose_callback(&gerber_hid, &region, 0);
+	pcb_hid_expose_all(&gerber_hid, &ctx);
 
 	memcpy(pcb_layer_stack, saved_layer_stack, sizeof(pcb_layer_stack));
 
@@ -573,7 +626,7 @@ static int gerber_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer,
 
 
 	if (!all_layers)
-		if ((group >= 0) && pcb_is_layergrp_empty(group))
+		if ((group >= 0) && pcb_is_layergrp_empty(group) && !(flags & PCB_LYT_SILK))
 			return 0;
 
 	if ((flags & PCB_LYT_INVIS) || (flags & PCB_LYT_ASSY)) {
@@ -581,8 +634,13 @@ static int gerber_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer,
 		return 0;
 	}
 
-#warning TODO
-	group_name = "TODO:group_name";
+	if ((group >= 0) && (group < pcb_max_group)) {
+		group_name = PCB->LayerGroups.grp[group].name;
+		if (group_name == NULL)
+			group_name = "<unknown>";
+	}
+	else
+		group_name = "<virtual group>";
 
 	flash_drills = 0;
 	if (flags & PCB_LYT_OUTLINE)
diff --git a/src_plugins/export_ipcd356/ipcd356.c b/src_plugins/export_ipcd356/ipcd356.c
index dde60df..27edc5a 100644
--- a/src_plugins/export_ipcd356/ipcd356.c
+++ b/src_plugins/export_ipcd356/ipcd356.c
@@ -603,6 +603,11 @@ static void IPCD356_parse_arguments(int *argc, char ***argv)
 
 pcb_hid_t IPCD356_hid;
 
+void hid_export_ipcd356_uninit()
+{
+	pcb_hid_remove_attributes_by_cookie(ipcd356_cookie);
+}
+
 pcb_uninit_t *hid_export_ipcd356_init()
 {
 	memset(&IPCD356_hid, 0, sizeof(pcb_hid_t));
@@ -621,6 +626,5 @@ pcb_uninit_t *hid_export_ipcd356_init()
 	pcb_hid_register_hid(&IPCD356_hid);
 
 	pcb_hid_register_attributes(IPCD356_options, sizeof(IPCD356_options) / sizeof(IPCD356_options[0]), ipcd356_cookie, 0);
-	return NULL;
+	return hid_export_ipcd356_uninit;
 }
-
diff --git a/src_plugins/export_nelma/nelma.c b/src_plugins/export_nelma/nelma.c
index a889093..8e53abb 100644
--- a/src_plugins/export_nelma/nelma.c
+++ b/src_plugins/export_nelma/nelma.c
@@ -489,18 +489,14 @@ void nelma_choose_groups()
 	/* Set entire array to 0 (don't export any layer groups by default */
 	memset(nelma_export_group, 0, sizeof(nelma_export_group));
 
-	for (n = 0; n < pcb_max_copper_layer; n++) {
+	for (n = 0; n < pcb_max_layer; n++) {
 		unsigned int flags = pcb_layer_flags(n);
+		if (flags & PCB_LYT_SILK)
+			continue;
 		layer = &PCB->Data->Layer[n];
 
 		if (!PCB_LAYER_IS_EMPTY(layer)) {
 			/* layer isn't empty */
-
-			/*
-			 * is this check necessary? It seems that special
-			 * layers have negative indexes?
-			 */
-
 			if ((flags & PCB_LYT_COPPER) || (flags & PCB_LYT_OUTLINE)) {
 				/* layer is a copper layer */
 				m = pcb_layer_get_group(n);
@@ -568,18 +564,18 @@ static void nelma_finish_png()
 
 void nelma_start_png_export()
 {
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 
-	region.X1 = 0;
-	region.Y1 = 0;
-	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 
 	linewidth = -1;
 	lastbrush = (gdImagePtr) ((void *) -1);
 	lastcolor = -1;
 
-	pcb_hid_expose_callback(&nelma_hid, &region, 0);
+	pcb_hid_expose_all(&nelma_hid, &ctx);
 }
 
 static void nelma_do_export(pcb_hid_attr_val_t * options)
diff --git a/src_plugins/export_openscad/scad.c b/src_plugins/export_openscad/scad.c
index 16833d2..e0d57ea 100644
--- a/src_plugins/export_openscad/scad.c
+++ b/src_plugins/export_openscad/scad.c
@@ -501,8 +501,9 @@ static void scad_do_export(pcb_hid_attr_val_t * options)
 	int i;
 	int inner_layers;
 	float layer_spacing, layer_offset, cut_offset = 0.;
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 	pcb_layer_t *layer;
+	pcb_layergrp_id_t gbottom, gtop;
 
 	conf_force_set_bool(conf_core.editor.thin_draw, 0);
 	conf_force_set_bool(conf_core.editor.thin_draw_poly, 0);
@@ -536,9 +537,16 @@ static void scad_do_export(pcb_hid_attr_val_t * options)
 	scad_write_prologue(PCB->Filename);
 
 	memset(group_data, 0, sizeof(group_data));
-	group_data[pcb_layer_get_group(pcb_max_copper_layer + PCB_SOLDER_SIDE)].solder = 1;
-	group_data[pcb_layer_get_group(pcb_max_copper_layer + PCB_COMPONENT_SIDE)].component = 1;
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+
+	if (pcb_layer_group_list(PCB_LYT_SILK | PCB_LYT_BOTTOM, &gbottom, 1) > 0)
+		group_data[gbottom].solder = 1;
+
+	if (pcb_layer_group_list(PCB_LYT_SILK | PCB_LYT_TOP, &gtop, 1) > 0)
+		group_data[gtop].component = 1;
+
+	for (i = 0; i < pcb_max_layer; i++) {
+		if (pcb_layer_flags(i) & PCB_LYT_SILK)
+			continue;
 		layer = PCB->Data->Layer + i;
 		if (!pcb_layer_is_empty_(layer))
 			group_data[pcb_layer_get_group(i)].draw = 1;
@@ -566,14 +574,14 @@ static void scad_do_export(pcb_hid_attr_val_t * options)
 		}
 	}
 
-	region.X1 = 0;
-	region.Y1 = 0;
-	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 
 	layer_open = 0;
 
-	pcb_hid_expose_callback(&scad_hid, &region, 0);
+	pcb_hid_expose_all(&scad_hid, &ctx);
 
 /* And now .... Board outlines */
 
@@ -762,14 +770,28 @@ static int scad_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, u
 		return 0;
 
 	if (group >= 0 && group < pcb_max_group) {
-		if (!group_data[group].draw)
-			return 0;
-		scaled_layer_thickness = (group_data[group].solder
-															|| group_data[group].component) ? OUTER_COPPER_THICKNESS : INNER_COPPER_THICKNESS;
-		sprintf(layer_id, "layer_%02ld", group);
-		if (!outline_layer) {
+		if (flags & PCB_LYT_SILK) {
+			if (!opt_exp_silk)
+				return 0;
+			scaled_layer_thickness = SILK_LAYER_THICKNESS;
+			if (flags & PCB_LYT_TOP) {
+				strcpy(layer_id, "layer_topsilk");
+			}
+			else {
+				strcpy(layer_id, "layer_bottomsilk");
+			}
 			group_data[group].exp = 1;
 		}
+		else {
+			if (!group_data[group].draw)
+				return 0;
+			scaled_layer_thickness = (group_data[group].solder
+																|| group_data[group].component) ? OUTER_COPPER_THICKNESS : INNER_COPPER_THICKNESS;
+			sprintf(layer_id, "layer_%02ld", group);
+			if (!outline_layer) {
+				group_data[group].exp = 1;
+			}
+		}
 	}
 	else {
 		if (flags & PCB_LYT_PDRILL) {
@@ -780,17 +802,6 @@ static int scad_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, u
 			drill_layer = 1;
 			strcpy(layer_id, "layer_udrill");
 		}
-		else if ((flags & PCB_LYT_ANYTHING) == PCB_LYT_SILK) {
-			if (!opt_exp_silk)
-				return 0;
-			scaled_layer_thickness = SILK_LAYER_THICKNESS;
-			if (flags & PCB_LYT_TOP) {
-				strcpy(layer_id, "layer_topsilk");
-			}
-			else {
-				strcpy(layer_id, "layer_bottomsilk");
-			}
-		}
 		else if (flags & PCB_LYT_MASK) {
 			if (opt_mask_color == SCAD_MASK_NONE || opt_outline_type == SCAD_OUTLINE_NONE)
 				return 0;
@@ -802,9 +813,8 @@ static int scad_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, u
 				strcpy(layer_id, "layer_bottommask");
 			}
 		}
-		else {
+		else
 			return 0;
-		}
 	}
 
 	layer_open = 1;
@@ -1117,6 +1127,11 @@ static const char *openscad_cookie = "openscad exporter";
 
 static pcb_hid_t scad_hid;
 
+void hid_export_openscad_uninit()
+{
+	pcb_hid_remove_attributes_by_cookie(openscad_cookie);
+}
+
 pcb_uninit_t hid_export_openscad_init()
 {
 	memset(&scad_hid, 0, sizeof(scad_hid));
@@ -1154,5 +1169,5 @@ pcb_uninit_t hid_export_openscad_init()
 	pcb_hid_register_hid(&scad_hid);
 
 	pcb_hid_register_attributes(scad_options, sizeof(scad_options) / sizeof(scad_options[0]), openscad_cookie, 0);
-	return NULL;
+	return hid_export_openscad_uninit;
 }
diff --git a/src_plugins/export_png/png.c b/src_plugins/export_png/png.c
index 3b85ae0..c0cbf2a 100644
--- a/src_plugins/export_png/png.c
+++ b/src_plugins/export_png/png.c
@@ -56,6 +56,9 @@
 #include "hid_helper.h"
 #include "hid_flags.h"
 
+#define PNG_SCALE_HACK1 0
+#include "compat_misc.h"
+#define pcb_hack_round(d) pcb_round(d)
 
 #define CRASH(func) fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", func); abort()
 
@@ -71,9 +74,9 @@ static double scale = 1;
 static pcb_coord_t x_shift = 0;
 static pcb_coord_t y_shift = 0;
 static int show_solder_side;
-#define SCALE(w)   ((int)((w)/scale + 0.5))
-#define SCALE_X(x) ((int)(((x) - x_shift)/scale))
-#define SCALE_Y(y) ((int)(((show_solder_side ? (PCB->MaxHeight-(y)) : (y)) - y_shift)/scale))
+#define SCALE(w)   ((int)pcb_round((w)/scale))
+#define SCALE_X(x) ((int)pcb_hack_round(((x) - x_shift)/scale))
+#define SCALE_Y(y) ((int)pcb_hack_round(((show_solder_side ? (PCB->MaxHeight-(y)) : (y)) - y_shift)/scale))
 #define SWAP_IF_SOLDER(a,b) do { int c; if (show_solder_side) { c=a; a=b; b=c; }} while (0)
 
 /* Used to detect non-trivial outlines */
@@ -112,6 +115,7 @@ static int linewidth = -1;
 static int lastgroup = -1;
 static gdImagePtr lastbrush = (gdImagePtr) ((void *) -1);
 static int lastcap = -1;
+static int last_color_r, last_color_g, last_color_b, last_cap;
 
 /* For photo-mode we need the following layers as monochrome masks:
 
@@ -377,27 +381,30 @@ static pcb_hid_attribute_t *png_get_export_options(int *n)
 	return png_attribute_list;
 }
 
-static pcb_layergrp_id_t comp_layer, solder_layer;
 
 static pcb_layergrp_id_t group_for_layer(int l)
 {
-	if (l < pcb_max_copper_layer + 2 && l >= 0)
+	if (l < pcb_max_layer && l >= 0)
 		return pcb_layer_get_group(l);
 	/* else something unique */
 	return pcb_max_group + 3 + l;
 }
 
+static int is_solder(pcb_layergrp_id_t grp)     { return pcb_layergrp_flags(grp) & PCB_LYT_BOTTOM; }
+static int is_component(pcb_layergrp_id_t grp)  { return pcb_layergrp_flags(grp) & PCB_LYT_TOP; }
+
 static int layer_sort(const void *va, const void *vb)
 {
 	int a = *(int *) va;
 	int b = *(int *) vb;
-	int al = group_for_layer(a);
-	int bl = group_for_layer(b);
+	pcb_layergrp_id_t al = group_for_layer(a);
+	pcb_layergrp_id_t bl = group_for_layer(b);
 	int d = bl - al;
 
-	if (a >= 0 && a <= pcb_max_copper_layer + 1) {
-		int aside = (al == solder_layer ? 0 : al == comp_layer ? 2 : 1);
-		int bside = (bl == solder_layer ? 0 : bl == comp_layer ? 2 : 1);
+	if (a >= 0 && a < pcb_max_layer) {
+		int aside = (is_solder(al) ? 0 : is_component(al) ? 2 : 1);
+		int bside = (is_solder(bl) ? 0 : is_component(bl) ? 2 : 1);
+
 		if (bside != aside)
 			return bside - aside;
 	}
@@ -429,6 +436,7 @@ void png_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 {
 	static int saved_layer_stack[PCB_MAX_LAYER];
 	pcb_box_t tmp, region;
+	pcb_hid_expose_ctx_t ctx;
 
 	f = the_file;
 
@@ -452,12 +460,17 @@ void png_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 		conf_force_set_bool(conf_core.editor.show_solder_side, 0);
 		conf_force_set_bool(conf_core.editor.show_mask, 0);
 
-		comp_layer = pcb_layer_get_group(pcb_component_silk_layer);
-		solder_layer = pcb_layer_get_group(pcb_solder_silk_layer);
-		qsort(pcb_layer_stack, pcb_max_copper_layer, sizeof(pcb_layer_stack[0]), layer_sort);
+		qsort(pcb_layer_stack, pcb_max_layer, sizeof(pcb_layer_stack[0]), layer_sort);
 
 		if (photo_mode) {
 			int i, n = 0;
+			pcb_layergrp_id_t solder_layer = -1, comp_layer = -1;
+	
+			pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &solder_layer, 1);
+			pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &comp_layer, 1);
+			assert(solder_layer >= 0);
+			assert(comp_layer >= 0);
+
 			conf_force_set_bool(conf_core.editor.show_mask, 1);
 			photo_has_inners = 0;
 			if (comp_layer < solder_layer)
@@ -492,19 +505,21 @@ void png_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 	lastcap = -1;
 	lastgroup = -1;
 	show_solder_side = conf_core.editor.show_solder_side;
+	last_color_r = last_color_g = last_color_b = last_cap = -1;
 
 	in_mono = options[HA_mono].int_value;
 
 	if (!photo_mode && conf_core.editor.show_solder_side) {
 		int i, j;
-		for (i = 0, j = pcb_max_copper_layer - 1; i < j; i++, j--) {
+		for (i = 0, j = pcb_max_layer - 1; i < j; i++, j--) {
 			int k = pcb_layer_stack[i];
 			pcb_layer_stack[i] = pcb_layer_stack[j];
 			pcb_layer_stack[j] = k;
 		}
 	}
 
-	pcb_hid_expose_callback(&png_hid, bounds, 0);
+	ctx.view = *bounds;
+	pcb_hid_expose_all(&png_hid, &ctx);
 
 	memcpy(pcb_layer_stack, saved_layer_stack, sizeof(pcb_layer_stack));
 	conf_update(NULL); /* restore forced sets */
@@ -685,8 +700,8 @@ static void png_do_export(pcb_hid_attr_val_t * options)
 		 * a scale of 10 means 1 pixel is 10 inches
 		 */
 		scale = PCB_INCH_TO_COORD(1) / dpi;
-		w = w / scale;
-		h = h / scale;
+		w = pcb_round(w / scale) - PNG_SCALE_HACK1;
+		h = pcb_round(h / scale) - PNG_SCALE_HACK1;
 	}
 	else if (xmax == 0 && ymax == 0) {
 		fprintf(stderr, "ERROR:  You may not set both xmax, ymax," "and xy-max to zero\n");
@@ -1006,7 +1021,7 @@ static int png_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, un
 	if (flags & PCB_LYT_UI)
 		return 0;
 
-	if ((flags & PCB_LYT_ASSY) || (flags & PCB_LYT_FAB) || (flags & PCB_LYT_PASTE) || (flags & PCB_LYT_INVIS))
+	if ((flags & PCB_LYT_ASSY) || (flags & PCB_LYT_FAB) || (flags & PCB_LYT_PASTE) || (flags & PCB_LYT_INVIS) || (flags & PCB_LYT_CSECT))
 		return 0;
 
 	is_drill = ((flags & PCB_LYT_PDRILL) || (flags & PCB_LYT_UDRILL));
@@ -1166,6 +1181,8 @@ static void use_gc(pcb_hid_gc_t gc)
 		need_brush = 1;
 	}
 
+	need_brush |= (gc->color->r != last_color_r) || (gc->color->g != last_color_g) || (gc->color->b != last_color_b) || (gc->cap != last_cap);
+
 	if (lastbrush != gc->brush || need_brush) {
 		pcb_hidval_t bval;
 		char name[256];
@@ -1194,6 +1211,11 @@ static void use_gc(pcb_hid_gc_t gc)
 
 		sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r);
 
+		last_color_r = gc->color->r;
+		last_color_g = gc->color->g;
+		last_color_b = gc->color->b;
+		last_cap = gc->cap;
+
 		if (pcb_hid_cache_color(0, name, &bval, &brush_cache)) {
 			gc->brush = (gdImagePtr) bval.ptr;
 		}
@@ -1294,12 +1316,12 @@ static void png_draw_line(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_c
 		   are brought in by a pixel to make sure we have contiguous
 		   outlines.  */
 		if (x1 == PCB->MaxWidth && x2 == PCB->MaxWidth) {
-			x1 -= scale / 2;
-			x2 -= scale / 2;
+			x1 -= pcb_round(scale / 2);
+			x2 -= pcb_round(scale / 2);
 		}
 		if (y1 == PCB->MaxHeight && y2 == PCB->MaxHeight) {
-			y1 -= scale / 2;
-			y2 -= scale / 2;
+			y1 -= pcb_round(scale / 2);
+			y2 -= pcb_round(scale / 2);
 		}
 	}
 
@@ -1338,6 +1360,10 @@ static void png_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_co
 {
 	pcb_angle_t sa, ea;
 
+	use_gc(gc);
+	gdImageSetThickness(im, 0);
+	linewidth = 0;
+
 	/*
 	 * zero angle arcs need special handling as gd will output either
 	 * nothing at all or a full circle when passed delta angle of 0 or 360.
@@ -1351,31 +1377,38 @@ static void png_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_co
 		return;
 	}
 
-	/* 
-	 * in gdImageArc, 0 degrees is to the right and +90 degrees is down
-	 * in pcb, 0 degrees is to the left and +90 degrees is down
-	 */
-	start_angle = 180 - start_angle;
-	delta_angle = -delta_angle;
-	if (show_solder_side) {
-		start_angle = -start_angle;
-		delta_angle = -delta_angle;
-	}
-	if (delta_angle > 0) {
-		sa = start_angle;
-		ea = start_angle + delta_angle;
+	if ((delta_angle >= 360) || (delta_angle <= -360)) {
+		/* save some expensive calculations if we are going to draw a full circle anyway */
+		sa = 0;
+		ea = 360;
 	}
 	else {
-		sa = start_angle + delta_angle;
-		ea = start_angle;
-	}
+		/*
+		 * in gdImageArc, 0 degrees is to the right and +90 degrees is down
+		 * in pcb, 0 degrees is to the left and +90 degrees is down
+		 */
+		start_angle = 180 - start_angle;
+		delta_angle = -delta_angle;
+		if (show_solder_side) {
+			start_angle = -start_angle;
+			delta_angle = -delta_angle;
+		}
+		if (delta_angle > 0) {
+			sa = start_angle;
+			ea = start_angle + delta_angle;
+		}
+		else {
+			sa = start_angle + delta_angle;
+			ea = start_angle;
+		}
 
-	/* 
-	 * make sure we start between 0 and 360 otherwise gd does
-	 * strange things
-	 */
-	sa = pcb_normalize_angle(sa);
-	ea = pcb_normalize_angle(ea);
+		/*
+		 * make sure we start between 0 and 360 otherwise gd does
+		 * strange things
+		 */
+		sa = pcb_normalize_angle(sa);
+		ea = pcb_normalize_angle(ea);
+	}
 
 	have_outline |= doing_outline;
 
@@ -1384,9 +1417,6 @@ static void png_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_co
 	printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
 				 (void *)im, SCALE_X(cx), SCALE_Y(cy), SCALE(width), SCALE(height), sa, ea, gc->color->c);
 #endif
-	use_gc(gc);
-	gdImageSetThickness(im, 0);
-	linewidth = 0;
 	gdImageArc(im, SCALE_X(cx), SCALE_Y(cy), SCALE(2 * width), SCALE(2 * height), sa, ea, gdBrushed);
 }
 
diff --git a/src_plugins/export_ps/eps.c b/src_plugins/export_ps/eps.c
index f9dc1c0..3eba977 100644
--- a/src_plugins/export_ps/eps.c
+++ b/src_plugins/export_ps/eps.c
@@ -145,27 +145,28 @@ PCB_REGISTER_ATTRIBUTES(eps_attribute_list, ps_cookie)
 	return eps_attribute_list;
 }
 
-static int comp_layer, solder_layer;
-
 static pcb_layergrp_id_t group_for_layer(int l)
 {
-	if (l < pcb_max_copper_layer + 2 && l >= 0)
+	if (l < pcb_max_layer && l >= 0)
 		return pcb_layer_get_group(l);
 	/* else something unique */
 	return pcb_max_group + 3 + l;
 }
 
+static int is_solder(pcb_layergrp_id_t grp)     { return pcb_layergrp_flags(grp) & PCB_LYT_BOTTOM; }
+static int is_component(pcb_layergrp_id_t grp)  { return pcb_layergrp_flags(grp) & PCB_LYT_TOP; }
+
 static int layer_sort(const void *va, const void *vb)
 {
 	int a = *(int *) va;
 	int b = *(int *) vb;
-	int al = group_for_layer(a);
-	int bl = group_for_layer(b);
+	pcb_layergrp_id_t al = group_for_layer(a);
+	pcb_layergrp_id_t bl = group_for_layer(b);
 	int d = bl - al;
 
-	if (a >= 0 && a <= pcb_max_copper_layer + 1) {
-		int aside = (al == solder_layer ? 0 : al == comp_layer ? 2 : 1);
-		int bside = (bl == solder_layer ? 0 : bl == comp_layer ? 2 : 1);
+	if (a >= 0 && a < pcb_max_layer) {
+		int aside = (is_solder(al) ? 0 : is_component(al) ? 2 : 1);
+		int bside = (is_solder(bl) ? 0 : is_component(bl) ? 2 : 1);
 		if (bside != aside)
 			return bside - aside;
 	}
@@ -183,6 +184,7 @@ void eps_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 	int i;
 	static int saved_layer_stack[PCB_MAX_LAYER];
 	pcb_box_t tmp, region;
+	pcb_hid_expose_ctx_t ctx;
 
 	conf_force_set_bool(conf_core.editor.thin_draw, 0);
 	conf_force_set_bool(conf_core.editor.thin_draw_poly, 0);
@@ -204,8 +206,10 @@ void eps_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 	memset(print_layer, 0, sizeof(print_layer));
 
 	/* Figure out which layers actually have stuff on them.  */
-	for (i = 0; i < pcb_max_copper_layer; i++) {
+	for (i = 0; i < pcb_max_layer; i++) {
 		pcb_layer_t *layer = PCB->Data->Layer + i;
+		if (pcb_layer_flags(i) & PCB_LYT_SILK)
+			continue;
 		if (layer->On)
 			if (!PCB_LAYER_IS_EMPTY(layer))
 				print_group[pcb_layer_get_group(i)] = 1;
@@ -222,8 +226,11 @@ void eps_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 	/* If NO layers had anything on them, at least print the component
 	   layer to get the pins.  */
 	if (fast_erase == 0) {
-		print_group[pcb_layer_get_group(pcb_component_silk_layer)] = 1;
-		fast_erase = 1;
+		pcb_layergrp_id_t comp_copp;
+		if (pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &comp_copp, 1) > 0) {
+			print_group[pcb_layer_get_group(comp_copp)] = 1;
+			fast_erase = 1;
+		}
 	}
 
 	/* "fast_erase" is 1 if we can just paint white to erase.  */
@@ -231,9 +238,12 @@ void eps_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 
 	/* Now, for each group we're printing, mark its layers for
 	   printing.  */
-	for (i = 0; i < pcb_max_copper_layer; i++)
+	for (i = 0; i < pcb_max_layer; i++) {
+		if (pcb_layer_flags(i) & PCB_LYT_SILK)
+			continue;
 		if (print_group[pcb_layer_get_group(i)])
 			print_layer[i] = 1;
+	}
 
 	if (fast_erase) {
 		eps_hid.poly_before = 1;
@@ -247,9 +257,7 @@ void eps_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 	memcpy(saved_layer_stack, pcb_layer_stack, sizeof(pcb_layer_stack));
 	as_shown = options[HA_as_shown].int_value;
 	if (!options[HA_as_shown].int_value) {
-		comp_layer = pcb_layer_get_group(pcb_component_silk_layer);
-		solder_layer = pcb_layer_get_group(pcb_solder_silk_layer);
-		qsort(pcb_layer_stack, pcb_max_copper_layer, sizeof(pcb_layer_stack[0]), layer_sort);
+		qsort(pcb_layer_stack, pcb_max_layer, sizeof(pcb_layer_stack[0]), layer_sort);
 	}
 	fprintf(f, "%%!PS-Adobe-3.0 EPSF-3.0\n");
 	linewidth = -1;
@@ -290,7 +298,8 @@ void eps_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 	fprintf(f, "/cc { 0 360 arc nclip } bind def\n");
 	fprintf(f, "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n");
 
-	pcb_hid_expose_callback(&eps_hid, bounds, 0);
+	ctx.view = *bounds;
+	pcb_hid_expose_all(&eps_hid, &ctx);
 
 	fprintf(f, "showpage\n");
 
@@ -352,10 +361,10 @@ static int eps_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, un
 	if (flags & PCB_LYT_UI)
 		return 0;
 
-	if ((flags & PCB_LYT_ASSY) || (flags & PCB_LYT_FAB) || (flags & PCB_LYT_INVIS))
+	if ((flags & PCB_LYT_ASSY) || (flags & PCB_LYT_FAB) || (flags & PCB_LYT_CSECT) || (flags & PCB_LYT_INVIS))
 		return 0;
 
-	if ((group >= 0) && pcb_is_layergrp_empty(group))
+	if ((group >= 0) && pcb_is_layergrp_empty(group) && (flags & PCB_LYT_OUTLINE))
 		return 0;
 
 	is_drill = ((flags & PCB_LYT_PDRILL) || (flags & PCB_LYT_UDRILL));
diff --git a/src_plugins/export_ps/ps.c b/src_plugins/export_ps/ps.c
index f52b8ab..640cd1c 100644
--- a/src_plugins/export_ps/ps.c
+++ b/src_plugins/export_ps/ps.c
@@ -402,7 +402,7 @@ static struct {
 
 	double scale_factor;
 
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t exps;
 
 	pcb_hid_attr_val_t ps_values[NUM_OPTIONS];
 
@@ -428,7 +428,7 @@ static pcb_hid_attribute_t *ps_get_export_options(int *n)
 
 static pcb_layergrp_id_t group_for_layer(int l)
 {
-	if (l < pcb_max_copper_layer + 2 && l >= 0)
+	if (l < pcb_max_layer && l >= 0)
 		return pcb_layer_get_group(l);
 	/* else something unique */
 	return pcb_max_group + 3 + l;
@@ -650,17 +650,17 @@ void ps_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 		global.outline_layer = NULL;
 
 	memcpy(saved_layer_stack, pcb_layer_stack, sizeof(pcb_layer_stack));
-	qsort(pcb_layer_stack, pcb_max_copper_layer, sizeof(pcb_layer_stack[0]), layer_sort);
+	qsort(pcb_layer_stack, pcb_max_layer, sizeof(pcb_layer_stack[0]), layer_sort);
 
 	global.linewidth = -1;
 	/* reset static vars */
 	ps_set_layer_group(-1, -1, 0, -1);
 	use_gc(NULL);
 
-	global.region.X1 = 0;
-	global.region.Y1 = 0;
-	global.region.X2 = PCB->MaxWidth;
-	global.region.Y2 = PCB->MaxHeight;
+	global.exps.view.X1 = 0;
+	global.exps.view.Y1 = 0;
+	global.exps.view.X2 = PCB->MaxWidth;
+	global.exps.view.Y2 = PCB->MaxHeight;
 
 	if (!global.multi_file) {
 		/* %%Page DSC requires both a label and an ordinal */
@@ -671,14 +671,14 @@ void ps_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 		fprintf(the_file, "/tocp { /y y 12 sub def 90 y moveto rightshow } bind def\n");
 
 		global.doing_toc = 1;
-		global.pagecount = 1;				/* 'pagecount' is modified by pcb_hid_expose_callback() call */
-		pcb_hid_expose_callback(&ps_hid, &global.region, 0);
+		global.pagecount = 1;				/* 'pagecount' is modified by pcb_hid_expose_all() call */
+		pcb_hid_expose_all(&ps_hid, &global.exps);
 	}
 
 	global.pagecount = 1;					/* Reset 'pagecount' if single file */
 	global.doing_toc = 0;
 	ps_set_layer_group(-1, -1, 0, -1); /* reset static vars */
-	pcb_hid_expose_callback(&ps_hid, &global.region, 0);
+	pcb_hid_expose_all(&ps_hid, &global.exps);
 
 	if (the_file)
 		fprintf(the_file, "showpage\n");
@@ -779,6 +779,9 @@ static int ps_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, uns
 	if (flags & PCB_LYT_INVIS)
 		return 0;
 
+	if (flags & PCB_LYT_CSECT) /* not yet finished */
+		return 0;
+
 	name = pcb_layer_to_file_name(tmp_ln, layer, flags, PCB_FNS_fixed);
 
 	global.is_drill = ((flags & PCB_LYT_PDRILL) || (flags & PCB_LYT_UDRILL));
@@ -953,7 +956,7 @@ static int ps_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, uns
 			global.outline_layer != NULL &&
 			global.outline_layer != pcb_get_layer(layer) &&
 			!(flags & PCB_LYT_OUTLINE)) {
-		pcb_draw_layer(global.outline_layer, &global.region);
+		pcb_draw_layer(global.outline_layer, &global.exps.view);
 	}
 
 	return 1;
diff --git a/src_plugins/export_stat/stat.c b/src_plugins/export_stat/stat.c
index 432dd35..bb9af7b 100644
--- a/src_plugins/export_stat/stat.c
+++ b/src_plugins/export_stat/stat.c
@@ -169,74 +169,78 @@ static void stat_do_export(pcb_hid_attr_val_t * options)
 	fprintf(f, "	}\n");
 
 	fprintf(f, "	li:logical_layers {\n");
-	for(lid = 0; lid < pcb_max_copper_layer; lid++) {
+	for(lid = 0; lid < pcb_max_layer; lid++) {
 		pcb_layer_t *l = PCB->Data->Layer+lid;
 		int empty = pcb_layer_is_empty_(l);
+		unsigned int lflg = pcb_layer_flags(lid);
+
 		lgid = pcb_layer_get_group(lid);
 		lgs = lgss + lgid;
 
 		fprintf(f, "		ha:layer_%d {\n", lid);
 		fprintf(f, "			name={%s}\n", l->Name);
 		fprintf(f, "			empty=%s\n", empty ? "yes" : "no");
+		fprintf(f, "			flags=%x\n", lflg);
 		fprintf(f, "			grp=%ld\n", lgid);
 
-		memset(&ls, 0, sizeof(ls));
-
-		PCB_LINE_LOOP(l) {
-			pcb_coord_t v;
-			double d;
-			lgs->lines++;
-			ls.lines++;
-			v = pcb_line_length(line);
-			ls.trace_len += v;
-			lgs->trace_len += v;
-			d = pcb_line_area(line);
-			ls.copper_area += d;
-			lgs->copper_area += d;
-			
-		}
-		PCB_END_LOOP;
-
-		PCB_ARC_LOOP(l) {
-			pcb_coord_t v;
-			double d;
-			lgs->arcs++;
-			ls.arcs++;
-			v = pcb_arc_length(arc);
-			ls.trace_len += v;
-			lgs->trace_len += v;
-			d = pcb_arc_area(arc);
-			ls.copper_area += d;
-			lgs->copper_area += d;
-		}
-		PCB_END_LOOP;
-
-		PCB_POLY_LOOP(l) {
-			double v;
-			lgs->polys++;
-			ls.polys++;
-			v = pcb_poly_area(polygon);
-			ls.copper_area += v;
-			lgs->copper_area += v;
+		if (lflg & PCB_LYT_COPPER) {
+			memset(&ls, 0, sizeof(ls));
+
+			PCB_LINE_LOOP(l) {
+				pcb_coord_t v;
+				double d;
+				lgs->lines++;
+				ls.lines++;
+				v = pcb_line_length(line);
+				ls.trace_len += v;
+				lgs->trace_len += v;
+				d = pcb_line_area(line);
+				ls.copper_area += d;
+				lgs->copper_area += d;
+				
+			}
+			PCB_END_LOOP;
+
+			PCB_ARC_LOOP(l) {
+				pcb_coord_t v;
+				double d;
+				lgs->arcs++;
+				ls.arcs++;
+				v = pcb_arc_length(arc);
+				ls.trace_len += v;
+				lgs->trace_len += v;
+				d = pcb_arc_area(arc);
+				ls.copper_area += d;
+				lgs->copper_area += d;
+			}
+			PCB_END_LOOP;
+
+			PCB_POLY_LOOP(l) {
+				double v;
+				lgs->polys++;
+				ls.polys++;
+				v = pcb_poly_area(polygon);
+				ls.copper_area += v;
+				lgs->copper_area += v;
+			}
+			PCB_END_LOOP;
+
+			if (!empty)
+				group_not_empty[lgid] = 1;
+
+			fprintf(f, "			lines=%lu\n", ls.lines);
+			fprintf(f, "			arcs=%lu\n",  ls.arcs);
+			fprintf(f, "			polys=%lu\n", ls.polys);
+			pcb_fprintf(f, "			trace_len=%$mm\n", ls.trace_len);
+			fprintf(f, "			copper_area={%f mm^2}\n", (double)ls.copper_area / (double)PCB_MM_TO_COORD(1) / (double)PCB_MM_TO_COORD(1));
 		}
-		PCB_END_LOOP;
-
-		if (!empty)
-			group_not_empty[lgid] = 1;
-
-		fprintf(f, "			lines=%lu\n", ls.lines);
-		fprintf(f, "			arcs=%lu\n",  ls.arcs);
-		fprintf(f, "			polys=%lu\n", ls.polys);
-		pcb_fprintf(f, "			trace_len=%$mm\n", ls.trace_len);
-		fprintf(f, "			copper_area={%f mm^2}\n", (double)ls.copper_area / (double)PCB_MM_TO_COORD(1) / (double)PCB_MM_TO_COORD(1));
-
 		fprintf(f, "		}\n");
 	}
 	fprintf(f, "	}\n");
 
 	phg = 0;
 	fprintf(f, "	li:physical_layers {\n");
-	for(lgid = 0; lgid < pcb_max_copper_layer; lgid++) {
+	for(lgid = 0; lgid < pcb_max_group; lgid++) {
 		if (group_not_empty[lgid]) {
 			phg++;
 			fprintf(f, "		ha:layergroup_%ld {\n", lgid);
diff --git a/src_plugins/export_svg/svg.c b/src_plugins/export_svg/svg.c
index 9a60abc..82cc59c 100644
--- a/src_plugins/export_svg/svg.c
+++ b/src_plugins/export_svg/svg.c
@@ -194,12 +194,12 @@ static pcb_hid_attribute_t *svg_get_export_options(int *n)
 void svg_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 {
 	static int saved_layer_stack[PCB_MAX_LAYER];
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 
-	region.X1 = 0;
-	region.Y1 = 0;
-	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 
 	f = the_file;
 
@@ -237,7 +237,7 @@ void svg_hid_export_to_file(FILE * the_file, pcb_hid_attr_val_t * options)
 	gds_init(&sbright);
 	gds_init(&sdark);
 	gds_init(&snormal);
-	pcb_hid_expose_callback(&svg_hid, &region, 0);
+	pcb_hid_expose_all(&svg_hid, &ctx);
 
 	conf_update(NULL); /* restore forced sets */
 }
@@ -591,9 +591,12 @@ static void svg_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_co
 		delta_angle = -delta_angle;
 	}
 
-
-	if (delta_angle >= +360.0) { delta_angle = 359.999; diff=1; }
-	if (delta_angle <= -360.0) { delta_angle = 359.999; diff=1; }
+	/* workaround for near-360 deg rendering bugs */
+	if ((delta_angle >= +360.0) || (delta_angle <= -360.0)) {
+		svg_draw_arc(gc, cx, cy, width, height, 0, 180);
+		svg_draw_arc(gc, cx, cy, width, height, 180, 180);
+		return;
+	}
 
 	if (fabs(delta_angle) <= 0.001) { delta_angle = 0.001; diff=1; }
 
diff --git a/src_plugins/fontmode/fontmode.c b/src_plugins/fontmode/fontmode.c
index 65aee1f..054c4e5 100644
--- a/src_plugins/fontmode/fontmode.c
+++ b/src_plugins/fontmode/fontmode.c
@@ -72,6 +72,7 @@ static int FontEdit(int argc, const char **argv, pcb_coord_t Ux, pcb_coord_t Uy)
 	pcb_font_t *font;
 	pcb_symbol_t *symbol;
 	pcb_layer_t *lfont, *lorig, *lwidth, *lgrid;
+	pcb_layergrp_id_t gtop, gbottom;
 	int s, l;
 
 	if (pcb_hid_actionl("New", "Font", 0))
@@ -84,8 +85,11 @@ static int FontEdit(int argc, const char **argv, pcb_coord_t Ux, pcb_coord_t Uy)
 	conf_set_design("design/min_wid", "%s", "1"); PCB->minWid = 1;
 	conf_set_design("design/min_slk", "%s", "1"); PCB->minSlk = 1;
 
-	pcb_layer_move_to_group(pcb_max_copper_layer + PCB_COMPONENT_SIDE, 0);
-	pcb_layer_move_to_group(pcb_max_copper_layer + PCB_SOLDER_SIDE, 1);
+	if (pcb_layer_group_list(PCB_LYT_SILK | PCB_LYT_BOTTOM, &gbottom, 1) > 0)
+		pcb_layer_move_to_group(gbottom, 1);
+
+	if (pcb_layer_group_list(PCB_LYT_SILK | PCB_LYT_TOP, &gtop, 1) > 0)
+		pcb_layer_move_to_group(gtop, 0);
 
 	while (PCB->Data->LayerN > 4)
 		pcb_layer_move(4, -1);
diff --git a/src_plugins/fp_wget/tester.c b/src_plugins/fp_wget/tester.c
index 230bd78..5300c7c 100644
--- a/src_plugins/fp_wget/tester.c
+++ b/src_plugins/fp_wget/tester.c
@@ -8,14 +8,14 @@ char *pcb_strdup(const char *s) { return strdup(s); }
 
 pcb_plug_fp_t *pcb_plug_fp_chain = NULL;
 
-library_t ltmp;
-library_t *pcb_fp_mkdir_p(const char *path)
+pcb_library_t ltmp;
+pcb_library_t *pcb_fp_mkdir_p(const char *path)
 {
 	printf("lib mkdir: '%s'\n", path);
 	return (library_t *)<mp;
 }
 
-library_t *pcb_fp_append_entry(library_t *parent, const char *name, pcb_fp_type_t type, void *tags[])
+pcb_library_t *pcb_fp_append_entry(library_t *parent, const char *name, pcb_fp_type_t type, void *tags[])
 {
 	printf("lib entry: '%s'\n", name);
 	return (library_t *)<mp;
diff --git a/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/hid/hid_callbacks.c b/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/hid/hid_callbacks.c
index 61cc578..51e4879 100644
--- a/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/hid/hid_callbacks.c
+++ b/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/hid/hid_callbacks.c
@@ -53,20 +53,20 @@ void gpmi_hid_destroy_gc(pcb_hid_gc_t gc)
 void gpmi_hid_do_export(pcb_hid_attr_val_t * options)
 {
 	gpmi_hid_t *h = hid_gpmi_data_get(pcb_exporter);
-  int save_ons[PCB_MAX_LAYER + 2];
-  pcb_box_t region;
+	int save_ons[PCB_MAX_LAYER + 2];
+	pcb_hid_expose_ctx_t ctx;
 
 	h->result = options;
 	gpmi_event(h->module, HIDE_do_export_start, h);
 
 	pcb_hid_save_and_show_layer_ons(save_ons);
 
-  region.X1 = 0;
-  region.Y1 = 0;
-  region.X2 = PCB->MaxWidth;
-  region.Y2 = PCB->MaxHeight;
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 
-	pcb_hid_expose_callback(h->hid, &region, 0);
+	pcb_hid_expose_all(h->hid, &ctx.view);
 	pcb_hid_restore_layer_ons(save_ons);
 	gpmi_event(h->module, HIDE_do_export_finish, h);
 	h->result = NULL;
diff --git a/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layers.c b/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layers.c
index a16c79a..d5f2065 100644
--- a/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layers.c
+++ b/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layers.c
@@ -45,17 +45,11 @@ int layout_get_max_possible_layer()
 	return PCB_MAX_LAYER+2;
 }
 
-int layout_get_max_copper_layer()
-{
-	return pcb_max_copper_layer;
-}
-
 int layout_get_max_layer()
 {
-	return pcb_max_copper_layer+2;
+	return pcb_max_layer;
 }
 
-
 const char *layout_layer_name(int layer)
 {
 	layer_check(layer)("");
diff --git a/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layout.h b/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layout.h
index e1b9c25..493747a 100644
--- a/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layout.h
+++ b/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/layout/layout.h
@@ -228,9 +228,6 @@ int layout_resolve_layer(const char *name);
 /* return the theoretical number of layers supported by PCB */
 int layout_get_max_possible_layer();
 
-/* return the actual number of copper layers on the current design */
-int layout_get_max_copper_layer();
-
 /* return the actual number of layers on the current design */
 int layout_get_max_layer();
 
diff --git a/src_plugins/hid_batch/batch.c b/src_plugins/hid_batch/batch.c
index b5efb3d..e6c9e40 100644
--- a/src_plugins/hid_batch/batch.c
+++ b/src_plugins/hid_batch/batch.c
@@ -76,21 +76,18 @@ static int help(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 static int info(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
 	int i, j;
-	pcb_layergrp_id_t cg, sg;
 	if (!PCB || !PCB->Data || !PCB->Filename) {
 		printf("No PCB loaded.\n");
 		return 0;
 	}
 	printf("Filename: %s\n", PCB->Filename);
 	pcb_printf("Size: %ml x %ml mils, %mm x %mm mm\n", PCB->MaxWidth, PCB->MaxHeight, PCB->MaxWidth, PCB->MaxHeight);
-	cg = pcb_layer_get_group(pcb_component_silk_layer);
-	sg = pcb_layer_get_group(pcb_solder_silk_layer);
 	for (i = 0; i < PCB_MAX_LAYER; i++) {
-
 		pcb_layergrp_id_t lg = pcb_layer_get_group(i);
+		unsigned int gflg = pcb_layergrp_flags(lg);
 		for (j = 0; j < PCB_MAX_LAYER; j++)
 			putchar(j == lg ? '#' : '-');
-		printf(" %c %s\n", lg == cg ? 'c' : lg == sg ? 's' : '-', PCB->Data->Layer[i].Name);
+		printf(" %c %s\n", (gflg & PCB_LYT_TOP) ? 'c' : (gflg & PCB_LYT_BOTTOM) ? 's' : '-', PCB->Data->Layer[i].Name);
 	}
 	return 0;
 }
diff --git a/src_plugins/hid_gtk/Plug.tmpasm b/src_plugins/hid_gtk/Plug.tmpasm
index bcd2404..4b53ed4 100644
--- a/src_plugins/hid_gtk/Plug.tmpasm
+++ b/src_plugins/hid_gtk/Plug.tmpasm
@@ -1,33 +1,19 @@
 put /local/pcb/mod {hid_gtk}
 put /local/pcb/mod/OBJS_C99 [@
-	$(PLUGDIR)/hid_gtk/ghid-cell-renderer-visibility.o
-	$(PLUGDIR)/hid_gtk/ghid-coord-entry.o
-	$(PLUGDIR)/hid_gtk/ghid-layer-selector.o
+	$(PLUGDIR)/hid_gtk/colors.o
 	$(PLUGDIR)/hid_gtk/ghid-main-menu.o
-	$(PLUGDIR)/hid_gtk/ghid-route-style-selector.o
-	$(PLUGDIR)/hid_gtk/ghid-propedit.o
-	$(PLUGDIR)/hid_gtk/ghid-search.o
 	$(PLUGDIR)/hid_gtk/gtkhid-main.o
 	$(PLUGDIR)/hid_gtk/gui-command-window.o
 	$(PLUGDIR)/hid_gtk/gui-config.o
-	$(PLUGDIR)/hid_gtk/gui-dialog-print.o
-	$(PLUGDIR)/hid_gtk/gui-dialog.o
 	$(PLUGDIR)/hid_gtk/gui-drc-window.o
-	$(PLUGDIR)/hid_gtk/gui-keyref-window.o
 	$(PLUGDIR)/hid_gtk/gui-library-window.o
 	$(PLUGDIR)/hid_gtk/gui-log-window.o
-	$(PLUGDIR)/hid_gtk/gui-misc.o
 	$(PLUGDIR)/hid_gtk/gui-netlist-window.o
 	$(PLUGDIR)/hid_gtk/gui-output-events.o
-	$(PLUGDIR)/hid_gtk/gui-pinout-preview.o
-	$(PLUGDIR)/hid_gtk/gui-pinout-window.o
 	$(PLUGDIR)/hid_gtk/gui-top-window.o
-	$(PLUGDIR)/hid_gtk/gui-utils.o
 	$(PLUGDIR)/hid_gtk/gtkhid-gdk.o
-	$(PLUGDIR)/hid_gtk/menu_lht.o
 	$(PLUGDIR)/hid_gtk/gtk_conf_list.o
 	$(PLUGDIR)/hid_gtk/gschem_accel_label.o
-	$(PLUGDIR)/hid_gtk/win_place.o
 @]
 put /local/pcb/mod/CONF {$(PLUGDIR)/hid_gtk/hid_gtk_conf.h}
 
@@ -36,13 +22,6 @@ switch /local/pcb/hid_gtk/controls
 	default
 		put /local/pcb/mod/CFLAGS   /target/libs/gui/gtk2/cflags
 		put /local/pcb/mod/LDFLAGS  /target/libs/gui/gtk2/ldflags
-		put /local/pcb/mod/CLEANFILES { $(PLUGDIR)/hid_gtk/menu_lht.c }
-		append /local/pcb/RULES [@
-### lesstif menu embed
-$(PLUGDIR)/hid_gtk/menu_lht.c: pcb-menu-gtk.lht
-	$(CQUOTE) -n hid_gtk_menu_default <pcb-menu-gtk.lht >$(PLUGDIR)/hid_gtk/menu_lht.c
-@]
-
 	end
 end
 
diff --git a/src_plugins/hid_gtk/colors.c b/src_plugins/hid_gtk/colors.c
new file mode 100644
index 0000000..5f97a9c
--- /dev/null
+++ b/src_plugins/hid_gtk/colors.c
@@ -0,0 +1,64 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * FIXME: Do we still need that ? long gone, no ?
+ * 
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* FIXME: Find a way to get rid of GHidPort *out and gui.h */
+#include "gui.h"
+
+/* FIXME: could be more generic with a pcb_color_s structure depending on Toolkit :
+ * GdkColor for GTK2
+ * GdkRGBA  for GTK3
+ */
+/*#include "colors.h"*/
+
+const gchar *ghid_get_color_name(GdkColor * color)
+{
+	static char tmp[16];
+
+	if (!color)
+		return "#000000";
+
+	sprintf(tmp, "#%2.2x%2.2x%2.2x", (color->red >> 8) & 0xff, (color->green >> 8) & 0xff, (color->blue >> 8) & 0xff);
+	return tmp;
+}
+
+void ghid_map_color_string(const char *color_string, GdkColor * color)
+{
+	static GdkColormap *colormap = NULL;
+	GHidPort *out = &ghid_port;
+
+	if (!color || !out->top_window)
+		return;
+	if (colormap == NULL)
+		colormap = gtk_widget_get_colormap(out->top_window);
+	if (color->red || color->green || color->blue)
+		gdk_colormap_free_colors(colormap, color, 1);
+	gdk_color_parse(color_string, color);
+	gdk_color_alloc(colormap, color);
+}
diff --git a/src_plugins/hid_gtk/colors.h b/src_plugins/hid_gtk/colors.h
new file mode 100644
index 0000000..7e3cbf2
--- /dev/null
+++ b/src_plugins/hid_gtk/colors.h
@@ -0,0 +1,4 @@
+#include <gdk/gdk.h>
+
+const gchar *ghid_get_color_name(GdkColor * color);
+void ghid_map_color_string(const char *color_string, GdkColor * color);
diff --git a/src_plugins/hid_gtk/ghid-cell-renderer-visibility.c b/src_plugins/hid_gtk/ghid-cell-renderer-visibility.c
deleted file mode 100644
index 0c0478a..0000000
--- a/src_plugins/hid_gtk/ghid-cell-renderer-visibility.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*! \file <gtk-pcb-cell-render-visibility.c>
- *  \brief Implementation of GtkCellRenderer for layer visibility toggler
- *  \par More Information
- *  For details on the functions implemented here, see the Gtk
- *  documentation for the GtkCellRenderer object, which defines
- *  the interface we are implementing.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-#include <gtk/gtk.h>
-
-#include "config.h"
-#include "gtkhid.h"
-#include "gui.h"
-#include "compat_nls.h"
-
-#include "ghid-cell-renderer-visibility.h"
-
-enum {
-	TOGGLED,
-	LAST_SIGNAL
-};
-static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
-
-enum {
-	PROP_ACTIVE = 1,
-	PROP_COLOR
-};
-
-struct _GHidCellRendererVisibility {
-	GtkCellRenderer parent;
-
-	gboolean active;
-	gchar *color;
-};
-
-struct _GHidCellRendererVisibilityClass {
-	GtkCellRendererClass parent_class;
-
-	void (*toggled) (GHidCellRendererVisibility * cell, const gchar * path);
-};
-
-/* RENDERER FUNCTIONS */
-/*! \brief Calculates the window area the renderer will use */
-static void
-ghid_cell_renderer_visibility_get_size(GtkCellRenderer * cell,
-																			 GtkWidget * widget,
-																			 GdkRectangle * cell_area, gint * x_offset, gint * y_offset, gint * width, gint * height)
-{
-	GtkStyle *style = gtk_widget_get_style(widget);
-	gint w, h;
-	gint xpad, ypad;
-	gfloat xalign, yalign;
-
-	gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
-	gtk_cell_renderer_get_alignment(cell, &xalign, &yalign);
-
-	w = VISIBILITY_TOGGLE_SIZE + 2 * (xpad + style->xthickness);
-	h = VISIBILITY_TOGGLE_SIZE + 2 * (ypad + style->ythickness);
-
-	if (width)
-		*width = w;
-	if (height)
-		*height = h;
-
-	if (cell_area) {
-		if (x_offset) {
-			if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
-				xalign = 1. - xalign;
-			*x_offset = MAX(0, xalign * (cell_area->width - w));
-		}
-		if (y_offset)
-			*y_offset = MAX(0, yalign * (cell_area->height - h));
-	}
-}
-
-/*! \brief Actually renders the swatch */
-static void
-ghid_cell_renderer_visibility_render(GtkCellRenderer * cell,
-																		 GdkWindow * window,
-																		 GtkWidget * widget,
-																		 GdkRectangle * background_area,
-																		 GdkRectangle * cell_area, GdkRectangle * expose_area, GtkCellRendererState flags)
-{
-	GHidCellRendererVisibility *pcb_cell;
-	GdkRectangle toggle_rect;
-	GdkRectangle draw_rect;
-	gint xpad, ypad;
-
-	pcb_cell = GHID_CELL_RENDERER_VISIBILITY(cell);
-	ghid_cell_renderer_visibility_get_size(cell, widget, cell_area,
-																				 &toggle_rect.x, &toggle_rect.y, &toggle_rect.width, &toggle_rect.height);
-	gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
-
-	toggle_rect.x += cell_area->x + xpad;
-	toggle_rect.y += cell_area->y + ypad;
-	toggle_rect.width -= xpad * 2;
-	toggle_rect.height -= ypad * 2;
-
-	if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
-		return;
-
-	if (gdk_rectangle_intersect(expose_area, cell_area, &draw_rect)) {
-		GdkColor color;
-		cairo_t *cr = gdk_cairo_create(window);
-		if (expose_area) {
-			gdk_cairo_rectangle(cr, expose_area);
-			cairo_clip(cr);
-		}
-		cairo_set_line_width(cr, 1);
-
-		cairo_rectangle(cr, toggle_rect.x + 0.5, toggle_rect.y + 0.5, toggle_rect.width - 1, toggle_rect.height - 1);
-		cairo_set_source_rgb(cr, 1, 1, 1);
-		cairo_fill_preserve(cr);
-		cairo_set_source_rgb(cr, 0, 0, 0);
-		cairo_stroke(cr);
-
-		gdk_color_parse(pcb_cell->color, &color);
-		if (flags & GTK_CELL_RENDERER_PRELIT) {
-			color.red = (4 * color.red + 65535) / 5;
-			color.green = (4 * color.green + 65535) / 5;
-			color.blue = (4 * color.blue + 65535) / 5;
-		}
-		gdk_cairo_set_source_color(cr, &color);
-		if (pcb_cell->active)
-			cairo_rectangle(cr, toggle_rect.x + 0.5, toggle_rect.y + 0.5, toggle_rect.width - 1, toggle_rect.height - 1);
-		else {
-			cairo_move_to(cr, toggle_rect.x + 1, toggle_rect.y + 1);
-			cairo_rel_line_to(cr, toggle_rect.width / 2, 0);
-			cairo_rel_line_to(cr, -toggle_rect.width / 2, toggle_rect.width / 2);
-			cairo_close_path(cr);
-		}
-		cairo_fill(cr);
-
-		cairo_destroy(cr);
-	}
-}
-
-/*! \brief Toggless the swatch */
-static gint
-ghid_cell_renderer_visibility_activate(GtkCellRenderer * cell,
-																			 GdkEvent * event,
-																			 GtkWidget * widget,
-																			 const gchar * path,
-																			 GdkRectangle * background_area, GdkRectangle * cell_area, GtkCellRendererState flags)
-{
-	g_signal_emit(cell, toggle_cell_signals[TOGGLED], 0, path);
-	return TRUE;
-}
-
-/* Setter/Getter */
-static void ghid_cell_renderer_visibility_get_property(GObject * object, guint param_id, GValue * value, GParamSpec * pspec)
-{
-	GHidCellRendererVisibility *pcb_cell = GHID_CELL_RENDERER_VISIBILITY(object);
-
-	switch (param_id) {
-	case PROP_ACTIVE:
-		g_value_set_boolean(value, pcb_cell->active);
-		break;
-	case PROP_COLOR:
-		g_value_set_string(value, pcb_cell->color);
-		break;
-	}
-}
-
-static void
-ghid_cell_renderer_visibility_set_property(GObject * object, guint param_id, const GValue * value, GParamSpec * pspec)
-{
-	GHidCellRendererVisibility *pcb_cell = GHID_CELL_RENDERER_VISIBILITY(object);
-
-	switch (param_id) {
-	case PROP_ACTIVE:
-		pcb_cell->active = g_value_get_boolean(value);
-		break;
-	case PROP_COLOR:
-		g_free(pcb_cell->color);
-		pcb_cell->color = g_value_dup_string(value);
-		break;
-	}
-}
-
-
-/* CONSTRUCTOR */
-static void ghid_cell_renderer_visibility_init(GHidCellRendererVisibility * ls)
-{
-	g_object_set(ls, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
-}
-
-static void ghid_cell_renderer_visibility_class_init(GHidCellRendererVisibilityClass * klass)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS(klass);
-	GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass);
-
-	object_class->get_property = ghid_cell_renderer_visibility_get_property;
-	object_class->set_property = ghid_cell_renderer_visibility_set_property;
-
-	cell_class->get_size = ghid_cell_renderer_visibility_get_size;
-	cell_class->render = ghid_cell_renderer_visibility_render;
-	cell_class->activate = ghid_cell_renderer_visibility_activate;
-
-	g_object_class_install_property(object_class, PROP_ACTIVE,
-																	g_param_spec_boolean("active",
-																											 _("Visibility state"),
-																											 _("Visibility of the layer"), FALSE, G_PARAM_READWRITE));
-	g_object_class_install_property(object_class, PROP_COLOR,
-																	g_param_spec_string("color", _("Layer color"), _("Layer color"), FALSE, G_PARAM_READWRITE));
-
-
- /**
-  * GHidCellRendererVisibility::toggled:
-  * @cell_renderer: the object which received the signal
-  * @path: string representation of #GtkTreePath describing the 
-  *        event location
-  *
-  * The ::toggled signal is emitted when the cell is toggled. 
-  **/
-	toggle_cell_signals[TOGGLED] =
-		g_signal_new(_("toggled"),
-								 G_OBJECT_CLASS_TYPE(object_class),
-								 G_SIGNAL_RUN_LAST,
-								 G_STRUCT_OFFSET(GHidCellRendererVisibilityClass, toggled),
-								 NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
-}
-
-/* PUBLIC FUNCTIONS */
-GType ghid_cell_renderer_visibility_get_type(void)
-{
-	static GType ls_type = 0;
-
-	if (!ls_type) {
-		const GTypeInfo ls_info = {
-			sizeof(GHidCellRendererVisibilityClass),
-			NULL,											/* base_init */
-			NULL,											/* base_finalize */
-			(GClassInitFunc) ghid_cell_renderer_visibility_class_init,
-			NULL,											/* class_finalize */
-			NULL,											/* class_data */
-			sizeof(GHidCellRendererVisibility),
-			0,												/* n_preallocs */
-			(GInstanceInitFunc) ghid_cell_renderer_visibility_init,
-		};
-
-		ls_type = g_type_register_static(GTK_TYPE_CELL_RENDERER, "GHidCellRendererVisibility", &ls_info, 0);
-	}
-
-	return ls_type;
-}
-
-GtkCellRenderer *ghid_cell_renderer_visibility_new(void)
-{
-	GHidCellRendererVisibility *rv = g_object_new(GHID_CELL_RENDERER_VISIBILITY_TYPE, NULL);
-
-	rv->active = FALSE;
-
-	return GTK_CELL_RENDERER(rv);
-}
diff --git a/src_plugins/hid_gtk/ghid-cell-renderer-visibility.h b/src_plugins/hid_gtk/ghid-cell-renderer-visibility.h
deleted file mode 100644
index c87308b..0000000
--- a/src_plugins/hid_gtk/ghid-cell-renderer-visibility.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef GHID_CELL_RENDERER_VISIBILITY_H__
-#define GHID_CELL_RENDERER_VISIBILITY_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-G_BEGIN_DECLS										/* keep c++ happy */
-#define VISIBILITY_TOGGLE_SIZE	16
-#define GHID_CELL_RENDERER_VISIBILITY_TYPE            (ghid_cell_renderer_visibility_get_type ())
-#define GHID_CELL_RENDERER_VISIBILITY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_CELL_RENDERER_VISIBILITY_TYPE, GHidCellRendererVisibility))
-#define GHID_CELL_RENDERER_VISIBILITY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GHID_CELL_RENDERER_VISIBILITY_TYPE, GHidCellRendererVisibilityClass))
-#define IS_GHID_CELL_RENDERER_VISIBILITY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_CELL_RENDERER_VISIBILITY_TYPE))
-#define IS_GHID_CELL_RENDERER_VISIBILITY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHID_CELL_RENDERER_VISIBILITY_TYPE))
-typedef struct _GHidCellRendererVisibility GHidCellRendererVisibility;
-typedef struct _GHidCellRendererVisibilityClass GHidCellRendererVisibilityClass;
-
-GType ghid_cell_renderer_visibility_get_type(void);
-GtkCellRenderer *ghid_cell_renderer_visibility_new(void);
-
-G_END_DECLS											/* keep c++ happy */
-#endif
diff --git a/src_plugins/hid_gtk/ghid-coord-entry.c b/src_plugins/hid_gtk/ghid-coord-entry.c
deleted file mode 100644
index 90c9b54..0000000
--- a/src_plugins/hid_gtk/ghid-coord-entry.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*! \file <gtk-pcb-coord-entry.c>
- *  \brief Implementation of GHidCoordEntry widget
- *  \par Description
- *  This widget is a modified spinbox for the user to enter
- *  pcb coords. It is assigned a default unit (for display),
- *  but this can be changed by the user by typing a new one
- *  or right-clicking on the box.
- *
- *  Internally, it keeps track of its value in pcb coords.
- *  From the user's perspective, it uses natural human units.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-#include <gtk/gtk.h>
-
-#include "config.h"
-#include "gtkhid.h"
-#include "gui.h"
-#include "pcb-printf.h"
-#include "compat_nls.h"
-
-#include "ghid-coord-entry.h"
-
-enum {
-	UNIT_CHANGE_SIGNAL,
-	LAST_SIGNAL
-};
-
-static guint ghid_coord_entry_signals[LAST_SIGNAL] = { 0 };
-
-struct _GHidCoordEntry {
-	GtkSpinButton parent;
-
-	pcb_coord_t min_value;
-	pcb_coord_t max_value;
-	pcb_coord_t value;
-
-	enum ce_step_size step_size;
-	const pcb_unit_t *unit;
-};
-
-struct _GHidCoordEntryClass {
-	GtkSpinButtonClass parent_class;
-
-	void (*change_unit) (GHidCoordEntry *, const pcb_unit_t *);
-};
-
-/* SIGNAL HANDLERS */
-/*! \brief Callback for "Change Unit" menu click */
-static void menu_item_activate_cb(GtkMenuItem * item, GHidCoordEntry * ce)
-{
-	const char *text = gtk_menu_item_get_label(item);
-	const pcb_unit_t *unit = get_unit_struct(text);
-
-	g_signal_emit(ce, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, unit);
-}
-
-/*! \brief Callback for context menu creation */
-static void ghid_coord_entry_popup_cb(GHidCoordEntry * ce, GtkMenu * menu, gpointer data)
-{
-	int i, n;
-	const pcb_unit_t *unit_list;
-	GtkWidget *menu_item, *submenu;
-
-	/* Build submenu */
-	n = pcb_get_n_units();
-	unit_list = get_unit_list();
-
-	submenu = gtk_menu_new();
-	for (i = 0; i < n; ++i) {
-		menu_item = gtk_menu_item_new_with_label(unit_list[i].suffix);
-		g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(menu_item_activate_cb), ce);
-		gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menu_item);
-		gtk_widget_show(menu_item);
-	}
-
-	/* Add submenu to menu */
-	menu_item = gtk_separator_menu_item_new();
-	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menu_item);
-	gtk_widget_show(menu_item);
-
-	menu_item = gtk_menu_item_new_with_label(_("Change Units"));
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
-	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menu_item);
-	gtk_widget_show(menu_item);
-}
-
-/*! \brief Callback for user output */
-static gboolean ghid_coord_entry_output_cb(GHidCoordEntry * ce, gpointer data)
-{
-	GtkAdjustment *adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ce));
-	double value = gtk_adjustment_get_value(adj);
-	char *text;
-
-	text = pcb_strdup_printf("%.*f %s", ce->unit->default_prec, value, ce->unit->suffix);
-	gtk_entry_set_text(GTK_ENTRY(ce), text);
-	free(text);
-
-	return TRUE;
-}
-
-/*! \brief Callback for user input */
-static gboolean ghid_coord_text_changed_cb(GHidCoordEntry * entry, gpointer data)
-{
-	const char *text;
-	char *suffix;
-	const pcb_unit_t *new_unit;
-	double value;
-
-	/* Check if units have changed */
-	text = gtk_entry_get_text(GTK_ENTRY(entry));
-	value = strtod(text, &suffix);
-	new_unit = get_unit_struct(suffix);
-	if (new_unit && new_unit != entry->unit) {
-		entry->value = pcb_unit_to_coord(new_unit, value);
-		g_signal_emit(entry, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, new_unit);
-	}
-
-	return FALSE;
-}
-
-/*! \brief Callback for change in value (input or ^v clicks) */
-static gboolean ghid_coord_value_changed_cb(GHidCoordEntry * ce, gpointer data)
-{
-	GtkAdjustment *adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ce));
-
-	/* Re-calculate internal value */
-	double value = gtk_adjustment_get_value(adj);
-	ce->value = pcb_unit_to_coord(ce->unit, value);
-	/* Handle potential unit changes */
-	ghid_coord_text_changed_cb(ce, data);
-
-	return FALSE;
-}
-
-/*! \brief Change the unit used by a coord entry
- *
- *  \param [in] ce         The entry to be acted on
- *  \parin [in] new_unit   The new unit to be used
- */
-static void ghid_coord_entry_change_unit(GHidCoordEntry * ce, const pcb_unit_t * new_unit)
-{
-	double climb_rate = 0.0;
-	GtkAdjustment *adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ce));
-
-	ce->unit = new_unit;
-	/* Re-calculate min/max values for spinbox */
-	gtk_adjustment_configure(adj, pcb_coord_to_unit(new_unit, ce->value),
-													 pcb_coord_to_unit(new_unit, ce->min_value),
-													 pcb_coord_to_unit(new_unit, ce->max_value), ce->unit->step_small, ce->unit->step_medium, 0.0);
-
-	switch (ce->step_size) {
-	case CE_TINY:
-		climb_rate = new_unit->step_tiny;
-		break;
-	case CE_SMALL:
-		climb_rate = new_unit->step_small;
-		break;
-	case CE_MEDIUM:
-		climb_rate = new_unit->step_medium;
-		break;
-	case CE_LARGE:
-		climb_rate = new_unit->step_large;
-		break;
-	}
-	gtk_spin_button_configure(GTK_SPIN_BUTTON(ce), adj, climb_rate, new_unit->default_prec + strlen(new_unit->suffix));
-}
-
-/* CONSTRUCTOR */
-static void ghid_coord_entry_init(GHidCoordEntry * ce)
-{
-	/* Hookup signal handlers */
-	g_signal_connect(G_OBJECT(ce), "focus_out_event", G_CALLBACK(ghid_coord_text_changed_cb), NULL);
-	g_signal_connect(G_OBJECT(ce), "value_changed", G_CALLBACK(ghid_coord_value_changed_cb), NULL);
-	g_signal_connect(G_OBJECT(ce), "populate_popup", G_CALLBACK(ghid_coord_entry_popup_cb), NULL);
-	g_signal_connect(G_OBJECT(ce), "output", G_CALLBACK(ghid_coord_entry_output_cb), NULL);
-}
-
-static void ghid_coord_entry_class_init(GHidCoordEntryClass * klass)
-{
-	klass->change_unit = ghid_coord_entry_change_unit;
-
-	/* GtkAutoComplete *ce : the object acted on */
-	/* const pcb_unit_t *new_unit: the new unit that was set */
-	ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL] =
-		g_signal_new("change-unit",
-								 G_TYPE_FROM_CLASS(klass),
-								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-								 G_STRUCT_OFFSET(GHidCoordEntryClass, change_unit),
-								 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
-
-}
-
-/* PUBLIC FUNCTIONS */
-GType ghid_coord_entry_get_type(void)
-{
-	static GType ce_type = 0;
-
-	if (!ce_type) {
-		const GTypeInfo ce_info = {
-			sizeof(GHidCoordEntryClass),
-			NULL,											/* base_init */
-			NULL,											/* base_finalize */
-			(GClassInitFunc) ghid_coord_entry_class_init,
-			NULL,											/* class_finalize */
-			NULL,											/* class_data */
-			sizeof(GHidCoordEntry),
-			0,												/* n_preallocs */
-			(GInstanceInitFunc) ghid_coord_entry_init,
-		};
-
-		ce_type = g_type_register_static(GTK_TYPE_SPIN_BUTTON, "GHidCoordEntry", &ce_info, 0);
-	}
-
-	return ce_type;
-}
-
-/*! \brief Create a new GHidCoordEntry
- *
- *  \param [in] min_val    The minimum allowed value, in pcb coords
- *  \param [in] max_val    The maximum allowed value, in pcb coords
- *  \param [in] value      The default value, in pcb coords
- *  \param [in] unit       The default unit
- *  \param [in] step_size  How large the default increments should be
- *
- *  \return a freshly-allocated GHidCoordEntry
- */
-GtkWidget *ghid_coord_entry_new(pcb_coord_t min_val, pcb_coord_t max_val, pcb_coord_t value, const pcb_unit_t * unit, enum ce_step_size step_size)
-{
-	/* Setup spinbox min/max values */
-	double small_step, big_step;
-	GtkAdjustment *adj;
-	GHidCoordEntry *ce = g_object_new(GHID_COORD_ENTRY_TYPE, NULL);
-
-	ce->unit = unit;
-	ce->min_value = min_val;
-	ce->max_value = max_val;
-	ce->value = value;
-
-	ce->step_size = step_size;
-	switch (step_size) {
-	case CE_TINY:
-		small_step = unit->step_tiny;
-		big_step = unit->step_small;
-		break;
-	case CE_SMALL:
-		small_step = unit->step_small;
-		big_step = unit->step_medium;
-		break;
-	case CE_MEDIUM:
-		small_step = unit->step_medium;
-		big_step = unit->step_large;
-		break;
-	case CE_LARGE:
-		small_step = unit->step_large;
-		big_step = unit->step_huge;
-		break;
-	default:
-		small_step = big_step = 0;
-		break;
-	}
-
-	adj = GTK_ADJUSTMENT(gtk_adjustment_new(pcb_coord_to_unit(unit, value),
-																					pcb_coord_to_unit(unit, min_val),
-																					pcb_coord_to_unit(unit, max_val), small_step, big_step, 0.0));
-	gtk_spin_button_configure(GTK_SPIN_BUTTON(ce), adj, small_step, unit->default_prec + strlen(unit->suffix));
-	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ce), FALSE);
-
-	return GTK_WIDGET(ce);
-}
-
-/*! \brief Gets a GHidCoordEntry's value, in pcb coords */
-pcb_coord_t ghid_coord_entry_get_value(GHidCoordEntry * ce)
-{
-	return ce->value;
-}
-
-/*! \brief Gets a GHidCoordEntry's value as text */
-int ghid_coord_entry_get_value_str(GHidCoordEntry * ce, char *out, int out_len)
-{
-	GtkAdjustment *adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ce));
-	double value = gtk_adjustment_get_value(adj);
-	return pcb_snprintf(out, out_len, "%.*f %s", ce->unit->default_prec, value, ce->unit->suffix);
-}
-
-/*! \brief Sets a GHidCoordEntry's value, in pcb coords */
-void ghid_coord_entry_set_value(GHidCoordEntry * ce, pcb_coord_t val)
-{
-	gtk_spin_button_set_value(GTK_SPIN_BUTTON(ce), pcb_coord_to_unit(ce->unit, val));
-}
diff --git a/src_plugins/hid_gtk/ghid-coord-entry.h b/src_plugins/hid_gtk/ghid-coord-entry.h
deleted file mode 100644
index b7c8414..0000000
--- a/src_plugins/hid_gtk/ghid-coord-entry.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* This is the modified GtkSpinbox used for entering Coords.
- * Hopefully it can be used as a template whenever we migrate the
- * rest of the Gtk HID to use GObjects and GtkWidget subclassing.
- */
-#ifndef GHID_COORD_ENTRY_H__
-#define GHID_COORD_ENTRY_H__
-
-#include <glib.h>
-#include <glib-object.h>
-#include "unit.h"
-
-G_BEGIN_DECLS										/* keep c++ happy */
-#define GHID_COORD_ENTRY_TYPE            (ghid_coord_entry_get_type ())
-#define GHID_COORD_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_COORD_ENTRY_TYPE, GHidCoordEntry))
-#define GHID_COORD_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GHID_COORD_ENTRY_TYPE, GHidCoordEntryClass))
-#define IS_GHID_COORD_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_COORD_ENTRY_TYPE))
-#define IS_GHID_COORD_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHID_COORD_ENTRY_TYPE))
-typedef struct _GHidCoordEntry GHidCoordEntry;
-typedef struct _GHidCoordEntryClass GHidCoordEntryClass;
-
-/* Step sizes */
-enum ce_step_size { CE_TINY, CE_SMALL, CE_MEDIUM, CE_LARGE };
-
-GType ghid_coord_entry_get_type(void);
-GtkWidget *ghid_coord_entry_new(pcb_coord_t min_val, pcb_coord_t max_val, pcb_coord_t value, const pcb_unit_t * unit, enum ce_step_size step_size);
-void ghid_coord_entry_add_entry(GHidCoordEntry * ce, const gchar * name, const gchar * desc);
-gchar *ghid_coord_entry_get_last_command(GHidCoordEntry * ce);
-
-int ghid_coord_entry_get_value_str(GHidCoordEntry * ce, char *out, int out_len);
-pcb_coord_t ghid_coord_entry_get_value(GHidCoordEntry * ce);
-void ghid_coord_entry_set_value(GHidCoordEntry * ce, pcb_coord_t val);
-
-G_END_DECLS											/* keep c++ happy */
-#endif
diff --git a/src_plugins/hid_gtk/ghid-layer-selector.c b/src_plugins/hid_gtk/ghid-layer-selector.c
deleted file mode 100644
index 8bdec50..0000000
--- a/src_plugins/hid_gtk/ghid-layer-selector.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/*! \file <gtk-pcb-layer-selector.c>
- *  \brief Implementation of GHidLayerSelector widget
- *  \par Description
- *  This widget is the layer selector on the left side of the Gtk
- *  GUI. It also builds the relevant sections of the menu for layer
- *  selection and visibility toggling, and keeps these in sync.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-
-#include "config.h"
-#include "gtkhid.h"
-#include "gui.h"
-#include "pcb-printf.h"
-
-#include "ghid-layer-selector.h"
-#include "ghid-cell-renderer-visibility.h"
-
-#define INITIAL_ACTION_MAX	40
-
-/* Forward dec'ls */
-struct _layer;
-static void ghid_layer_selector_finalize(GObject * object);
-static void menu_pick_cb(GtkRadioAction * action, struct _layer *ldata);
-
-/*! \brief Signals exposed by the widget */
-enum {
-	SELECT_LAYER_SIGNAL,
-	TOGGLE_LAYER_SIGNAL,
-	LAST_SIGNAL
-};
-
-/*! \brief Columns used for internal data store */
-enum {
-	STRUCT_COL,
-	USER_ID_COL,
-	VISIBLE_COL,
-	COLOR_COL,
-	TEXT_COL,
-	FONT_COL,
-	ACTIVATABLE_COL,
-	SEPARATOR_COL,
-	N_COLS
-};
-
-static GtkTreeView *ghid_layer_selector_parent_class;
-static guint ghid_layer_selector_signals[LAST_SIGNAL] = { 0 };
-
-struct _GHidLayerSelector {
-	GtkTreeView parent;
-
-	GtkListStore *list_store;
-	GtkTreeSelection *selection;
-	GtkTreeViewColumn *visibility_column;
-
-	GtkActionGroup *action_group;
-	GtkAccelGroup *accel_group;
-
-	GSList *radio_group;
-	int n_actions;
-
-	gboolean accel_available[20];
-
-	gboolean last_activatable;
-
-	gulong selection_changed_sig_id;
-};
-
-struct _GHidLayerSelectorClass {
-	GtkTreeViewClass parent_class;
-
-	void (*select_layer) (GHidLayerSelector *, gint);
-	void (*toggle_layer) (GHidLayerSelector *, gint);
-};
-
-struct _layer {
-	gint accel_index;							/* Index into ls->accel_available */
-	GtkWidget *pick_item;
-	GtkWidget *view_item;
-	GtkToggleAction *view_action;
-	GtkRadioAction *pick_action;
-	GtkTreeRowReference *rref;
-};
-
-/*! \brief Deletes the action and accelerator from a layer */
-static void free_ldata(GHidLayerSelector * ls, struct _layer *ldata)
-{
-	if (ldata->pick_action) {
-		gtk_action_disconnect_accelerator(GTK_ACTION(ldata->pick_action));
-		gtk_action_group_remove_action(ls->action_group, GTK_ACTION(ldata->pick_action));
-/* TODO: make this work without wrecking the radio action group
- *           g_object_unref (G_OBJECT (ldata->pick_action)); 
- *                   */
-	}
-	if (ldata->view_action) {
-		gtk_action_disconnect_accelerator(GTK_ACTION(ldata->view_action));
-		gtk_action_group_remove_action(ls->action_group, GTK_ACTION(ldata->view_action));
-		g_object_unref(G_OBJECT(ldata->view_action));
-	}
-	gtk_tree_row_reference_free(ldata->rref);
-	if (ldata->accel_index >= 0)
-		ls->accel_available[ldata->accel_index] = TRUE;
-	g_free(ldata);
-
-}
-
-/*! \brief internal set-visibility function -- emits no signals */
-static void set_visibility(GHidLayerSelector * ls, GtkTreeIter * iter, struct _layer *ldata, gboolean state)
-{
-	gtk_list_store_set(ls->list_store, iter, VISIBLE_COL, state, -1);
-
-	if ((ldata) && (ldata->view_item)) {
-		gtk_action_block_activate(GTK_ACTION(ldata->view_action));
-		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ldata->view_item), state);
-		gtk_action_unblock_activate(GTK_ACTION(ldata->view_action));
-	}
-}
-
-/*! \brief Flip the visibility state of a given layer 
- *  \par Function Description
- *  Changes the internal toggle state and menu checkbox state
- *  of the layer pointed to by iter. Emits a toggle-layer signal.
- *
- *  \param [in] ls    The selector to be acted on
- *  \param [in] iter  A GtkTreeIter pointed at the relevant layer
- *  \param [in] emit  Whether or not to emit a signal
- */
-static void toggle_visibility(GHidLayerSelector * ls, GtkTreeIter * iter, gboolean emit)
-{
-	gint user_id;
-	struct _layer *ldata;
-	gboolean toggle;
-	gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), iter, USER_ID_COL, &user_id, VISIBLE_COL, &toggle, STRUCT_COL, &ldata, -1);
-	set_visibility(ls, iter, ldata, !toggle);
-	if (emit)
-		g_signal_emit(ls, ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL], 0, user_id);
-}
-
-/*! \brief Decide if a GtkListStore entry is a layer or separator */
-static gboolean tree_view_separator_func(GtkTreeModel * model, GtkTreeIter * iter, gpointer data)
-{
-	gboolean ret_val;
-	gtk_tree_model_get(model, iter, SEPARATOR_COL, &ret_val, -1);
-	return ret_val;
-}
-
-/*! \brief Decide if a GtkListStore entry may be selected */
-static gboolean
-tree_selection_func(GtkTreeSelection * selection, GtkTreeModel * model, GtkTreePath * path, gboolean selected, gpointer data)
-{
-	GtkTreeIter iter;
-
-	if (gtk_tree_model_get_iter(model, &iter, path)) {
-		gboolean activatable;
-		gtk_tree_model_get(model, &iter, ACTIVATABLE_COL, &activatable, -1);
-		return activatable;
-	}
-
-	return FALSE;
-}
-
-/* SIGNAL HANDLERS */
-/*! \brief Callback for mouse-click: toggle visibility */
-static gboolean button_press_cb(GHidLayerSelector * ls, GdkEventButton * event)
-{
-	/* Handle visibility independently to prevent changing the active
-	 *  layer, which will happen if we let this event propagate.  */
-	GtkTreeViewColumn *column;
-	GtkTreePath *path;
-
-	/* Ignore the synthetic presses caused by double and tripple clicks, and
-	 * also ignore all but left-clicks
-	 */
-	if (event->type != GDK_BUTTON_PRESS || event->button != 1)
-		return TRUE;
-
-	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(ls), event->x, event->y, &path, &column, NULL, NULL)) {
-		GtkTreeIter iter;
-		gboolean activatable, separator;
-		gtk_tree_model_get_iter(GTK_TREE_MODEL(ls->list_store), &iter, path);
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, ACTIVATABLE_COL, &activatable, SEPARATOR_COL, &separator, -1);
-		/* Toggle visibility for non-activatable layers no matter
-		 *  where you click. */
-		if (!separator && (column == ls->visibility_column || !activatable)) {
-			toggle_visibility(ls, &iter, TRUE);
-			return TRUE;
-		}
-	}
-	return FALSE;
-}
-
-/*! \brief Callback for layer selection change: sync menu, emit signal */
-static void selection_changed_cb(GtkTreeSelection * selection, GHidLayerSelector * ls)
-{
-	GtkTreeIter iter;
-	if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
-		gint user_id;
-		struct _layer *ldata;
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &ldata, USER_ID_COL, &user_id, -1);
-
-		if (ldata && ldata->pick_action) {
-			gtk_action_block_activate(GTK_ACTION(ldata->pick_action));
-			gtk_radio_action_set_current_value(ldata->pick_action, user_id);
-			gtk_action_unblock_activate(GTK_ACTION(ldata->pick_action));
-		}
-		g_signal_emit(ls, ghid_layer_selector_signals[SELECT_LAYER_SIGNAL], 0, user_id);
-	}
-}
-
-/*! \brief Callback for menu actions: sync layer selection list, emit signal */
-static void menu_view_cb(GtkToggleAction * action, struct _layer *ldata)
-{
-	GHidLayerSelector *ls;
-	GtkTreeModel *model = gtk_tree_row_reference_get_model(ldata->rref);
-	GtkTreePath *path = gtk_tree_row_reference_get_path(ldata->rref);
-	gboolean state = gtk_toggle_action_get_active(action);
-	GtkTreeIter iter;
-	gint user_id;
-
-	gtk_tree_model_get_iter(model, &iter, path);
-	gtk_list_store_set(GTK_LIST_STORE(model), &iter, VISIBLE_COL, state, -1);
-	gtk_tree_model_get(model, &iter, USER_ID_COL, &user_id, -1);
-
-	ls = g_object_get_data(G_OBJECT(model), "layer-selector");
-	g_signal_emit(ls, ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL], 0, user_id);
-}
-
-/*! \brief Callback for menu actions: sync layer selection list, emit signal */
-static void menu_pick_cb(GtkRadioAction * action, struct _layer *ldata)
-{
-	/* We only care about the activation signal (as opposed to deactivation).
-	 * A row we are /deactivating/ might not even exist anymore! */
-	if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
-		GHidLayerSelector *ls;
-		GtkTreeModel *model = gtk_tree_row_reference_get_model(ldata->rref);
-		GtkTreePath *path = gtk_tree_row_reference_get_path(ldata->rref);
-		GtkTreeIter iter;
-		gint user_id;
-
-		gtk_tree_model_get_iter(model, &iter, path);
-		gtk_tree_model_get(model, &iter, USER_ID_COL, &user_id, -1);
-
-		ls = g_object_get_data(G_OBJECT(model), "layer-selector");
-		g_signal_handler_block(ls->selection, ls->selection_changed_sig_id);
-		gtk_tree_selection_select_path(ls->selection, path);
-		g_signal_handler_unblock(ls->selection, ls->selection_changed_sig_id);
-		g_signal_emit(ls, ghid_layer_selector_signals[SELECT_LAYER_SIGNAL], 0, user_id);
-	}
-}
-
-/* CONSTRUCTOR */
-static void ghid_layer_selector_init(GHidLayerSelector * ls)
-{
-	/* Hookup signal handlers */
-}
-
-static void ghid_layer_selector_class_init(GHidLayerSelectorClass * klass)
-{
-	GObjectClass *object_class = (GObjectClass *) klass;
-
-	ghid_layer_selector_signals[SELECT_LAYER_SIGNAL] =
-		g_signal_new("select-layer",
-								 G_TYPE_FROM_CLASS(klass),
-								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-								 G_STRUCT_OFFSET(GHidLayerSelectorClass, select_layer),
-								 NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-	ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL] =
-		g_signal_new("toggle-layer",
-								 G_TYPE_FROM_CLASS(klass),
-								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-								 G_STRUCT_OFFSET(GHidLayerSelectorClass, toggle_layer),
-								 NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-
-	object_class->finalize = ghid_layer_selector_finalize;
-}
-
-/*! \brief Clean up object before garbage collection
- */
-static void ghid_layer_selector_finalize(GObject * object)
-{
-	GtkTreeIter iter;
-	GHidLayerSelector *ls = (GHidLayerSelector *) object;
-
-	g_object_unref(ls->accel_group);
-	g_object_unref(ls->action_group);
-
-	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
-	do {
-		struct _layer *ldata;
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &ldata, -1);
-		free_ldata(ls, ldata);
-	}
-	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
-
-	G_OBJECT_CLASS(ghid_layer_selector_parent_class)->finalize(object);
-}
-
-/* PUBLIC FUNCTIONS */
-GType ghid_layer_selector_get_type(void)
-{
-	static GType ls_type = 0;
-
-	if (!ls_type) {
-		const GTypeInfo ls_info = {
-			sizeof(GHidLayerSelectorClass),
-			NULL,											/* base_init */
-			NULL,											/* base_finalize */
-			(GClassInitFunc) ghid_layer_selector_class_init,
-			NULL,											/* class_finalize */
-			NULL,											/* class_data */
-			sizeof(GHidLayerSelector),
-			0,												/* n_preallocs */
-			(GInstanceInitFunc) ghid_layer_selector_init,
-		};
-
-		ls_type = g_type_register_static(GTK_TYPE_TREE_VIEW, "GHidLayerSelector", &ls_info, 0);
-	}
-
-	return ls_type;
-}
-
-/*! \brief Create a new GHidLayerSelector
- *
- *  \return a freshly-allocated GHidLayerSelector.
- */
-GtkWidget *ghid_layer_selector_new(void)
-{
-	int i;
-	GtkCellRenderer *renderer1 = ghid_cell_renderer_visibility_new();
-	GtkCellRenderer *renderer2 = gtk_cell_renderer_text_new();
-	GtkTreeViewColumn *opacity_col = gtk_tree_view_column_new_with_attributes("", renderer1,
-																																						"active", VISIBLE_COL,
-																																						"color", COLOR_COL, NULL);
-	GtkTreeViewColumn *name_col = gtk_tree_view_column_new_with_attributes("", renderer2,
-																																				 "text", TEXT_COL,
-																																				 "font", FONT_COL,
-																																				 NULL);
-
-	GHidLayerSelector *ls = g_object_new(GHID_LAYER_SELECTOR_TYPE, NULL);
-
-	/* action index, active, color, text, font, is_separator */
-	ls->list_store = gtk_list_store_new(N_COLS, G_TYPE_POINTER, G_TYPE_INT,
-																			G_TYPE_BOOLEAN, G_TYPE_STRING,
-																			G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
-	gtk_tree_view_insert_column(GTK_TREE_VIEW(ls), opacity_col, -1);
-	gtk_tree_view_insert_column(GTK_TREE_VIEW(ls), name_col, -1);
-	gtk_tree_view_set_model(GTK_TREE_VIEW(ls), GTK_TREE_MODEL(ls->list_store));
-	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ls), FALSE);
-
-	ls->last_activatable = TRUE;
-	ls->visibility_column = opacity_col;
-	ls->selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ls));
-	ls->accel_group = gtk_accel_group_new();
-	ls->action_group = gtk_action_group_new("LayerSelector");
-	ls->n_actions = 0;
-	for (i = 0; i < 20; ++i)
-		ls->accel_available[i] = TRUE;
-
-	gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(ls), tree_view_separator_func, NULL, NULL);
-	gtk_tree_selection_set_select_function(ls->selection, tree_selection_func, NULL, NULL);
-	gtk_tree_selection_set_mode(ls->selection, GTK_SELECTION_BROWSE);
-
-	g_object_set_data(G_OBJECT(ls->list_store), "layer-selector", ls);
-	g_signal_connect(ls, "button_press_event", G_CALLBACK(button_press_cb), NULL);
-	ls->selection_changed_sig_id = g_signal_connect(ls->selection, "changed", G_CALLBACK(selection_changed_cb), ls);
-
-	g_object_ref(ls->accel_group);
-
-	return GTK_WIDGET(ls);
-}
-
-/*! \brief Add a layer to a GHidLayerSelector.
- *  \par Function Description
- *  This function adds an entry to a GHidLayerSelector, which will
- *  appear in the layer-selection list as well as visibility and selection
- *  menus (assuming this is a selectable layer). For the first 20 layers,
- *  keyboard accelerators will be added for selection/visibility toggling.
- *
- *  If the user_id passed already exists in the layer selector, that layer
- *  will have its data overwritten with the new stuff.
- *
- *  \param [in] ls            The selector to be acted on
- *  \param [in] user_id       An ID used to identify the layer; will be passed to selection/visibility callbacks
- *  \param [in] name          The name of the layer; will be used on selector and menus
- *  \param [in] color_string  The color of the layer on selector
- *  \param [in] visibile      Whether the layer is visible
- *  \param [in] activatable   Whether the layer appears in menus and can be selected
- */
-void
-ghid_layer_selector_add_layer(GHidLayerSelector * ls,
-															gint user_id,
-															const gchar * name, const gchar * color_string, gboolean visible, gboolean activatable)
-{
-	struct _layer *new_layer = NULL;
-	gchar *pname, *vname;
-	gboolean new_iter = TRUE;
-	gboolean last_activatable = TRUE;
-	GtkTreePath *path;
-	GtkTreeIter iter;
-	int i;
-
-	/* Look for existing layer with this ID */
-	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter))
-		do {
-			gboolean is_sep, active;
-			gint read_id;
-			gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store),
-												 &iter, USER_ID_COL, &read_id, SEPARATOR_COL, &is_sep, ACTIVATABLE_COL, &active, -1);
-			if (!is_sep) {
-				last_activatable = active;
-				if (read_id == user_id) {
-					new_iter = FALSE;
-					break;
-				}
-			}
-		}
-		while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
-
-	/* Handle separator addition */
-	if (new_iter) {
-		if (activatable != last_activatable) {
-			/* Add separator between activatable/non-activatable boundaries */
-			gtk_list_store_append(ls->list_store, &iter);
-			gtk_list_store_set(ls->list_store, &iter, STRUCT_COL, NULL, SEPARATOR_COL, TRUE, -1);
-		}
-		/* Create new layer */
-		new_layer = malloc(sizeof(*new_layer));
-		gtk_list_store_append(ls->list_store, &iter);
-		gtk_list_store_set(ls->list_store, &iter,
-											 STRUCT_COL, new_layer,
-											 USER_ID_COL, user_id,
-											 VISIBLE_COL, visible,
-											 COLOR_COL, color_string,
-											 TEXT_COL, name,
-											 FONT_COL, activatable ? NULL : "Italic", ACTIVATABLE_COL, activatable, SEPARATOR_COL, FALSE, -1);
-	}
-	else {
-		/* If the row exists, we clear out its ldata to create
-		 * a new action, accelerator and menu item. */
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &new_layer, -1);
-		free_ldata(ls, new_layer);
-		new_layer = malloc(sizeof(*new_layer));
-
-		gtk_list_store_set(ls->list_store, &iter,
-											 STRUCT_COL, new_layer,
-											 VISIBLE_COL, visible,
-											 COLOR_COL, color_string,
-											 TEXT_COL, name, FONT_COL, activatable ? NULL : "Italic", ACTIVATABLE_COL, activatable, -1);
-	}
-
-	/* -- Setup new actions -- */
-	vname = g_strdup_printf("LayerView%d", ls->n_actions);
-	pname = g_strdup_printf("LayerPick%d", ls->n_actions);
-
-	/* Create row reference for actions */
-	path = gtk_tree_model_get_path(GTK_TREE_MODEL(ls->list_store), &iter);
-	new_layer->rref = gtk_tree_row_reference_new(GTK_TREE_MODEL(ls->list_store), path);
-	gtk_tree_path_free(path);
-
-	/* Create selection action */
-	if (activatable) {
-		new_layer->pick_action = gtk_radio_action_new(pname, name, NULL, NULL, user_id);
-		gtk_radio_action_set_group(new_layer->pick_action, ls->radio_group);
-		ls->radio_group = gtk_radio_action_get_group(new_layer->pick_action);
-	}
-	else
-		new_layer->pick_action = NULL;
-
-	/* Create visibility action */
-	new_layer->view_action = gtk_toggle_action_new(vname, name, NULL, NULL);
-	gtk_toggle_action_set_active(new_layer->view_action, visible);
-
-	/* Determine keyboard accelerators */
-	for (i = 0; i < 20; ++i)
-		if (ls->accel_available[i])
-			break;
-	if (i < 20) {
-		/* Map 1-0 to actions 1-10 (with '0' meaning 10) */
-		gchar *accel1 = g_strdup_printf("%s%d",
-																		i < 10 ? "" : "<Alt>",
-																		(i + 1) % 10);
-		gchar *accel2 = g_strdup_printf("<Ctrl>%s%d",
-																		i < 10 ? "" : "<Alt>",
-																		(i + 1) % 10);
-
-		if (activatable) {
-			GtkAction *action = GTK_ACTION(new_layer->pick_action);
-			gtk_action_set_accel_group(action, ls->accel_group);
-			gtk_action_group_add_action_with_accel(ls->action_group, action, accel1);
-			gtk_action_connect_accelerator(action);
-			g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(menu_pick_cb), new_layer);
-		}
-		gtk_action_set_accel_group(GTK_ACTION(new_layer->view_action), ls->accel_group);
-		gtk_action_group_add_action_with_accel(ls->action_group, GTK_ACTION(new_layer->view_action), accel2);
-		gtk_action_connect_accelerator(GTK_ACTION(new_layer->view_action));
-		g_signal_connect(G_OBJECT(new_layer->view_action), "activate", G_CALLBACK(menu_view_cb), new_layer);
-
-		ls->accel_available[i] = FALSE;
-		new_layer->accel_index = i;
-		g_free(accel2);
-		g_free(accel1);
-	}
-	else {
-		new_layer->accel_index = -1;
-	}
-	/* finalize new layer struct */
-	new_layer->pick_item = new_layer->view_item = NULL;
-
-	/* cleanup */
-	g_free(vname);
-	g_free(pname);
-
-	ls->n_actions++;
-}
-
-/*! \brief Install the "Current Layer" menu items for a layer selector
- *  \par Function Description
- *  Takes a menu shell and installs menu items for layer selection in
- *  the shell, at the given position.
- *
- *  \param [in] ls      The selector to be acted on
- *  \param [in] shell   The menu to install the items in
- *  \param [in] pos     The position in the menu to install items
- *
- *  \return the number of items installed
- */
-gint ghid_layer_selector_install_pick_items(GHidLayerSelector * ls, GtkMenuShell * shell, gint pos)
-{
-	GtkTreeIter iter;
-	int n = 0;
-
-	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
-	do {
-		struct _layer *ldata;
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &ldata, -1);
-		if (ldata && ldata->pick_action) {
-			GtkAction *action = GTK_ACTION(ldata->pick_action);
-			ldata->pick_item = gtk_action_create_menu_item(action);
-			gtk_menu_shell_insert(shell, ldata->pick_item, pos + n);
-			++n;
-		}
-	}
-	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
-
-	return n;
-}
-
-/*! \brief Install the "Shown Layers" menu items for a layer selector
- *  \par Function Description
- *  Takes a menu shell and installs menu items for layer selection in
- *  the shell, at the given position.
- *
- *  \param [in] ls      The selector to be acted on
- *  \param [in] shell   The menu to install the items in
- *  \param [in] pos     The position in the menu to install items
- *
- *  \return the number of items installed
- */
-gint ghid_layer_selector_install_view_items(GHidLayerSelector * ls, GtkMenuShell * shell, gint pos)
-{
-	GtkTreeIter iter;
-	int n = 0;
-
-	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
-	do {
-		struct _layer *ldata;
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &ldata, -1);
-		if (ldata && ldata->view_action) {
-			GtkAction *action = GTK_ACTION(ldata->view_action);
-			ldata->view_item = gtk_action_create_menu_item(action);
-			gtk_menu_shell_insert(shell, ldata->view_item, pos + n);
-			++n;
-		}
-	}
-	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
-
-	return n;
-}
-
-/*! \brief Returns the GtkAccelGroup of a layer selector
- *  \par Function Description
- *
- *  \param [in] ls            The selector to be acted on
- *
- *  \return the accel group of the selector
- */
-GtkAccelGroup *ghid_layer_selector_get_accel_group(GHidLayerSelector * ls)
-{
-	return ls->accel_group;
-}
-
-/*! \brief used internally */
-static gboolean toggle_foreach_func(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
-{
-	gint id;
-	GHidLayerSelector *ls = g_object_get_data(G_OBJECT(model),
-																						"layer-selector");
-
-	gtk_tree_model_get(model, iter, USER_ID_COL, &id, -1);
-	if (id == *(gint *) data) {
-		toggle_visibility(ls, iter, TRUE);
-		return TRUE;
-	}
-	return FALSE;
-}
-
-/*! \brief Toggle a layer's visibility
- *  \par Function Description
- *  Toggle the layer indicated by user_id, emitting a layer-toggle signal.
- *
- *  \param [in] ls       The selector to be acted on
- *  \param [in] user_id  The ID of the layer to be affected
- */
-void ghid_layer_selector_toggle_layer(GHidLayerSelector * ls, gint user_id)
-{
-	gtk_tree_model_foreach(GTK_TREE_MODEL(ls->list_store), toggle_foreach_func, &user_id);
-}
-
-/*! \brief used internally */
-static gboolean select_foreach_func(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
-{
-	gint id;
-	GHidLayerSelector *ls = g_object_get_data(G_OBJECT(model),
-																						"layer-selector");
-
-	gtk_tree_model_get(model, iter, USER_ID_COL, &id, -1);
-	if (id == *(gint *) data) {
-		gtk_tree_selection_select_path(ls->selection, path);
-		return TRUE;
-	}
-	return FALSE;
-}
-
-/*! \brief Select a layer
- *  \par Function Description
- *  Select the layer indicated by user_id, emitting a layer-select signal.
- *
- *  \param [in] ls       The selector to be acted on
- *  \param [in] user_id  The ID of the layer to be affected
- */
-void ghid_layer_selector_select_layer(GHidLayerSelector * ls, gint user_id)
-{
-	gtk_tree_model_foreach(GTK_TREE_MODEL(ls->list_store), select_foreach_func, &user_id);
-}
-
-/*! \brief Selects the next visible layer
- *  \par Function Description
- *  Used to ensure hidden layers are not active; if the active layer is
- *  visible, this function is a noop. Otherwise, it will look for the
- *  next layer that IS visible, and select that. Failing that, it will
- *  return FALSE.
- *
- *  \param [in] ls       The selector to be acted on
- *
- *  \return TRUE on success, FALSE if all selectable layers are hidden
- */
-gboolean ghid_layer_selector_select_next_visible(GHidLayerSelector * ls)
-{
-	GtkTreeIter iter;
-	if (gtk_tree_selection_get_selected(ls->selection, NULL, &iter)) {
-		/* Scan forward, looking for selectable iter */
-		do {
-			gboolean visible, activatable;
-			gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, VISIBLE_COL, &visible, ACTIVATABLE_COL, &activatable, -1);
-			if (visible && activatable) {
-				gtk_tree_selection_select_iter(ls->selection, &iter);
-				return TRUE;
-			}
-		}
-		while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
-		/* Move iter to start, and repeat. */
-		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
-		do {
-			gboolean visible, activatable;
-			gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, VISIBLE_COL, &visible, ACTIVATABLE_COL, &activatable, -1);
-			if (visible && activatable) {
-				gtk_tree_selection_select_iter(ls->selection, &iter);
-				return TRUE;
-			}
-		}
-		while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
-		/* Failing this, just emit a selected signal on the original layer. */
-		selection_changed_cb(ls->selection, ls);
-	}
-	/* If we get here, nothing is selectable, so fail. */
-	return FALSE;
-}
-
-/*! \brief Makes the selected layer visible
- *  \par Function Description
- *  Used to ensure hidden layers are not active; un-hides the currently
- *  selected layer.
- *
- *  \param [in] ls       The selector to be acted on
- */
-void ghid_layer_selector_make_selected_visible(GHidLayerSelector * ls)
-{
-	GtkTreeIter iter;
-	if (gtk_tree_selection_get_selected(ls->selection, NULL, &iter)) {
-		gboolean visible;
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, VISIBLE_COL, &visible, -1);
-		if (!visible)
-			toggle_visibility(ls, &iter, FALSE);
-	}
-}
-
-/*! \brief Sets the colors of all layers in a layer-selector
- *  \par Function Description
- *  Updates the colors of a layer selector via a callback mechanism:
- *  the user_id of each layer is passed to the callback function,
- *  which returns a color string to update the layer's color, or NULL
- *  to leave it alone.
- *
- *  \param [in] ls       The selector to be acted on
- *  \param [in] callback Takes the user_id of the layer and returns a color string
- */
-void ghid_layer_selector_update_colors(GHidLayerSelector * ls, const gchar * (*callback) (int user_id))
-{
-	GtkTreeIter iter;
-	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
-	do {
-		gint user_id;
-		const gchar *new_color;
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, USER_ID_COL, &user_id, -1);
-		new_color = callback(user_id);
-		if (new_color != NULL)
-			gtk_list_store_set(ls->list_store, &iter, COLOR_COL, new_color, -1);
-	}
-	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
-}
-
-/*! \brief Deletes layers from a layer selector
- *  \par Function Description
- *  Deletes layers according to a callback function: a return value of TRUE
- *  means delete, FALSE means leave it alone. Do not try to delete all layers
- *  using this function; with nothing left to select, pcb will likely go into
- *  an infinite recursion between pcb_hid_action() and g_signal().
- *
- *  Separators will be deleted if the layer AFTER them is deleted.
- *
- *  \param [in] ls       The selector to be acted on
- *  \param [in] callback Takes the user_id of the layer and returns a boolean
- */
-void ghid_layer_selector_delete_layers(GHidLayerSelector * ls, gboolean(*callback) (int user_id))
-{
-	GtkTreeIter iter, last_iter;
-
-	gboolean iter_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
-	while (iter_valid) {
-		struct _layer *ldata;
-		gboolean sep, was_sep = FALSE;
-		gint user_id;
-
-		/* Find next iter to delete */
-		while (iter_valid) {
-			gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store),
-												 &iter, USER_ID_COL, &user_id, STRUCT_COL, &ldata, SEPARATOR_COL, &sep, -1);
-			if (!sep && callback(user_id))
-				break;
-
-			/* save iter in case it's a bad separator */
-			was_sep = sep;
-			last_iter = iter;
-			/* iterate */
-			iter_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter);
-		}
-
-		if (iter_valid) {
-			/* remove preceeding separator */
-			if (was_sep)
-				gtk_list_store_remove(ls->list_store, &last_iter);
-
-					/*** remove row ***/
-			iter_valid = gtk_list_store_remove(ls->list_store, &iter);
-			free_ldata(ls, ldata);
-		}
-		last_iter = iter;
-	}
-}
-
-/*! \brief Sets the visibility toggle-state of all layers
- *  \par Function Description
- *  Shows layers according to a callback function: a return value of TRUE
- *  means show, FALSE means hide.
- *
- *  \param [in] ls       The selector to be acted on
- *  \param [in] callback Takes the user_id of the layer and returns a boolean
- */
-void ghid_layer_selector_show_layers(GHidLayerSelector * ls, gboolean(*callback) (int user_id))
-{
-	GtkTreeIter iter;
-	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
-	do {
-		struct _layer *ldata;
-		gboolean sep;
-		gint user_id;
-
-		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store),
-											 &iter, USER_ID_COL, &user_id, STRUCT_COL, &ldata, SEPARATOR_COL, &sep, -1);
-		if (!sep)
-			set_visibility(ls, &iter, ldata, callback(user_id));
-	}
-	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
-}
diff --git a/src_plugins/hid_gtk/ghid-layer-selector.h b/src_plugins/hid_gtk/ghid-layer-selector.h
deleted file mode 100644
index 56a00a3..0000000
--- a/src_plugins/hid_gtk/ghid-layer-selector.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef GHID_LAYER_SELECTOR_H__
-#define GHID_LAYER_SELECTOR_H__
-
-#include <glib.h>
-#include <glib-object.h>
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS										/* keep c++ happy */
-#define GHID_LAYER_SELECTOR_TYPE            (ghid_layer_selector_get_type ())
-#define GHID_LAYER_SELECTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_LAYER_SELECTOR_TYPE, GHidLayerSelector))
-#define GHID_LAYER_SELECTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GHID_LAYER_SELECTOR_TYPE, GHidLayerSelectorClass))
-#define IS_GHID_LAYER_SELECTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_LAYER_SELECTOR_TYPE))
-#define IS_GHID_LAYER_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHID_LAYER_SELECTOR_TYPE))
-typedef struct _GHidLayerSelector GHidLayerSelector;
-typedef struct _GHidLayerSelectorClass GHidLayerSelectorClass;
-
-GType ghid_layer_selector_get_type(void);
-GtkWidget *ghid_layer_selector_new(void);
-
-void ghid_layer_selector_add_layer(GHidLayerSelector * ls,
-																	 gint user_id,
-																	 const gchar * name, const gchar * color_string, gboolean visible, gboolean activatable);
-
-gint ghid_layer_selector_install_pick_items(GHidLayerSelector * ls, GtkMenuShell * shell, gint pos);
-gint ghid_layer_selector_install_view_items(GHidLayerSelector * ls, GtkMenuShell * shell, gint pos);
-
-GtkAccelGroup *ghid_layer_selector_get_accel_group(GHidLayerSelector * ls);
-
-void ghid_layer_selector_toggle_layer(GHidLayerSelector * ls, gint user_id);
-void ghid_layer_selector_select_layer(GHidLayerSelector * ls, gint user_id);
-gboolean ghid_layer_selector_select_next_visible(GHidLayerSelector * ls);
-void ghid_layer_selector_make_selected_visible(GHidLayerSelector * ls);
-void ghid_layer_selector_update_colors(GHidLayerSelector * ls, const gchar * (*callback) (int user_id));
-void ghid_layer_selector_delete_layers(GHidLayerSelector * ls, gboolean(*callback) (int user_id));
-void ghid_layer_selector_show_layers(GHidLayerSelector * ls, gboolean(*callback) (int user_id));
-
-G_END_DECLS											/* keep c++ happy */
-#endif
diff --git a/src_plugins/hid_gtk/ghid-main-menu.c b/src_plugins/hid_gtk/ghid-main-menu.c
index 7760452..4349b83 100644
--- a/src_plugins/hid_gtk/ghid-main-menu.c
+++ b/src_plugins/hid_gtk/ghid-main-menu.c
@@ -4,31 +4,33 @@
  *  This widget is the main pcb menu.
  */
 
-#include <glib.h>
-#include <glib-object.h>
+/*#include <glib.h>
+#include <glib-object.h>*/
 #include <gtk/gtk.h>
 #include <liblihata/tree.h>
 
 #include "config.h"
-#include "gtkhid.h"
+#include "gtkhid-main.h"
 #include "gui.h"
 #include "pcb-printf.h"
 #include "misc_util.h"
 #include "error.h"
 #include "conf.h"
 #include "ghid-main-menu.h"
-#include "ghid-layer-selector.h"
-#include "ghid-route-style-selector.h"
+#include "../src_plugins/lib_gtk_common/wt_layer_selector.h"
+#include "../src_plugins/lib_gtk_common/wt_route_style.h"
+
 #include "gschem_accel_label.h"
 
+
 static int action_counter;
 
 typedef struct {
-	GtkWidget *widget;  /* for most uses */
-	GtkWidget *destroy; /* destroy this */
+	GtkWidget *widget;						/* for most uses */
+	GtkWidget *destroy;						/* destroy this */
 } menu_handle_t;
 
-static menu_handle_t *handle_alloc(GtkWidget *widget, GtkWidget *destroy)
+static menu_handle_t *handle_alloc(GtkWidget * widget, GtkWidget * destroy)
 {
 	menu_handle_t *m = malloc(sizeof(menu_handle_t));
 	m->widget = widget;
@@ -69,7 +71,7 @@ struct _GHidMainMenuClass {
 
 /* LHT HANDLER */
 
-void ghid_main_menu_real_add_node(GHidMainMenu * menu, GtkMenuShell * shell, lht_node_t *base);
+void ghid_main_menu_real_add_node(GHidMainMenu * menu, GtkMenuShell * shell, lht_node_t * base);
 
 extern conf_hid_id_t ghid_menuconf_id;
 static GtkAction *ghid_add_menu(GHidMainMenu * menu, GtkMenuShell * shell, lht_node_t * sub_res)
@@ -81,6 +83,7 @@ static GtkAction *ghid_add_menu(GHidMainMenu * menu, GtkMenuShell * shell, lht_n
 	char *menu_label;
 	lht_node_t *n_action = pcb_hid_cfg_menu_field(sub_res, PCB_MF_ACTION, NULL);
 	lht_node_t *n_keydesc = pcb_hid_cfg_menu_field(sub_res, PCB_MF_ACCELERATOR, NULL);
+	int is_main;
 
 	/* Resolve accelerator and save it */
 	if (n_keydesc != NULL) {
@@ -92,6 +95,9 @@ static GtkAction *ghid_add_menu(GHidMainMenu * menu, GtkMenuShell * shell, lht_n
 			pcb_hid_cfg_error(sub_res, "No action specified for key accel\n");
 	}
 
+	is_main = (sub_res->parent->type == LHT_LIST) && (sub_res->parent->name != NULL)
+		&& (strcmp(sub_res->parent->name, "main_menu") == 0);
+
 	/* Resolve the mnemonic */
 	tmp_val = pcb_hid_cfg_menu_field_str(sub_res, PCB_MF_MNEMONIC);
 	if (tmp_val)
@@ -101,7 +107,7 @@ static GtkAction *ghid_add_menu(GHidMainMenu * menu, GtkMenuShell * shell, lht_n
 	tmp_val = sub_res->name;
 
 	/* Hack '_' in based on mnemonic value */
-	if (!mnemonic)
+	if ((!mnemonic) || (is_main))
 		menu_label = g_strdup(tmp_val);
 	else {
 		char *post_ = strchr(tmp_val, mnemonic);
@@ -135,7 +141,7 @@ static GtkAction *ghid_add_menu(GHidMainMenu * menu, GtkMenuShell * shell, lht_n
 		   the node format is correct; iterate over the list of submenus and create
 		   them recursively. */
 		n = pcb_hid_cfg_menu_field(sub_res, PCB_MF_SUBMENU, NULL);
-		for(n = n->data.list.first; n != NULL; n = n->next)
+		for (n = n->data.list.first; n != NULL; n = n->next)
 			ghid_main_menu_real_add_node(menu, GTK_MENU_SHELL(submenu), n);
 	}
 	else {
@@ -170,8 +176,9 @@ static GtkAction *ghid_add_menu(GHidMainMenu * menu, GtkMenuShell * shell, lht_n
 				conf_hid_set_cb(nat, ghid_menuconf_id, &cbs);
 			}
 			else {
-				if ((update_on == NULL) || (*update_on != '\0')) /* warn if update_on is not explicitly empty */
-					pcb_message(PCB_MSG_WARNING, "Checkbox menu item not %s updated on any conf change - try to use the update_on field\n", checked);
+				if ((update_on == NULL) || (*update_on != '\0'))	/* warn if update_on is not explicitly empty */
+					pcb_message(PCB_MSG_WARNING,
+											"Checkbox menu item not %s updated on any conf change - try to use the update_on field\n", checked);
 			}
 		}
 		else if (label && strcmp(label, "false") == 0) {
@@ -187,7 +194,7 @@ static GtkAction *ghid_add_menu(GHidMainMenu * menu, GtkMenuShell * shell, lht_n
 			accel = NULL;
 			gtk_menu_shell_append(shell, item);
 			sub_res->user_data = handle_alloc(item, item);
-			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu->action_cb), (gpointer)n_action);
+			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu->action_cb), (gpointer) n_action);
 			if ((tip != NULL) || (n_keydesc != NULL)) {
 				char *acc = NULL, *s;
 				if (n_keydesc != NULL)
@@ -227,58 +234,59 @@ static GtkAction *ghid_add_menu(GHidMainMenu * menu, GtkMenuShell * shell, lht_n
  *  \param [in] shall   The base menu shell (a menu bar or popup menu)
  *  \param [in] base    The base of the menu item subtree
  * */
-void ghid_main_menu_real_add_node(GHidMainMenu * menu, GtkMenuShell * shell, lht_node_t *base)
+void ghid_main_menu_real_add_node(GHidMainMenu * menu, GtkMenuShell * shell, lht_node_t * base)
 {
-	switch(base->type) {
-		case LHT_HASH: /* leaf submenu */
-			{
-				GtkAction *action = NULL;
-				action = ghid_add_menu(menu, shell, base);
-				if (action) {
-					const char *val;
-
-					val = pcb_hid_cfg_menu_field_str(base, PCB_MF_CHECKED);
-					if (val != NULL)
-						g_object_set_data(G_OBJECT(action), "checked-flag", (gpointer *)val);
-
-					val = pcb_hid_cfg_menu_field_str(base, PCB_MF_ACTIVE);
-					if (val != NULL)
-						g_object_set_data(G_OBJECT(action), "active-flag", (gpointer *)val);
-				}
+	switch (base->type) {
+	case LHT_HASH:								/* leaf submenu */
+		{
+			GtkAction *action = NULL;
+			action = ghid_add_menu(menu, shell, base);
+			if (action) {
+				const char *val;
+
+				val = pcb_hid_cfg_menu_field_str(base, PCB_MF_CHECKED);
+				if (val != NULL)
+					g_object_set_data(G_OBJECT(action), "checked-flag", (gpointer *) val);
+
+				val = pcb_hid_cfg_menu_field_str(base, PCB_MF_ACTIVE);
+				if (val != NULL)
+					g_object_set_data(G_OBJECT(action), "active-flag", (gpointer *) val);
 			}
-			break;
-		case LHT_TEXT: /* separator */
-			{
-				GList *children;
-				int pos;
-
-				children = gtk_container_get_children(GTK_CONTAINER(shell));
-				pos = g_list_length(children);
-				g_list_free(children);
-
-				if ((strcmp(base->data.text.value, "sep") == 0) || (strcmp(base->data.text.value, "-") == 0)) {
-					GtkWidget *item = gtk_separator_menu_item_new();
-					gtk_menu_shell_append(shell, item);
-					base->user_data = handle_alloc(item, item);
-				}
-				else if (strcmp(base->data.text.value, "@layerview") == 0) {
-					menu->layer_view_shell = shell;
-					menu->layer_view_pos = pos;
-				}
-				else if (strcmp(base->data.text.value, "@layerpick") == 0) {
-					menu->layer_pick_shell = shell;
-					menu->layer_pick_pos = pos;
-				}
-				else if (strcmp(base->data.text.value, "@routestyles") == 0) {
-					menu->route_style_shell = shell;
-					menu->route_style_pos = pos;
-				}
-				else
-					pcb_hid_cfg_error(base, "Unexpected text node; the only text accepted here is sep, -, @layerview, @layerpick and @routestyles");
+		}
+		break;
+	case LHT_TEXT:								/* separator */
+		{
+			GList *children;
+			int pos;
+
+			children = gtk_container_get_children(GTK_CONTAINER(shell));
+			pos = g_list_length(children);
+			g_list_free(children);
+
+			if ((strcmp(base->data.text.value, "sep") == 0) || (strcmp(base->data.text.value, "-") == 0)) {
+				GtkWidget *item = gtk_separator_menu_item_new();
+				gtk_menu_shell_append(shell, item);
+				base->user_data = handle_alloc(item, item);
+			}
+			else if (strcmp(base->data.text.value, "@layerview") == 0) {
+				menu->layer_view_shell = shell;
+				menu->layer_view_pos = pos;
+			}
+			else if (strcmp(base->data.text.value, "@layerpick") == 0) {
+				menu->layer_pick_shell = shell;
+				menu->layer_pick_pos = pos;
+			}
+			else if (strcmp(base->data.text.value, "@routestyles") == 0) {
+				menu->route_style_shell = shell;
+				menu->route_style_pos = pos;
 			}
-			break;
-		default:
-			pcb_hid_cfg_error(base, "Unexpected node type; should be hash (submenu) or text (separator or @special)");
+			else
+				pcb_hid_cfg_error(base,
+													"Unexpected text node; the only text accepted here is sep, -, @layerview, @layerpick and @routestyles");
+		}
+		break;
+	default:
+		pcb_hid_cfg_error(base, "Unexpected node type; should be hash (submenu) or text (separator or @special)");
 	}
 }
 
@@ -344,20 +352,20 @@ GtkWidget *ghid_main_menu_new(GCallback action_cb)
 }
 
 /*! \brief Turn a lht node into the main menu */
-void ghid_main_menu_add_node(GHidMainMenu * menu, const lht_node_t *base)
+void ghid_main_menu_add_node(GHidMainMenu * menu, const lht_node_t * base)
 {
 	lht_node_t *n;
 	if (base->type != LHT_LIST) {
 		pcb_hid_cfg_error(base, "Menu description shall be a list (li)\n");
 		abort();
 	}
-	for(n = base->data.list.first; n != NULL; n = n->next) {
+	for (n = base->data.list.first; n != NULL; n = n->next) {
 		ghid_main_menu_real_add_node(menu, GTK_MENU_SHELL(menu), n);
 	}
 }
 
 /*! \brief Turn a lihata node into a popup menu */
-void ghid_main_menu_add_popup_node(GHidMainMenu * menu, lht_node_t *base)
+void ghid_main_menu_add_popup_node(GHidMainMenu * menu, lht_node_t * base)
 {
 	lht_node_t *submenu, *i;
 	GtkWidget *new_menu;
@@ -372,7 +380,7 @@ void ghid_main_menu_add_popup_node(GHidMainMenu * menu, lht_node_t *base)
 	g_object_ref_sink(new_menu);
 	base->user_data = handle_alloc(new_menu, new_menu);
 
-	for(i = submenu->data.list.first; i != NULL; i = i->next)
+	for (i = submenu->data.list.first; i != NULL; i = i->next)
 		ghid_main_menu_real_add_node(menu, GTK_MENU_SHELL(new_menu), i);
 
 	gtk_widget_show_all(new_menu);
@@ -407,7 +415,7 @@ ghid_main_menu_update_toggle_state(GHidMainMenu * menu,
 }
 
 /*! \brief Installs or updates layer selector items */
-void ghid_main_menu_install_layer_selector(GHidMainMenu * mm, GHidLayerSelector * ls)
+void ghid_main_menu_install_layer_selector(GHidMainMenu * mm, pcb_gtk_layer_selector_t * ls)
 {
 	GList *children, *iter;
 
@@ -421,7 +429,7 @@ void ghid_main_menu_install_layer_selector(GHidMainMenu * mm, GHidLayerSelector
 		g_list_free(children);
 
 		/* Install new ones */
-		mm->n_layer_views = ghid_layer_selector_install_view_items(ls, mm->layer_view_shell, mm->layer_view_pos);
+		mm->n_layer_views = pcb_gtk_layer_selector_install_view_items(ls, mm->layer_view_shell, mm->layer_view_pos);
 	}
 
 	/* @layerpick */
@@ -434,12 +442,12 @@ void ghid_main_menu_install_layer_selector(GHidMainMenu * mm, GHidLayerSelector
 		g_list_free(children);
 
 		/* Install new ones */
-		mm->n_layer_picks = ghid_layer_selector_install_pick_items(ls, mm->layer_pick_shell, mm->layer_pick_pos);
+		mm->n_layer_picks = pcb_gtk_layer_selector_install_pick_items(ls, mm->layer_pick_shell, mm->layer_pick_pos);
 	}
 }
 
 /*! \brief Installs or updates route style selector items */
-void ghid_main_menu_install_route_style_selector(GHidMainMenu * mm, GHidRouteStyleSelector * rss)
+void ghid_main_menu_install_route_style_selector(GHidMainMenu * mm, pcb_gtk_route_style_t * rss)
 {
 	GList *children, *iter;
 	/* @routestyles */
@@ -451,7 +459,7 @@ void ghid_main_menu_install_route_style_selector(GHidMainMenu * mm, GHidRouteSty
 			gtk_container_remove(GTK_CONTAINER(mm->route_style_shell), iter->data);
 		g_list_free(children);
 		/* Install new ones */
-		mm->n_route_styles = ghid_route_style_selector_install_items(rss, mm->route_style_shell, mm->route_style_pos);
+		mm->n_route_styles = pcb_gtk_route_style_install_items(rss, mm->route_style_shell, mm->route_style_pos);
 	}
 }
 
@@ -466,7 +474,7 @@ GtkAccelGroup *ghid_main_menu_get_accel_group(GHidMainMenu * menu)
 }
 
 /* Create a new popup window */
-static GtkWidget *new_popup(lht_node_t *menu_item)
+static GtkWidget *new_popup(lht_node_t * menu_item)
 {
 	GtkWidget *new_menu = gtk_menu_new();
 /*	GHidMainMenu *menu  = GHID_MAIN_MENU(ghidgui->menu_bar);*/
@@ -478,7 +486,8 @@ static GtkWidget *new_popup(lht_node_t *menu_item)
 }
 
 /* Menu widget create callback: create a main menu, popup or submenu as descending the path */
-static int ghid_create_menu_widget(void *ctx, const char *path, const char *name, int is_main, lht_node_t *parent, lht_node_t *menu_item)
+static int ghid_create_menu_widget(void *ctx, const char *path, const char *name, int is_main, lht_node_t * parent,
+																	 lht_node_t * menu_item)
 {
 	int is_popup = (strncmp(path, "/popups", 7) == 0);
 	menu_handle_t *ph = parent->user_data;
@@ -491,7 +500,7 @@ static int ghid_create_menu_widget(void *ctx, const char *path, const char *name
 	return 0;
 }
 
-static int ghid_remove_menu_widget(void *ctx, lht_node_t *nd)
+static int ghid_remove_menu_widget(void *ctx, lht_node_t * nd)
 {
 	menu_handle_t *h = nd->user_data;
 	if (h != NULL) {
@@ -510,7 +519,8 @@ static int ghid_remove_menu_widget(void *ctx, lht_node_t *nd)
 }
 
 /* Create a new menu by path */
-void ghid_create_menu(const char *menu_path, const char *action, const char *mnemonic, const char *accel, const char *tip, const char *cookie)
+void ghid_create_menu(const char *menu_path, const char *action, const char *mnemonic, const char *accel, const char *tip,
+											const char *cookie)
 {
 	pcb_hid_cfg_create_menu(ghid_cfg, menu_path, action, mnemonic, accel, tip, cookie, ghid_create_menu_widget, NULL);
 }
@@ -519,4 +529,3 @@ int ghid_remove_menu(const char *menu_path)
 {
 	return pcb_hid_cfg_remove_menu(ghid_cfg, menu_path, ghid_remove_menu_widget, NULL);
 }
-
diff --git a/src_plugins/hid_gtk/ghid-main-menu.h b/src_plugins/hid_gtk/ghid-main-menu.h
index 5d91fcf..0db87c7 100644
--- a/src_plugins/hid_gtk/ghid-main-menu.h
+++ b/src_plugins/hid_gtk/ghid-main-menu.h
@@ -1,12 +1,9 @@
 #ifndef GHID_MAIN_MENU_H__
 #define GHID_MAIN_MENU_H__
 
-#include <glib.h>
-#include <glib-object.h>
-#include <gtk/gtk.h>
+#include "../src_plugins/lib_gtk_common/wt_layer_selector.h"
+#include "../src_plugins/lib_gtk_common/wt_route_style.h"
 
-#include "ghid-layer-selector.h"
-#include "ghid-route-style-selector.h"
 #include "hid_cfg.h"
 #include "hid_cfg_input.h"
 
@@ -21,17 +18,18 @@ typedef struct _GHidMainMenuClass GHidMainMenuClass;
 
 GType ghid_main_menu_get_type(void);
 GtkWidget *ghid_main_menu_new(GCallback action_cb);
-void ghid_main_menu_add_node(GHidMainMenu * menu, const lht_node_t *base);
+void ghid_main_menu_add_node(GHidMainMenu * menu, const lht_node_t * base);
 GtkAccelGroup *ghid_main_menu_get_accel_group(GHidMainMenu * menu);
 void ghid_main_menu_update_toggle_state(GHidMainMenu * menu,
 																				void (*cb) (GtkAction *, const char *toggle_flag, const char *active_flag));
 
-void ghid_main_menu_add_popup_node(GHidMainMenu * menu, lht_node_t *base);
+void ghid_main_menu_add_popup_node(GHidMainMenu * menu, lht_node_t * base);
 
-void ghid_main_menu_install_layer_selector(GHidMainMenu * mm, GHidLayerSelector * ls);
-void ghid_main_menu_install_route_style_selector(GHidMainMenu * mm, GHidRouteStyleSelector * rss);
+void ghid_main_menu_install_layer_selector(GHidMainMenu * mm, pcb_gtk_layer_selector_t * ls);
+void ghid_main_menu_install_route_style_selector(GHidMainMenu * mm, pcb_gtk_route_style_t * rss);
 
-void ghid_create_menu(const char *menu_path, const char *action, const char *mnemonic, const char *accel, const char *tip, const char *cookie);
+void ghid_create_menu(const char *menu_path, const char *action, const char *mnemonic, const char *accel, const char *tip,
+											const char *cookie);
 int ghid_remove_menu(const char *menu_path);
 
 extern pcb_hid_cfg_t *ghid_cfg;
diff --git a/src_plugins/hid_gtk/ghid-propedit.c b/src_plugins/hid_gtk/ghid-propedit.c
deleted file mode 100644
index 0fefa2b..0000000
--- a/src_plugins/hid_gtk/ghid-propedit.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  pcb-rnd, interactive printed circuit board design
- *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* object property edit dialog */
-
-#include <stdlib.h>
-#include <string.h>
-#include <gtk/gtk.h>
-#include "config.h"
-#include "gui.h"
-#include "compat_misc.h"
-#include "compat_nls.h"
-#include "polygon.h"
-#include "obj_all.h"
-
-static char *str_sub(const char *val, char sepi, char sepo)
-{
-	char *tmp, *sep;
-	tmp = pcb_strdup(val);
-	sep = strchr(tmp, sepi);
-	if (sep != NULL)
-		*sep = sepo;
-	return tmp;
-}
-
-static void val_combo_changed_cb(GtkComboBox * combo, ghid_propedit_dialog_t *dlg)
-{
-	char *cval, *tmp;
-	GtkTreeIter iter;
-	if (gtk_combo_box_get_active_iter(combo, &iter)) {
-		gtk_tree_model_get(GTK_TREE_MODEL(dlg->vals), &iter, 0, &cval, -1);
-		dlg->stock_val = 1;
-		tmp = str_sub(cval, '=', '\0');
-		gtk_entry_set_text(GTK_ENTRY(dlg->entry_val), tmp);
-		free(tmp);
-	}
-}
-
-static void val_entry_changed_cb(GtkWidget *entry, ghid_propedit_dialog_t *dlg)
-{
-	if (dlg->stock_val == 0)
-		gtk_combo_box_set_active(GTK_COMBO_BOX(dlg->val_box), -1);
-	else
-		dlg->stock_val = 0;
-}
-
-static void val_combo_reset(ghid_propedit_dialog_t *dlg)
-{
-	gtk_list_store_clear(dlg->vals);
-}
-
-static void val_combo_add(ghid_propedit_dialog_t *dlg, const char *val)
-{
-	gtk_list_store_insert_with_values(dlg->vals, NULL, -1, 0, val, -1);
-}
-
-#define NO0(s) pcb_strdup((s) == NULL ? "" : (s))
-void ghid_propedit_prop_add(ghid_propedit_dialog_t *dlg, const char *name, const char *common, const char *min, const char *max, const char *avg)
-{
-	gtk_list_store_insert_with_values(dlg->props, &dlg->last_add_iter, -1,  0,pcb_strdup(name),  1,NO0(common),  2,NO0(min),  3,NO0(max),  4,NO0(avg),  -1);
-	dlg->last_add_iter_valid = 1;
-}
-
-static void hdr_add(ghid_propedit_dialog_t *dlg, const char *name, int col)
-{
-	GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dlg->tree), -1, name, renderer, "text", col, NULL);
-}
-
-
-static void list_cursor_changed_cb(GtkWidget *tree, ghid_propedit_dialog_t *dlg)
-{
-	GtkTreeSelection *tsel;
-	GtkTreeModel *tm;
-	GtkTreeIter iter;
-	const char *prop, *comm, *val;
-	char *tmp;
-
-	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->tree));
-	if (tsel == NULL)
-		return;
-
-	gtk_tree_selection_get_selected(tsel, &tm, &iter);
-	if (iter.stamp == 0)
-		return;
-
-	gtk_tree_model_get(tm, &iter, 0, &prop, 1, &comm, -1);
-
-	printf("prop: %s!\n", prop);
-
-	val_combo_reset(dlg);
-
-	val = ghidgui->propedit_query(ghidgui->propedit_pe, "v1st", prop, NULL, 0);
-	while(val != NULL) {
-		tmp = str_sub(val, '\n', '=');
-		val_combo_add(dlg, tmp);
-		free(tmp);
-		val = ghidgui->propedit_query(ghidgui->propedit_pe, "vnxt", prop, NULL, 0);
-	}
-
-	tmp = str_sub(comm, '\n', '\0');
-	gtk_entry_set_text(GTK_ENTRY(dlg->entry_val), tmp);
-	free(tmp);
-}
-
-static void do_remove_cb(GtkWidget *tree, ghid_propedit_dialog_t *dlg)
-{
-	GtkTreeSelection *tsel;
-	GtkTreeModel *tm;
-	GtkTreeIter iter;
-	char *prop;
-
-	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->tree));
-	if (tsel == NULL)
-		return;
-
-	gtk_tree_selection_get_selected(tsel, &tm, &iter);
-	if (iter.stamp == 0)
-		return;
-
-	gtk_tree_model_get(tm, &iter, 0, &prop, -1);
-
-	if (ghidgui->propedit_query(ghidgui->propedit_pe, "vdel", prop, NULL, 0) != NULL)
-		gtk_list_store_remove(GTK_LIST_STORE(tm), &iter);
-
-	free(prop);
-}
-
-static int keyval_input(char **key, char **val)
-{
-	GtkWidget *dialog;
-	GtkWidget *content_area;
-	GtkWidget *vbox, *label, *kentry, *ventry;
-	gboolean response;
-	GHidPort *out = &ghid_port;
-
-	dialog = gtk_dialog_new_with_buttons("New attribute",
-																			 GTK_WINDOW(out->top_window),
-																			 GTK_DIALOG_MODAL,
-																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
-	vbox = gtk_vbox_new(FALSE, 4);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
-
-	label = gtk_label_new("");
-	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
-	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
-	gtk_label_set_markup(GTK_LABEL(label), "Attribute key:");
-
-	kentry = gtk_entry_new();
-	gtk_entry_set_activates_default(GTK_ENTRY(kentry), TRUE);
-	gtk_box_pack_start(GTK_BOX(vbox), kentry, TRUE, TRUE, 0);
-
-	label = gtk_label_new("");
-	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
-	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
-	gtk_label_set_markup(GTK_LABEL(label), "Attribute value:");
-
-	ventry = gtk_entry_new();
-	gtk_entry_set_activates_default(GTK_ENTRY(ventry), TRUE);
-	gtk_box_pack_start(GTK_BOX(vbox), ventry, TRUE, TRUE, 0);
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-	gtk_container_add(GTK_CONTAINER(content_area), vbox);
-	gtk_widget_show_all(dialog);
-
-	response = gtk_dialog_run(GTK_DIALOG(dialog));
-	if (response == GTK_RESPONSE_OK) {
-		*key = gtk_editable_get_chars(GTK_EDITABLE(kentry), 0, -1);
-		*val = gtk_editable_get_chars(GTK_EDITABLE(ventry), 0, -1);
-		gtk_widget_destroy(dialog);
-		return 1;
-	}
-
-	gtk_widget_destroy(dialog);
-	return 0;
-}
-
-
-static void do_addattr_cb(GtkWidget *tree, ghid_propedit_dialog_t *dlg)
-{
-	char *name, *value;
-
-	if (keyval_input(&name, &value)) {
-		char *path;
-		if ((name[0] == 'a') && (name[1] == '/')) {
-			path = name;
-			name = NULL;
-		}
-		else {
-			int len = strlen(name);
-			path = malloc(len+3);
-			path[0] = 'a';
-			path[1] = '/';
-			strcpy(path+2, name);
-		}
-		ghidgui->propedit_query(ghidgui->propedit_pe, "vset", path, value, 0);
-		free(path);
-		free(name);
-	}
-}
-
-static void do_apply_cb(GtkWidget *tree, ghid_propedit_dialog_t *dlg)
-{
-	GtkTreeSelection *tsel;
-	GtkTreeModel *tm;
-	GtkTreeIter iter;
-	char *prop, *val;
-	const char *typ;
-
-	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->tree));
-	if (tsel == NULL)
-		return;
-
-	gtk_tree_selection_get_selected(tsel, &tm, &iter);
-	if (iter.stamp == 0)
-		return;
-
-	gtk_tree_model_get(tm, &iter, 0, &prop, -1);
-
-	val = pcb_strdup(gtk_entry_get_text(GTK_ENTRY(dlg->entry_val)));
-
-	typ = ghidgui->propedit_query(ghidgui->propedit_pe, "type", prop, NULL, 0);
-	if (typ != NULL) {
-		if (*typ == 'c') { /* if type of the field if coords, we may need to fix missing units */
-			char *end;
-			strtod(val, &end);
-			while(isspace(*end)) end++;
-			if (*end == '\0') { /* no unit - automatically append current default */
-				int len = strlen(val);
-				char *new_val;
-				new_val = malloc(len+32);
-				strcpy(new_val, val);
-				sprintf(new_val+len, " %s", conf_core.editor.grid_unit->suffix);
-				free(val);
-				val = new_val;
-			}
-		}
-
-		if (ghidgui->propedit_query(ghidgui->propedit_pe, "vset", prop, val, 0) != NULL) {
-			/* could change values update the table - the new row is already added, remove the old */
-			gtk_list_store_remove(GTK_LIST_STORE(tm), &iter);
-			if (dlg->last_add_iter_valid) {
-				gtk_tree_selection_select_iter(tsel, &dlg->last_add_iter);
-				dlg->last_add_iter_valid = 0;
-			}
-			/* get the combo box updated */
-			list_cursor_changed_cb(dlg->tree, dlg);
-			if ((*val == '+') || (*val == '-'))
-				gtk_entry_set_text(GTK_ENTRY(dlg->entry_val), val); /* keep relative values intact for a reapply */
-		}
-		else
-			pcb_message(PCB_MSG_WARNING, "Failed to change any object - %s is possibly invalid value for %s\n", val, prop);
-	}
-	else
-		pcb_message(PCB_MSG_ERROR, "Internal error: no type for proeprty %s\n", prop);
-
-	free(val);
-	g_free(prop);
-}
-
-static GdkPixmap *pm;
-static gboolean preview_expose_event(GtkWidget *w, GdkEventExpose *event)
-{
-	gdk_draw_drawable(w->window, w->style->fg_gc[gtk_widget_get_state(w)],
-		pm,
-		event->area.x, event->area.y,
-		event->area.x, event->area.y,
-		event->area.width, event->area.height);
-	return FALSE;
-}
-
-static pcb_board_t preview_pcb;
-
-static GtkWidget *preview_init(ghid_propedit_dialog_t *dlg)
-{
-	GtkWidget *area = gtk_drawing_area_new();
-	pcb_board_t *old_pcb;
-	int n, zoom1, fx, fy;
-	pcb_coord_t cx, cy;
-
-/*
-	void *v;
-	v = pcb_poly_new_from_rectangle(PCB->Data->Layer+1,
-		PCB_MIL_TO_COORD(0), PCB_MIL_TO_COORD(0),
-		PCB_MIL_TO_COORD(1500), PCB_MIL_TO_COORD(1500),
-		pcb_flag_make(PCB_FLAG_CLEARPOLY | PCB_FLAG_FULLPOLY));
-	printf("poly2=%p -----------\n", (void *)v);
-	DrawPolygon(PCB->Data->Layer+1, v);
-	pcb_draw();
-	gtk_drawing_area_size(GTK_DRAWING_AREA(area), 300, 400);
-	return;
-*/
-
-	memset(&preview_pcb, 0, sizeof(preview_pcb));
-	preview_pcb.Data = pcb_buffer_new();
-	preview_pcb.MaxWidth = preview_pcb.MaxHeight = PCB_MIL_TO_COORD(2000);
-	pcb_colors_from_settings(&preview_pcb);
-	pcb_font_create_default(&preview_pcb);
-	preview_pcb.ViaOn = 1;
-
-	for(n = 0; n < pcb_max_copper_layer+2; n++) {
-		preview_pcb.Data->Layer[n].On = 1;
-		preview_pcb.Data->Layer[n].Color = pcb_strdup(PCB->Data->Layer[n].Color);
-		preview_pcb.Data->Layer[n].Name = pcb_strdup("preview dummy");
-	}
-
-	memcpy(&preview_pcb.LayerGroups, &PCB->LayerGroups, sizeof(PCB->LayerGroups));
-	preview_pcb.Data->LayerN = pcb_max_copper_layer;
-	preview_pcb.Data->pcb = &preview_pcb;
-
-#warning TODO: preview_pcb is never freed
-
-	pcb_via_new(preview_pcb.Data,
-							PCB_MIL_TO_COORD(1000), PCB_MIL_TO_COORD(1000),
-							PCB_MIL_TO_COORD(50), PCB_MIL_TO_COORD(10), 0, PCB_MIL_TO_COORD(20), "", pcb_no_flags());
-
-	pcb_line_new(preview_pcb.Data->Layer+0,
-		PCB_MIL_TO_COORD(1000), PCB_MIL_TO_COORD(1000),
-		PCB_MIL_TO_COORD(1000), PCB_MIL_TO_COORD(1300),
-		PCB_MIL_TO_COORD(20), PCB_MIL_TO_COORD(20), pcb_flag_make(PCB_FLAG_CLEARLINE));
-
-	pcb_arc_new(preview_pcb.Data->Layer+0,
-		PCB_MIL_TO_COORD(1000), PCB_MIL_TO_COORD(1000),
-		PCB_MIL_TO_COORD(100), PCB_MIL_TO_COORD(100),
-		0.0, 90.0,
-		PCB_MIL_TO_COORD(20), PCB_MIL_TO_COORD(20), pcb_flag_make(PCB_FLAG_CLEARLINE));
-
-		pcb_text_new(preview_pcb.Data->Layer+0, &PCB->Font,
-							PCB_MIL_TO_COORD(850), PCB_MIL_TO_COORD(1150), 0, 100, "Text", pcb_flag_make(PCB_FLAG_CLEARLINE));
-
-	{
-		pcb_polygon_t *v = pcb_poly_new_from_rectangle(preview_pcb.Data->Layer,
-			PCB_MIL_TO_COORD(10), PCB_MIL_TO_COORD(10),
-			PCB_MIL_TO_COORD(1200), PCB_MIL_TO_COORD(1200),
-			pcb_flag_make(PCB_FLAG_CLEARPOLY));
-		pcb_poly_init_clip(preview_pcb.Data, preview_pcb.Data->Layer, v);
-	}
-
-	old_pcb = PCB;
-	PCB = &preview_pcb;
-
-	zoom1 = 1;
-	cx = PCB_MIL_TO_COORD(1000+300/2*zoom1);
-	cy = PCB_MIL_TO_COORD(1000+400/2*zoom1);
-	fx = conf_core.editor.view.flip_x;
-	fy = conf_core.editor.view.flip_y;
-	conf_set(CFR_DESIGN, "editor/view/flip_x", -1, "0", POL_OVERWRITE);
-	conf_set(CFR_DESIGN, "editor/view/flip_y", -1, "0", POL_OVERWRITE);
-	pm = ghid_render_pixmap(cx, cy,
-	40000 * zoom1, 300, 400, gdk_drawable_get_depth(GDK_DRAWABLE(gport->top_window->window)));
-	conf_setf(CFR_DESIGN, "editor/view/flip_x", -1, "%d", fx, POL_OVERWRITE);
-	conf_setf(CFR_DESIGN, "editor/view/flip_y", -1, "%d", fy, POL_OVERWRITE);
-
-/*
-	{
-		GdkGC *gc = gdk_gc_new(GDK_DRAWABLE(gport->top_window->window));
-		GdkColor clr = {0, 0, 0, 0};
-		int x, y;
-		double zm = 40000 * zoom1;
-
-		gdk_gc_set_rgb_fg_color(gc, &clr);
-
-		x = (PCB_MIL_TO_COORD(1000) - cx) / zm + 0.5 + 200;
-		y = (PCB_MIL_TO_COORD(1000) - cy) / zm + 0.5 + 150;
-		gdk_draw_line(pm, gc, x, y, 0, 0);
-		gdk_draw_line(pm, gc, x+1, y+1, 1, 1);
-		gdk_draw_line(pm, gc, x-1, y-1, -1, -1);
-	}
-*/
-
-
-	PCB = old_pcb;
-
-
-	g_signal_connect(G_OBJECT(area), "expose-event", G_CALLBACK(preview_expose_event), pm);
-	return area;
-}
-
-/*static void sort_by_name(GtkTreeModel *liststore)
-{
-	GtkTreeSortable *sortable = GTK_TREE_SORTABLE(liststore);
-	gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING);
-}*/
-
-static gint sort_name_cmp(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
-{
-	gint sortcol = GPOINTER_TO_INT(userdata);
-	gint ret = 0;
-  gchar *name1, *name2;
-
-	if (sortcol != 0)
-		return 0;
-
-	gtk_tree_model_get(model, a, 0, &name1, -1);
-	gtk_tree_model_get(model, b, 0, &name2, -1);
-
-	if ((name1 == NULL) && (name2 == NULL))
-		return 0;
-
-	if (name1 == NULL)
-		ret = -1;
-	else if (name2 == NULL)
-		ret = 1;
-	else if ((*name1 == 'a') && (*name2 == 'p')) /* force attributes to the bottom */
-		return 1;
-	else if ((*name1 == 'p') && (*name2 == 'a'))
-		return -1;
-	else
-		ret = strcmp(name1, name2);
-
-
-	g_free(name1);
-	g_free(name2);
-
-	return ret;
-}
-
-static void make_sortable(GtkTreeModel *liststore)
-{
-	GtkTreeSortable *sortable;
-
-	sortable = GTK_TREE_SORTABLE(liststore);
-	gtk_tree_sortable_set_sort_func(sortable, 0, sort_name_cmp, GINT_TO_POINTER(0), NULL);
-
-	gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING);
-}
-
-GtkWidget *ghid_propedit_dialog_create(ghid_propedit_dialog_t *dlg)
-{
-	GtkWidget *window, *vbox_tree, *vbox_edit, *hbox_win, *label, *hbx, *dummy, *box_val_edit, *preview;
-	GtkCellRenderer *renderer ;
-	GtkWidget *content_area, *top_window = gport->top_window;
-
-	dlg->last_add_iter_valid = 0;
-
-	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	window = gtk_dialog_new_with_buttons(_("Edit Properties"),
-																			 GTK_WINDOW(top_window),
-																			 GTK_DIALOG_DESTROY_WITH_PARENT,
-																			 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(window));
-
-	hbox_win = gtk_hbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(content_area), hbox_win);
-
-
-	vbox_tree = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox_win), vbox_tree, TRUE, TRUE, 4);
-	vbox_edit = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox_win), vbox_edit, TRUE, TRUE, 4);
-
-/***** LEFT *****/
-
-	label = gtk_label_new("Properties");
-	gtk_box_pack_start(GTK_BOX(vbox_tree), label, FALSE, FALSE, 4);
-
-	dlg->tree = gtk_tree_view_new();
-	gtk_box_pack_start(GTK_BOX(vbox_tree), dlg->tree, FALSE, TRUE, 4);
-
-	GType ty[5];
-
-	int n;
-	for(n = 0; n < 5; n++)
-		ty[n] = G_TYPE_STRING;
-	dlg->props = gtk_list_store_newv(5, ty);
-	make_sortable((GtkTreeModel *)dlg->props);
-	gtk_tree_view_set_model(GTK_TREE_VIEW(dlg->tree), GTK_TREE_MODEL(dlg->props));
-
-	hdr_add(dlg, "property", 0);
-	hdr_add(dlg, "common", 1);
-	hdr_add(dlg, "min", 2);
-	hdr_add(dlg, "max", 3);
-	hdr_add(dlg, "avg", 4);
-
-	/* dummy box to eat up vertical space */
-	hbx = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox_tree), hbx, TRUE, TRUE, 4);
-
-	/* list manipulation */
-	hbx = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox_tree), hbx, FALSE, TRUE, 4);
-
-	dlg->remove = gtk_button_new_with_label("Remove attribute");
-	gtk_box_pack_start(GTK_BOX(hbx), dlg->remove, FALSE, TRUE, 4);
-	g_signal_connect(G_OBJECT(dlg->remove), "clicked", G_CALLBACK(do_remove_cb), dlg);
-
-	dlg->addattr = gtk_button_new_with_label("Add attribute");
-	gtk_box_pack_start(GTK_BOX(hbx), dlg->addattr, FALSE, TRUE, 4);
-	g_signal_connect(G_OBJECT(dlg->addattr), "clicked", G_CALLBACK(do_addattr_cb), dlg);
-
-
-/***** RIGHT *****/
-/* preview */
-	preview = preview_init(dlg);
-	gtk_box_pack_start(GTK_BOX(vbox_edit), preview, TRUE, TRUE, 4);
-
-	label = gtk_label_new("Change property of all objects");
-	gtk_box_pack_start(GTK_BOX(vbox_edit), label, FALSE, TRUE, 4);
-
-	g_signal_connect(G_OBJECT(dlg->tree), "cursor-changed", G_CALLBACK(list_cursor_changed_cb), dlg);
-
-	/* value edit */
-	renderer = gtk_cell_renderer_text_new();
-
-	dlg->stock_val = 0;
-	dlg->vals = gtk_list_store_new(1, G_TYPE_STRING);
-	box_val_edit = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox_edit), box_val_edit, FALSE, TRUE, 4);
-
-	/* combo */
-	dlg->val_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(dlg->vals));
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dlg->val_box), renderer, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dlg->val_box), renderer, "text", 0, NULL);
-	gtk_box_pack_start(GTK_BOX(box_val_edit), dlg->val_box, FALSE, TRUE, 0);
-
-	g_signal_connect(G_OBJECT(dlg->val_box), "changed", G_CALLBACK(val_combo_changed_cb), dlg);
-
-	/* entry */
-	dlg->entry_val = gtk_entry_new();
-	gtk_box_pack_start(GTK_BOX(box_val_edit), dlg->entry_val, TRUE, TRUE, 0);
-
-	g_signal_connect(G_OBJECT(dlg->entry_val), "changed", G_CALLBACK(val_entry_changed_cb), dlg);
-
-	/* Apply button */
-	hbx = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox_edit), hbx, FALSE, TRUE, 4);
-
-	dummy = gtk_vbox_new(FALSE, 0); /* dummy box to eat up free space on the left */
-	gtk_box_pack_start(GTK_BOX(hbx), dummy, TRUE, TRUE, 4);
-
-	dlg->apply = gtk_button_new_with_label("Apply");
-	gtk_box_pack_start(GTK_BOX(hbx), dlg->apply, FALSE, TRUE, 4);
-	g_signal_connect(G_OBJECT(dlg->apply), "clicked", G_CALLBACK(do_apply_cb), dlg);
-
-
-	gtk_widget_show_all(window);
-
-	return window;
-}
diff --git a/src_plugins/hid_gtk/ghid-propedit.h b/src_plugins/hid_gtk/ghid-propedit.h
deleted file mode 100644
index 1128bbd..0000000
--- a/src_plugins/hid_gtk/ghid-propedit.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  pcb-rnd, interactive printed circuit board design
- *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* object property edit dialog */
-
-typedef struct {
-	/* property list */
-	GtkWidget *tree;        /* property list widget */
-	GtkListStore *props;    /* list model of properties */
-
-	/* value entry */
-	GtkWidget *entry_val;   /* text entry */
-	GtkWidget *val_box;     /* combo box */
-	GtkListStore *vals;     /* model of the combo box */
-	int stock_val;          /* 1 if the value in the entry box is being edited from the combo */
-	GtkTreeIter last_add_iter; /* the iterator of the last added row (sometimes it needs to be selected) */
-	int last_add_iter_valid;
-
-	/* buttons */
-	GtkWidget *apply, *remove, *addattr;
-} ghid_propedit_dialog_t;
-
-GtkWidget *ghid_propedit_dialog_create(ghid_propedit_dialog_t *dlg);
-
-void ghid_propedit_prop_add(ghid_propedit_dialog_t *dlg, const char *name, const char *common, const char *min, const char *max, const char *avg);
diff --git a/src_plugins/hid_gtk/ghid-route-style-selector.c b/src_plugins/hid_gtk/ghid-route-style-selector.c
deleted file mode 100644
index 3b9db23..0000000
--- a/src_plugins/hid_gtk/ghid-route-style-selector.c
+++ /dev/null
@@ -1,868 +0,0 @@
-/*! \file <gtk-pcb-route-style-selector.c>
- *  \brief Implementation of GHidRouteStyleSelector widget
- *  \par Description
- *  Please write description here.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-
-#include "config.h"
-#include "conf_core.h"
-#include "gtkhid.h"
-#include "gui.h"
-#include "pcb-printf.h"
-#include "route_style.h"
-#include "compat_nls.h"
-
-#include "ghid-route-style-selector.h"
-
-/* Forward dec'ls */
-struct _route_style;
-struct _route_style *ghid_route_style_selector_real_add_route_style(GHidRouteStyleSelector *, pcb_route_style_t *, int);
-static void ghid_route_style_selector_finalize(GObject * object);
-static void add_new_iter(GHidRouteStyleSelector * rss);
-
-/*! \brief Global action creation counter */
-static gint action_count;
-
-/*! \brief Signals exposed by the widget */
-enum {
-	SELECT_STYLE_SIGNAL,
-	STYLE_EDITED_SIGNAL,
-	LAST_SIGNAL
-};
-
-/*! \brief Columns used for internal data store */
-enum {
-	TEXT_COL,
-	DATA_COL,
-	N_COLS
-};
-
-static GtkVBox *ghid_route_style_selector_parent_class;
-static guint ghid_route_style_selector_signals[LAST_SIGNAL] = { 0 };
-
-struct _GHidRouteStyleSelector {
-	GtkVBox parent;
-
-	GSList *button_radio_group;
-	GSList *action_radio_group;
-	GtkWidget *edit_button;
-
-	GtkActionGroup *action_group;
-	GtkAccelGroup *accel_group;
-
-	int hidden_button; /* whether the hidden button is created */
-	int selected; /* index of the currently selected route style */
-
-	GtkListStore *model;
-	struct _route_style *active_style;
-
-	GtkTreeIter new_iter;     /* iter for the <new> item */
-
-};
-
-struct _GHidRouteStyleSelectorClass {
-	GtkVBoxClass parent_class;
-
-	void (*select_style) (GHidRouteStyleSelector *, pcb_route_style_t *);
-	void (*style_edited) (GHidRouteStyleSelector *, gboolean);
-};
-
-struct _route_style {
-	GtkRadioAction *action;
-	GtkWidget *button;
-	GtkWidget *menu_item;
-	GtkTreeRowReference *rref;
-	pcb_route_style_t *rst;
-	gulong sig_id;
-	int hidden;
-};
-
-/* SIGNAL HANDLERS */
-/*! \brief Callback for user selection of a route style */
-static void radio_select_cb(GtkToggleAction * action, GHidRouteStyleSelector * rss)
-{
-	rss->active_style = g_object_get_data(G_OBJECT(action), "route-style");
-	if (gtk_toggle_action_get_active(action))
-		g_signal_emit(rss, ghid_route_style_selector_signals[SELECT_STYLE_SIGNAL], 0, rss->active_style->rst);
-}
-
-/* EDIT DIALOG */
-struct _dialog {
-	GHidRouteStyleSelector *rss;
-	GtkWidget *name_entry;
-	GtkWidget *line_entry;
-	GtkWidget *via_hole_entry;
-	GtkWidget *via_size_entry;
-	GtkWidget *clearance_entry;
-
-	GtkWidget *select_box;
-
-	GtkWidget *attr_table;
-	GtkListStore *attr_model;
-
-	int inhibit_style_change; /* when 1, do not do anything when style changes */
-	int attr_editing; /* set to 1 when an attribute key or value text is being edited */
-};
-
-/* Rebuild the gtk table for attribute list from style */
-static void update_attrib(struct _dialog *dialog, struct _route_style *style)
-{
-	GtkTreeIter iter;
-	int i;
-
-	gtk_list_store_clear(dialog->attr_model);
-
-	for(i = 0; i < style->rst->attr.Number; i++) {
-		gtk_list_store_append(dialog->attr_model, &iter);
-		gtk_list_store_set(dialog->attr_model, &iter, 0, style->rst->attr.List[i].name, -1);
-		gtk_list_store_set(dialog->attr_model, &iter, 1, style->rst->attr.List[i].value, -1);
-	}
-
-	gtk_list_store_append(dialog->attr_model, &iter);
-	gtk_list_store_set(dialog->attr_model, &iter, 0, "<new>", -1);
-	gtk_list_store_set(dialog->attr_model, &iter, 1, "<new>", -1);
-}
-
-/*! \brief Callback for dialog box's combobox being changed
- *  \par Function Description
- *  When a different layer is selected, this function loads
- *  that layer's data into the dialog. Alternately, if the
- *  "New layer" option is selected, this loads a new name
- *  but no other data.
- *
- *  \param [in] combo   The combobox
- *  \param [in] dialog  The rest of the widgets to be updated
- */
-static void dialog_style_changed_cb(GtkComboBox * combo, struct _dialog *dialog)
-{
-	struct _route_style *style;
-	GtkTreeIter iter;
-
-	if (dialog->inhibit_style_change)
-		return;
-
-	gtk_combo_box_get_active_iter(combo, &iter);
-	gtk_tree_model_get(GTK_TREE_MODEL(dialog->rss->model), &iter, DATA_COL, &style, -1);
-
-	if (style == NULL) {
-		gtk_entry_set_text(GTK_ENTRY(dialog->name_entry), _("New Style"));
-		dialog->rss->selected = -1;
-		return;
-	}
-
-	gtk_entry_set_text(GTK_ENTRY(dialog->name_entry), style->rst->name);
-	ghid_coord_entry_set_value(GHID_COORD_ENTRY(dialog->line_entry), style->rst->Thick);
-	ghid_coord_entry_set_value(GHID_COORD_ENTRY(dialog->via_hole_entry), style->rst->Hole);
-	ghid_coord_entry_set_value(GHID_COORD_ENTRY(dialog->via_size_entry), style->rst->Diameter);
-	ghid_coord_entry_set_value(GHID_COORD_ENTRY(dialog->clearance_entry), style->rst->Clearance);
-
-	if (style->hidden)
-		dialog->rss->selected = -1;
-	else
-		dialog->rss->selected = style->rst - PCB->RouteStyle.array;
-
-	update_attrib(dialog, style);
-}
-
-#warning TODO: this should be in core
-static void copy_route_style(int idx)
-{
-	pcb_route_style_t *drst;
-
-	if ((idx < 0) || (idx >= vtroutestyle_len(&PCB->RouteStyle)))
-		return;
-	drst = PCB->RouteStyle.array + idx;
-	pcb_custom_route_style.Thick     = drst->Thick;
-	pcb_custom_route_style.Clearance = drst->Clearance;
-	pcb_custom_route_style.Diameter  = drst->Diameter;
-	pcb_custom_route_style.Hole      = drst->Hole;
-}
-
-/*  Callback for Delete route style button */
-static void delete_button_cb(GtkButton *button, struct _dialog *dialog)
-{
-	if (dialog->rss->selected < 0)
-		return;
-
-	dialog->inhibit_style_change = 1;
-	ghid_route_style_selector_empty(GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector));
-
-#warning TODO: some of these should be in core
-	copy_route_style(dialog->rss->selected);
-
-	vtroutestyle_remove(&PCB->RouteStyle, dialog->rss->selected, 1);
-	dialog->rss->active_style = NULL;
-	make_route_style_buttons(GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector));
-	pcb_trace("Style: %d deleted\n", dialog->rss->selected);
-	pcb_board_set_changed_flag(pcb_true);
-	ghid_window_set_name_label(PCB->Name);
-	add_new_iter(dialog->rss);
-	dialog->inhibit_style_change = 0;
-	ghid_route_style_selector_select_style(dialog->rss, &pcb_custom_route_style);
-	gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->select_box), 0);
-}
-
-/***** attr table *****/
-
-static int get_sel(struct _dialog *dlg)
-{
-	GtkTreeIter iter;
-	GtkTreeSelection *tsel;
-	GtkTreeModel *tm;
-	GtkTreePath *path;
-	int *i;
-
-	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->attr_table));
-	if (tsel == NULL)
-		return -1;
-
-	gtk_tree_selection_get_selected(tsel, &tm, &iter);
-	if (iter.stamp == 0)
-		return -1;
-
-	path = gtk_tree_model_get_path(tm, &iter);
-	if (path != NULL) {
-		i = gtk_tree_path_get_indices(path);
-		if (i != NULL) {
-/*			gtk_tree_model_get(GTK_TREE_MODEL(dlg->attr_model), &iter, 0, nkey, 1, nval, -1);*/
-			return i[0];
-		}
-	}
-	return -1;
-}
-
-
-static void attr_edited(int col, GtkCellRendererText *cell, gchar *path, gchar *new_text, struct _dialog *dlg)
-{
-	GtkTreeIter iter;
-	struct _route_style *style;
-	int idx = get_sel(dlg);
-
-	dlg->attr_editing = 0;
-
-	gtk_combo_box_get_active_iter(GTK_COMBO_BOX(dlg->select_box), &iter);
-	gtk_tree_model_get(GTK_TREE_MODEL(dlg->rss->model), &iter, DATA_COL, &style, -1);
-
-	if (style == NULL)
-		return;
-
-	if (idx >= style->rst->attr.Number) { /* add new */
-		if (col == 0)
-			pcb_attribute_put(&style->rst->attr, new_text, "n/a", 0);
-		else
-			pcb_attribute_put(&style->rst->attr, "n/a", new_text, 0);
-	}
-	else { /* overwrite existing */
-		char **dest;
-		if (col == 0)
-			dest = &style->rst->attr.List[idx].name;
-		else
-			dest = &style->rst->attr.List[idx].value;
-		if (*dest != NULL)
-			free(*dest);
-		*dest = pcb_strdup(new_text);
-	}
-
-	/* rebuild the table to keep it in sync - expensive, but it happens rarely */
-	update_attrib(dlg, style);
-}
-
-static void attr_edited_key_cb(GtkCellRendererText *cell, gchar *path, gchar *new_text, struct _dialog *dlg)
-{
-	attr_edited(0, cell, path, new_text, dlg);
-}
-
-static void attr_edited_val_cb(GtkCellRendererText *cell, gchar *path, gchar *new_text, struct _dialog *dlg)
-{
-	attr_edited(1, cell, path, new_text, dlg);
-}
-
-
-static void attr_edit_started_cb(GtkCellRendererText *cell, GtkCellEditable *e,gchar *path, struct _dialog *dlg)
-{
-	dlg->attr_editing = 1;
-}
-
-static void attr_edit_canceled_cb(GtkCellRendererText *cell, struct _dialog *dlg)
-{
-	dlg->attr_editing = 0;
-}
-
-static gboolean attr_key_release_cb(GtkWidget *widget, GdkEventKey *event, struct _dialog *dlg)
-{
-	unsigned short int kv = event->keyval;
-
-	if (dlg->attr_editing)
-		return FALSE;
-
-	switch(kv) {
-#ifdef GDK_KEY_KP_Delete
-		case GDK_KEY_KP_Delete:
-#endif
-#ifdef GDK_KEY_Delete
-		case GDK_KEY_Delete:
-#endif
-		case 'd': 
-			{
-				int idx = get_sel(dlg);
-				GtkTreeIter iter;
-				struct _route_style *style;
-				gtk_combo_box_get_active_iter(GTK_COMBO_BOX(dlg->select_box), &iter);
-				gtk_tree_model_get(GTK_TREE_MODEL(dlg->rss->model), &iter, DATA_COL, &style, -1);
-				if (style == NULL)
-					return FALSE;
-				if ((idx >= 0) && (idx < style->rst->attr.Number)) {
-					pcb_attribute_remove_idx(&style->rst->attr, idx);
-					update_attrib(dlg, style);
-				}
-			}
-			break;
-	}
-	return FALSE;
-}
-
-/**** dialog creation ****/
-
-/* \brief Helper for edit_button_cb */
-static void _table_attach_(GtkWidget * table, gint row, const gchar *label, GtkWidget *entry)
-{
-	GtkWidget *label_w = gtk_label_new(label);
-	gtk_misc_set_alignment(GTK_MISC(label_w), 1.0, 0.5);
-	gtk_table_attach(GTK_TABLE(table), label_w, 0, 1, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-}
-
-/* \brief Helper for edit_button_cb */
-static void _table_attach(GtkWidget * table, gint row, const gchar * label, GtkWidget ** entry, pcb_coord_t min, pcb_coord_t max)
-{
-	*entry = ghid_coord_entry_new(min, max, 0, conf_core.editor.grid_unit, CE_SMALL);
-	_table_attach_(table, row, label, *entry);
-}
-
-static void add_new_iter(GHidRouteStyleSelector * rss)
-{
-	/* Add "new style" option to list */
-	gtk_list_store_append(rss->model, &rss->new_iter);
-	gtk_list_store_set(rss->model, &rss->new_iter, TEXT_COL, _("<New>"), DATA_COL, NULL, -1);
-}
-
-/* \brief Builds and runs the "edit route styles" dialog */
-void ghid_route_style_selector_edit_dialog(GHidRouteStyleSelector * rss)
-{
-	GtkTreePath *path;
-	GtkTreeIter iter;
-	struct _dialog dialog_data;
-	GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
-	GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(rss));
-	GtkWidget *dialog;
-	GtkWidget *content_area;
-	GtkWidget *vbox, *hbox, *sub_vbox, *table;
-	GtkWidget *label, *select_box, *check_box;
-	GtkWidget *button;
-	const char *new_name;
-
-	memset(&dialog_data, 0, sizeof(dialog_data)); /* make sure all flags are cleared */
-
-	/* Build dialog */
-	dialog = gtk_dialog_new_with_buttons(_("Edit Route Styles"),
-																			 GTK_WINDOW(window),
-																			 GTK_DIALOG_DESTROY_WITH_PARENT,
-																			 GTK_STOCK_CANCEL, GTK_RESPONSE_NONE, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-	label = gtk_label_new(_("Edit Style:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-
-	select_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(rss->model));
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(select_box), renderer, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(select_box), renderer, "text", TEXT_COL, NULL);
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-
-	hbox = gtk_hbox_new(FALSE, 4);
-	gtk_box_pack_start(GTK_BOX(content_area), hbox, TRUE, TRUE, 4);
-	vbox = gtk_vbox_new(FALSE, 4);
-	gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 4);
-
-	hbox = gtk_hbox_new(FALSE, 4);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 4);
-	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), select_box, TRUE, TRUE, 0);
-
-	sub_vbox = ghid_category_vbox(vbox, _("Route Style Data"), 4, 2, TRUE, TRUE);
-	table = gtk_table_new(5, 2, FALSE);
-	gtk_box_pack_start(GTK_BOX(sub_vbox), table, TRUE, TRUE, 4);
-	label = gtk_label_new(_("Name:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-	dialog_data.name_entry = gtk_entry_new();
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-	gtk_table_attach(GTK_TABLE(table), dialog_data.name_entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-
-	_table_attach(table, 1, _("Line width:"), &dialog_data.line_entry, PCB_MIN_LINESIZE, PCB_MAX_LINESIZE);
-	_table_attach(table, 2, _("Via hole size:"),
-								&dialog_data.via_hole_entry, PCB_MIN_PINORVIAHOLE, PCB_MAX_PINORVIASIZE - PCB_MIN_PINORVIACOPPER);
-	_table_attach(table, 3, _("Via ring size:"),
-								&dialog_data.via_size_entry, PCB_MIN_PINORVIAHOLE + PCB_MIN_PINORVIACOPPER, PCB_MAX_PINORVIASIZE);
-	_table_attach(table, 4, _("Clearance:"), &dialog_data.clearance_entry, PCB_MIN_LINESIZE, PCB_MAX_LINESIZE);
-
-	_table_attach_(table, 5, "", gtk_label_new(""));
-
-	/* create attrib table */
-	{
-		GType *ty;
-		GtkCellRenderer *renderer;
-
-		dialog_data.attr_table = gtk_tree_view_new();
-
-		ty = malloc(sizeof(GType) * 2);
-		ty[0] = G_TYPE_STRING;
-		ty[1] = G_TYPE_STRING;
-		dialog_data.attr_model = gtk_list_store_newv(2, ty);
-		free(ty);
-
-		renderer = gtk_cell_renderer_text_new();
-		g_object_set(renderer, "editable", TRUE, NULL);
-		g_signal_connect(renderer, "edited", G_CALLBACK(attr_edited_key_cb), &dialog_data);
-		g_signal_connect(renderer, "editing-started", G_CALLBACK(attr_edit_started_cb), &dialog_data);
-		g_signal_connect(renderer, "editing-canceled", G_CALLBACK(attr_edit_canceled_cb), &dialog_data);
-		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dialog_data.attr_table), -1, "key", renderer, "text", 0, NULL);
-
-
-		renderer = gtk_cell_renderer_text_new();
-		g_object_set(renderer, "editable", TRUE, NULL);
-		g_signal_connect(renderer, "edited", G_CALLBACK(attr_edited_val_cb), &dialog_data);
-		g_signal_connect(renderer, "editing-started", G_CALLBACK(attr_edit_started_cb), &dialog_data);
-		g_signal_connect(renderer, "editing-canceled", G_CALLBACK(attr_edit_canceled_cb), &dialog_data);
-		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dialog_data.attr_table), -1, "value", renderer, "text", 1, NULL);
-
-		gtk_tree_view_set_model(GTK_TREE_VIEW(dialog_data.attr_table), GTK_TREE_MODEL(dialog_data.attr_model));
-		g_signal_connect(G_OBJECT(dialog_data.attr_table), "key-release-event", G_CALLBACK(attr_key_release_cb), &dialog_data);
-
-	}
-	_table_attach_(table, 6, _("Attributes:"), dialog_data.attr_table);
-
-
-	/* create delete button */
-	button = gtk_button_new_with_label (_("Delete Style"));
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(delete_button_cb), &dialog_data);
-	gtk_box_pack_start(GTK_BOX(vbox), button , TRUE, FALSE, 0);
-
-	sub_vbox = ghid_category_vbox(vbox, _("Set as Default"), 4, 2, TRUE, TRUE);
-	check_box = gtk_check_button_new_with_label(_("Save route style settings as default"));
-	gtk_box_pack_start(GTK_BOX(sub_vbox), check_box, TRUE, TRUE, 0);
-
-	add_new_iter(rss);
-
-	/* Display dialog */
-	dialog_data.rss = rss;
-	dialog_data.select_box = select_box;
-	if (rss->active_style != NULL) {
-		path = gtk_tree_row_reference_get_path(rss->active_style->rref);
-		gtk_tree_model_get_iter(GTK_TREE_MODEL(rss->model), &iter, path);
-		g_signal_connect(G_OBJECT(select_box), "changed", G_CALLBACK(dialog_style_changed_cb), &dialog_data);
-		gtk_combo_box_set_active_iter(GTK_COMBO_BOX(select_box), &iter);
-	}
-	gtk_widget_show_all(dialog);
-	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
-		int changed = 0;
-		pcb_route_style_t *rst;
-		struct _route_style *style;
-		gboolean save;
-		if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(select_box), &iter))
-			goto cancel;
-		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, DATA_COL, &style, -1);
-		if (style == NULL) {
-			int n = vtroutestyle_len(&PCB->RouteStyle);
-			rst = vtroutestyle_get(&PCB->RouteStyle, n, 1);
-		}
-		else {
-			rst = style->rst;
-			*rst->name = '\0';
-		}
-
-		new_name = gtk_entry_get_text(GTK_ENTRY(dialog_data.name_entry));
-
-		while(isspace(*new_name)) new_name++;
-		if (strcmp(rst->name, new_name) != 0) {
-			strncpy(rst->name, new_name, sizeof(rst->name)-1);
-			rst->name[sizeof(rst->name)-1] = '0';
-			changed = 1;
-		}
-
-/* Modify the route style only if there's significant difference (beyond rouding errors) */
-#define rst_modify(changed, dst, src) \
-	do { \
-		pcb_coord_t __tmp__ = src; \
-		if (abs(dst - __tmp__) > 10) { \
-			changed = 1; \
-			dst = __tmp__; \
-		} \
-	} while(0)
-		rst_modify(changed, rst->Thick, ghid_coord_entry_get_value(GHID_COORD_ENTRY(dialog_data.line_entry)));
-		rst_modify(changed, rst->Hole, ghid_coord_entry_get_value(GHID_COORD_ENTRY(dialog_data.via_hole_entry)));
-		rst_modify(changed, rst->Diameter, ghid_coord_entry_get_value(GHID_COORD_ENTRY(dialog_data.via_size_entry)));
-		rst_modify(changed, rst->Clearance, ghid_coord_entry_get_value(GHID_COORD_ENTRY(dialog_data.clearance_entry)));
-#undef rst_modify
-		save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_box));
-		if (style == NULL)
-			style = ghid_route_style_selector_real_add_route_style(rss, rst, 0);
-		else {
-			gtk_action_set_label(GTK_ACTION(style->action), rst->name);
-			gtk_list_store_set(rss->model, &iter, TEXT_COL, rst->name, -1);
-		}
-
-		/* Cleanup */
-		gtk_widget_destroy(dialog);
-		gtk_list_store_remove(rss->model, &rss->new_iter);
-		/* Emit change signals */
-		ghid_route_style_selector_select_style(rss, rst);
-		g_signal_emit(rss, ghid_route_style_selector_signals[STYLE_EDITED_SIGNAL], 0, save);
-
-		if (changed) {
-			pcb_board_set_changed_flag(pcb_true);
-			ghid_window_set_name_label(PCB->Name);
-		}
-	}
-	else {
-		cancel:;
-		gtk_widget_destroy(dialog);
-		gtk_list_store_remove(rss->model, &rss->new_iter);
-	}
-}
-
-/* end EDIT DIALOG */
-
-static void edit_button_cb(GtkButton * btn, GHidRouteStyleSelector * rss)
-{
-	ghid_route_style_selector_edit_dialog(rss);
-}
-
-/* CONSTRUCTOR */
-static void ghid_route_style_selector_init(GHidRouteStyleSelector * rss)
-{
-}
-
-static void ghid_route_style_selector_class_init(GHidRouteStyleSelectorClass * klass)
-{
-	GObjectClass *object_class = (GObjectClass *) klass;
-
-	ghid_route_style_selector_parent_class = g_type_class_peek_parent(klass);
-
-	ghid_route_style_selector_signals[SELECT_STYLE_SIGNAL] =
-		g_signal_new("select-style",
-								 G_TYPE_FROM_CLASS(klass),
-								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-								 G_STRUCT_OFFSET(GHidRouteStyleSelectorClass, select_style),
-								 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
-	ghid_route_style_selector_signals[STYLE_EDITED_SIGNAL] =
-		g_signal_new("style-edited",
-								 G_TYPE_FROM_CLASS(klass),
-								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-								 G_STRUCT_OFFSET(GHidRouteStyleSelectorClass, style_edited),
-								 NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
-	object_class->finalize = ghid_route_style_selector_finalize;
-}
-
-/*! \brief Clean up object before garbage collection
- */
-static void ghid_route_style_selector_finalize(GObject * object)
-{
-	GHidRouteStyleSelector *rss = (GHidRouteStyleSelector *) object;
-
-	ghid_route_style_selector_empty(rss);
-
-	g_object_unref(rss->accel_group);
-	g_object_unref(rss->action_group);
-
-	G_OBJECT_CLASS(ghid_route_style_selector_parent_class)->finalize(object);
-}
-
-/* PUBLIC FUNCTIONS */
-GType ghid_route_style_selector_get_type(void)
-{
-	static GType rss_type = 0;
-
-	if (!rss_type) {
-		const GTypeInfo rss_info = {
-			sizeof(GHidRouteStyleSelectorClass),
-			NULL,											/* base_init */
-			NULL,											/* base_finalize */
-			(GClassInitFunc) ghid_route_style_selector_class_init,
-			NULL,											/* class_finalize */
-			NULL,											/* class_data */
-			sizeof(GHidRouteStyleSelector),
-			0,												/* n_preallocs */
-			(GInstanceInitFunc) ghid_route_style_selector_init,
-		};
-
-		rss_type = g_type_register_static(GTK_TYPE_VBOX, "GHidRouteStyleSelector", &rss_info, 0);
-	}
-
-	return rss_type;
-}
-
-/*! \brief Create a new GHidRouteStyleSelector
- *
- *  \return a freshly-allocated GHidRouteStyleSelector.
- */
-GtkWidget *ghid_route_style_selector_new()
-{
-	GHidRouteStyleSelector *rss = g_object_new(GHID_ROUTE_STYLE_SELECTOR_TYPE, NULL);
-
-	rss->active_style = NULL;
-	rss->action_radio_group = NULL;
-	rss->button_radio_group = NULL;
-	rss->model = gtk_list_store_new(N_COLS, G_TYPE_STRING, G_TYPE_POINTER);
-
-	rss->accel_group = gtk_accel_group_new();
-	rss->action_group = gtk_action_group_new("RouteStyleSelector");
-
-	/* Create edit button */
-	rss->edit_button = gtk_button_new_with_label(_("Route Styles"));
-	g_signal_connect(G_OBJECT(rss->edit_button), "clicked", G_CALLBACK(edit_button_cb), rss);
-	gtk_box_pack_start(GTK_BOX(rss), rss->edit_button, FALSE, FALSE, 0);
-
-	return GTK_WIDGET(rss);
-}
-
-/*! \brief Create a new GHidRouteStyleSelector 
- *
- *  \param [in] rss     The selector to be acted on
- *  \param [in] data    PCB's route style object that will be edited
- */
-struct _route_style *ghid_route_style_selector_real_add_route_style(GHidRouteStyleSelector * rss,
-																																		pcb_route_style_t * data, int hide)
-{
-	GtkTreeIter iter;
-	GtkTreePath *path;
-	gchar *action_name = g_strdup_printf("RouteStyle%d", action_count);
-	struct _route_style *new_style = g_malloc(sizeof(*new_style));
-
-	/* Key the route style data with the pcb_route_style_t it controls */
-	new_style->hidden = hide;
-	new_style->rst = data;
-	new_style->action = gtk_radio_action_new(action_name, data->name, NULL, NULL, action_count);
-	gtk_radio_action_set_group(new_style->action, rss->action_radio_group);
-	rss->action_radio_group = gtk_radio_action_get_group(new_style->action);
-	new_style->button = gtk_radio_button_new(rss->button_radio_group);
-	rss->button_radio_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(new_style->button));
-	gtk_activatable_set_related_action(GTK_ACTIVATABLE(new_style->button), GTK_ACTION(new_style->action));
-
-	gtk_list_store_append(rss->model, &iter);
-	gtk_list_store_set(rss->model, &iter, TEXT_COL, data->name, DATA_COL, new_style, -1);
-	path = gtk_tree_model_get_path(GTK_TREE_MODEL(rss->model), &iter);
-	new_style->rref = gtk_tree_row_reference_new(GTK_TREE_MODEL(rss->model), path);
-	gtk_tree_path_free(path);
-
-	/* Setup accelerator */
-	if (action_count < 12) {
-		gchar *accel = g_strdup_printf("<Ctrl>F%d", action_count + 1);
-		gtk_action_set_accel_group(GTK_ACTION(new_style->action), rss->accel_group);
-		gtk_action_group_add_action_with_accel(rss->action_group, GTK_ACTION(new_style->action), accel);
-		g_free(accel);
-	}
-
-	/* Hookup and install radio button */
-	g_object_set_data(G_OBJECT(new_style->action), "route-style", new_style);
-	new_style->sig_id = g_signal_connect(G_OBJECT(new_style->action), "activate", G_CALLBACK(radio_select_cb), rss);
-	gtk_box_pack_start(GTK_BOX(rss), new_style->button, FALSE, FALSE, 0);
-
-	g_free(action_name);
-	++action_count;
-
-	if (hide)
-		gtk_widget_hide(new_style->button);
-
-	return new_style;
-}
-
-/*! \brief Adds a route style to a GHidRouteStyleSelector
- *  \par Function Description
- *  Adds a new route style to be managed by this selector. Note
- *  that the route style object passed to this function will be
- *  updated directly.
- *
- *  \param [in] rss     The selector to be acted on
- *  \param [in] data    PCB's route style object describing the style
- */
-void ghid_route_style_selector_add_route_style(GHidRouteStyleSelector * rss, pcb_route_style_t * data)
-{
-	if (!rss->hidden_button) {
-		if (*pcb_custom_route_style.name == '\0') {
-			memset(&pcb_custom_route_style, 0, sizeof(pcb_custom_route_style));
-			strcpy(pcb_custom_route_style.name, "<custom>");
-			copy_route_style(0);
-		}
-		ghid_route_style_selector_real_add_route_style(rss, &pcb_custom_route_style, 1);
-		rss->hidden_button = 1;
-	}
-	if (data != NULL)
-		ghid_route_style_selector_real_add_route_style(rss, data, 0);
-}
-
-
-/*! \brief Install the "Route Style" menu items
- *  \par Function Description
- *  Takes a menu shell and installs menu items for route style selection in
- *  the shell, at the given position. Note that we aren't really guaranteed
- *  the ordering of these items, since our internal data structure is a hash
- *  table. This shouldn't be a problem.
- *
- *  \param [in] rss     The selector to be acted on
- *  \param [in] shell   The menu to install the items in
- *  \param [in] pos     The position in the menu to install items
- *
- *  \return the number of items installed
- */
-gint ghid_route_style_selector_install_items(GHidRouteStyleSelector * rss, GtkMenuShell * shell, gint pos)
-{
-	gint n = 0;
-	GtkTreeIter iter;
-
-	if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter))
-		return 0;
-	do {
-		GtkAction *action;
-		struct _route_style *style;
-
-		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, DATA_COL, &style, -1);
-		if (style->hidden)
-			continue;
-		action = GTK_ACTION(style->action);
-		style->menu_item = gtk_action_create_menu_item(action);
-		gtk_menu_shell_insert(shell, style->menu_item, pos + n);
-		++n;
-	}
-	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(rss->model), &iter));
-
-	return n;
-}
-
-/*! \brief Selects a route style and emits a select-style signal
- *
- *  \param [in] rss  The selector to be acted on
- *  \param [in] rst  The style to select
- *
- *  \return TRUE if a style was selected, FALSE otherwise
- */
-gboolean ghid_route_style_selector_select_style(GHidRouteStyleSelector * rss, pcb_route_style_t * rst)
-{
-	GtkTreeIter iter;
-	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter);
-
-	do {
-		struct _route_style *style;
-		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, DATA_COL, &style, -1);
-		if ((style != NULL) && (style->rst == rst)) {
-			g_signal_handler_block(G_OBJECT(style->action), style->sig_id);
-			gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(style->action), TRUE);
-			g_signal_handler_unblock(G_OBJECT(style->action), style->sig_id);
-			rss->active_style = style;
-			g_signal_emit(rss, ghid_route_style_selector_signals[SELECT_STYLE_SIGNAL], 0, rss->active_style->rst);
-			return TRUE;
-		}
-	}
-	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(rss->model), &iter));
-
-	return FALSE;
-}
-
-/*! \brief Returns the GtkAccelGroup of a route style selector
- *  \par Function Description
- *
- *  \param [in] rss            The selector to be acted on
- *
- *  \return the accel group of the selector
- */
-GtkAccelGroup *ghid_route_style_selector_get_accel_group(GHidRouteStyleSelector * rss)
-{
-	return rss->accel_group;
-}
-
-/*! \brief Sets a GHidRouteStyleSelector selection to given values
- *  \par Function Description
- *  Given the line thickness, via size and clearance values of a route
- *  style, this function selects a route style with the given values.
- *  If there is no such style registered with the selector, nothing
- *  will happen. This function does not emit any signals.
- *
- *  \param [in] rss       The selector to be acted on
- *  \param [in] Thick     pcb_coord_t to match selection to
- *  \param [in] Hole      pcb_coord_t to match selection to
- *  \param [in] Diameter  pcb_coord_t to match selection to
- *  \param [in] Clearance  pcb_coord_t to match selection to
- */
-void ghid_route_style_selector_sync(GHidRouteStyleSelector * rss, pcb_coord_t Thick, pcb_coord_t Hole, pcb_coord_t Diameter, pcb_coord_t Clearance)
-{
-	GtkTreeIter iter;
-	int target, n;
-
-	/* Always update the label - even if there's no style, the current settings need to show */
-	ghid_set_status_line_label();
-
-	if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter))
-		return;
-
-	target = pcb_route_style_lookup(&PCB->RouteStyle, Thick, Diameter, Hole, Clearance, NULL);
-	if (target == -1) {
-		struct _route_style *style;
-
-		/* None of the styles matched: select the hidden custom button */
-		if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter))
-			return;
-
-		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, DATA_COL, &style, -1);
-		g_signal_handler_block(G_OBJECT(style->action), style->sig_id);
-		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(style->action), TRUE);
-		g_signal_handler_unblock(G_OBJECT(style->action), style->sig_id);
-		rss->active_style = style;
-
-		return;
-	}
-
-	/* need to select the style with index stored in target */
-	n = -1;
-	do {
-		struct _route_style *style;
-		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, DATA_COL, &style, -1);
-		if (n == target) {
-			g_signal_handler_block(G_OBJECT(style->action), style->sig_id);
-			gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(style->action), TRUE);
-			g_signal_handler_unblock(G_OBJECT(style->action), style->sig_id);
-			rss->active_style = style;
-			break;
-		}
-		n++;
-	} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(rss->model), &iter));
-}
-
-/*! \brief Removes all styles from a route style selector */
-void ghid_route_style_selector_empty(GHidRouteStyleSelector * rss)
-{
-	GtkTreeIter iter;
-	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter)) {
-		do {
-			struct _route_style *rsdata;
-			gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, DATA_COL, &rsdata, -1);
-			if (rsdata != NULL) {
-				if (rsdata->action) {
-					gtk_action_disconnect_accelerator(GTK_ACTION(rsdata->action));
-					gtk_action_group_remove_action(rss->action_group, GTK_ACTION(rsdata->action));
-					g_object_unref(G_OBJECT(rsdata->action));
-				}
-				if (rsdata->button)
-					gtk_widget_destroy(GTK_WIDGET(rsdata->button));;
-				gtk_tree_row_reference_free(rsdata->rref);
-				free(rsdata);
-			}
-		} while (gtk_list_store_remove(rss->model, &iter));
-	}
-	rss->action_radio_group = NULL;
-	rss->button_radio_group = NULL;
-	rss->hidden_button = 0;
-}
diff --git a/src_plugins/hid_gtk/ghid-route-style-selector.h b/src_plugins/hid_gtk/ghid-route-style-selector.h
deleted file mode 100644
index 970ada4..0000000
--- a/src_plugins/hid_gtk/ghid-route-style-selector.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef GHID_ROUTE_STYLE_SELECTOR_H__
-#define GHID_ROUTE_STYLE_SELECTOR_H__
-
-#include <glib.h>
-#include <glib-object.h>
-#include <gtk/gtk.h>
-
-#include "config.h"
-#include "route_style.h"
-
-G_BEGIN_DECLS										/* keep c++ happy */
-#define GHID_ROUTE_STYLE_SELECTOR_TYPE            (ghid_route_style_selector_get_type ())
-#define GHID_ROUTE_STYLE_SELECTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_ROUTE_STYLE_SELECTOR_TYPE, GHidRouteStyleSelector))
-#define GHID_ROUTE_STYLE_SELECTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GHID_ROUTE_STYLE_SELECTOR_TYPE, GHidRouteStyleSelectorClass))
-#define IS_GHID_ROUTE_STYLE_SELECTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_ROUTE_STYLE_SELECTOR_TYPE))
-#define IS_GHID_ROUTE_STYLE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHID_ROUTE_STYLE_SELECTOR_TYPE))
-typedef struct _GHidRouteStyleSelector GHidRouteStyleSelector;
-typedef struct _GHidRouteStyleSelectorClass GHidRouteStyleSelectorClass;
-
-GType ghid_route_style_selector_get_type(void);
-GtkWidget *ghid_route_style_selector_new(void);
-
-gint ghid_route_style_selector_install_items(GHidRouteStyleSelector * rss, GtkMenuShell * shell, gint pos);
-
-void ghid_route_style_selector_add_route_style(GHidRouteStyleSelector * rss, pcb_route_style_t * data);
-gboolean ghid_route_style_selector_select_style(GHidRouteStyleSelector * rss, pcb_route_style_t * rst);
-void ghid_route_style_selector_edit_dialog(GHidRouteStyleSelector * rss);
-
-GtkAccelGroup *ghid_route_style_selector_get_accel_group(GHidRouteStyleSelector * rss);
-
-void ghid_route_style_selector_sync(GHidRouteStyleSelector * rss, pcb_coord_t Thick, pcb_coord_t Hole, pcb_coord_t Diameter, pcb_coord_t Clearance);
-void ghid_route_style_selector_empty(GHidRouteStyleSelector * rss);
-
-G_END_DECLS											/* keep c++ happy */
-#endif
diff --git a/src_plugins/hid_gtk/ghid-search.c b/src_plugins/hid_gtk/ghid-search.c
deleted file mode 100644
index 7d7b871..0000000
--- a/src_plugins/hid_gtk/ghid-search.c
+++ /dev/null
@@ -1,857 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  pcb-rnd, interactive printed circuit board design
- *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* advanced search dialog */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <gtk/gtk.h>
-#include <genlist/gendlist.h>
-#include "config.h"
-#include "gui.h"
-#include "compat_misc.h"
-#include "ghid-search.h"
-#include "win_place.h"
-#include "hid_actions.h"
-#include "compat_nls.h"
-#include "misc_util.h"
-
-typedef struct expr1_s expr1_t;
-
-struct expr1_s {
-	GtkWidget *and;        /* only if not the first row */
-
-	GtkWidget *hbox;       /* only if first in row*/
-	GtkWidget *remove_row; /* only if first in row*/
-	GtkWidget *append_col; /* only if first in row*/
-	GtkWidget *spc;        /* only if first in row*/
-
-	GtkWidget *remove, *remove_button;
-	GtkWidget *content;    /* the actual expression */
-	GtkWidget *or;         /* only if not the first in the row */
-
-	gdl_elem_t next_or;   /* --> */
-	gdl_elem_t next_and;  /* v */
-	gdl_list_t ors;       /* only in the first; the row-first is not on this list, so it collects the subseqent siblings only */
-
-	expr1_t *row;         /* only if not the first */
-
-	gulong sig_remove_row;
-	gulong sig_append_col;
-
-	char *code;          /* ... to use in the query script */
-};
-
-typedef struct {
-	GtkWidget *window;
-	GtkWidget *expr;          /* manual expression entry */
-	GtkWidget *action;        /* what-to-do combo box */
-	GtkWidget *wizard_enable; /* checkbox */
-	GtkWidget *wizard_vbox;
-	GtkWidget *new_row;
-
-	gdl_list_t wizard;       /* of expr1_t */
-} ghid_search_dialog_t;
-
-static ghid_search_dialog_t sdlg;
-
-static void new_col_cb(GtkWidget *button, void *data);
-static void remove_row_cb(GtkWidget *button, void *data);
-static void remove_expr_cb(GtkWidget *button, void *data);
-static void edit_expr_cb(GtkWidget *button, void *data);
-static void expr_wizard_dialog(expr1_t *e);
-
-static void build_expr1(expr1_t *e, GtkWidget *parent_box)
-{
-	e->content = gtk_button_new_with_label("<expr>");
-	gtk_button_set_image(GTK_BUTTON(e->content), gtk_image_new_from_icon_name("gtk-new", GTK_ICON_SIZE_MENU));
-	gtk_box_pack_start(GTK_BOX(parent_box), e->content, FALSE, FALSE, 0);
-	gtk_widget_set_tooltip_text(e->content, "Edit search expression");
-	g_signal_connect(e->content, "clicked", G_CALLBACK(edit_expr_cb), e);
-
-	e->remove = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(parent_box), e->remove, FALSE, FALSE, 0);
-
-	e->remove_button = gtk_button_new_with_label("");
-	gtk_button_set_image(GTK_BUTTON(e->remove_button), gtk_image_new_from_icon_name("gtk-delete", GTK_ICON_SIZE_MENU));
-	gtk_box_pack_start(GTK_BOX(e->remove), e->remove_button, FALSE, FALSE, 0);
-	gtk_widget_set_tooltip_text(e->remove_button, "Remove this expression");
-	g_signal_connect(e->remove_button, "clicked", G_CALLBACK(remove_expr_cb), e);
-}
-
-/* e is not part of any list by the time of the call */
-static void destroy_expr1(expr1_t *e)
-{
-#	define destroy(w) if (w != NULL) gtk_widget_destroy(w)
-	destroy(e->and);
-	destroy(e->spc);
-	destroy(e->remove_row);
-	destroy(e->append_col);
-	destroy(e->remove);
-	destroy(e->content);
-	destroy(e->or);
-	destroy(e->hbox);
-	free(e);
-#	undef destroy
-}
-
-static expr1_t *append_row()
-{
-	expr1_t *e = calloc(sizeof(expr1_t), 1);
-
-	if (gdl_first(&sdlg.wizard) != NULL) {
-		e->and = gtk_label_new("AND");
-		gtk_misc_set_alignment(GTK_MISC(e->and), -1, 0.);
-		gtk_box_pack_start(GTK_BOX(sdlg.wizard_vbox), e->and, FALSE, FALSE, 0);
-	}
-
-	e->hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(sdlg.wizard_vbox), e->hbox, FALSE, FALSE, 0);
-
-	e->remove_row = gtk_button_new_with_label("");
-	gtk_button_set_image(GTK_BUTTON(e->remove_row), gtk_image_new_from_icon_name("gtk-delete", GTK_ICON_SIZE_SMALL_TOOLBAR));
-	gtk_box_pack_start(GTK_BOX(e->hbox), e->remove_row, FALSE, FALSE, 0);
-	e->sig_remove_row = g_signal_connect(e->remove_row, "clicked", G_CALLBACK(remove_row_cb), e);
-	gtk_widget_set_tooltip_text(e->remove_row, "Remove this row of expressions");
-
-
-	e->append_col = gtk_button_new_with_label("");
-	gtk_button_set_image(GTK_BUTTON(e->append_col), gtk_image_new_from_icon_name("gtk-add", GTK_ICON_SIZE_SMALL_TOOLBAR));
-	gtk_box_pack_start(GTK_BOX(e->hbox), e->append_col, FALSE, FALSE, 0);
-	e->sig_append_col = g_signal_connect(e->append_col, "clicked", G_CALLBACK(new_col_cb), e);
-	gtk_widget_set_tooltip_text(e->append_col, "Append an expression to this row with OR");
-
-	e->spc = gtk_vbox_new(FALSE, 10);
-	gtk_box_pack_start(GTK_BOX(e->hbox), e->spc, FALSE, FALSE, 10);
-
-	build_expr1(e, e->hbox);
-
-	gdl_append(&sdlg.wizard, e, next_and);
-	return e;
-}
-
-static expr1_t *append_col(expr1_t *row)
-{
-	expr1_t *e = calloc(sizeof(expr1_t), 1);
-
-	e->or = gtk_label_new(" OR ");
-	gtk_misc_set_alignment(GTK_MISC(e->or), -1, 1);
-	gtk_box_pack_start(GTK_BOX(row->hbox), e->or, FALSE, FALSE, 0);
-
-	build_expr1(e, row->hbox);
-
-	gdl_append(&row->ors, e, next_or);
-	e->row = row;
-	return e;
-}
-
-static void remove_row(expr1_t *row)
-{
-	expr1_t *o;
-	gdl_remove(&sdlg.wizard, row, next_and);
-	for(o = gdl_first(&row->ors); o != NULL; o = gdl_next(&row->ors, o))
-		destroy_expr1(o);
-	destroy_expr1(row);
-
-	/* the new first widget must not have an AND "preface" */
-	o = gdl_first(&sdlg.wizard);
-	if ((o != NULL) && (o->and != NULL)) {
-		gtk_widget_destroy(o->and);
-		o->and = NULL;
-	}
-}
-
-static void remove_expr(expr1_t *e)
-{
-	if (e->row == NULL) {
-		/* first item in a row */
-		expr1_t *o, *o2 = gdl_first(&e->ors);
-		if (o2 != NULL) {
-			/* there are subsequent items in the row - have to make the first of them the new head */
-			gdl_remove(&e->ors, o2, next_or);
-			gdl_insert_before(&sdlg.wizard, e, o2, next_and);
-			gdl_remove(&sdlg.wizard, e, next_and);
-#			define inherit(dst, src, fld)  dst->fld = src->fld; src->fld = NULL;
-			inherit(o2, e, and);
-			inherit(o2, e, hbox);
-			inherit(o2, e, remove_row);
-			inherit(o2, e, append_col);
-			inherit(o2, e, spc);
-#			undef inherit
-			/* move the list, reparenting it */
-			memcpy(&o2->ors, &e->ors, sizeof(e->ors));
-			for(o = gdl_first(&o2->ors); o != NULL; o = gdl_next(&o2->ors, o))
-				o->next_or.parent = &o2->ors;
-
-			o2->row = NULL;
-			memset(&e->ors, 0, sizeof(e->ors));
-			if (o2->or != NULL) {
-				gtk_widget_destroy(o2->or);
-				o2->or = NULL;
-			}
-
-			/* reconnect row signals to the new head */
-			g_signal_handler_disconnect(o2->remove_row, e->sig_remove_row);
-			g_signal_handler_disconnect(o2->append_col, e->sig_append_col);
-
-			o2->sig_remove_row = g_signal_connect(o2->remove_row, "clicked", G_CALLBACK(remove_row_cb), o2);
-			o2->sig_append_col = g_signal_connect(o2->append_col, "clicked", G_CALLBACK(new_col_cb), o2);
-		}
-		else {
-			/* only item of the row */
-			remove_row(e);
-			return;
-		}
-	}
-	else
-		gdl_remove(&e->row->ors, e, next_or);
-	destroy_expr1(e);
-}
-
-static int num_ors(expr1_t *head)
-{
-	int count = 0;
-	expr1_t *o;
-	if (head->code != NULL)
-		count++;
-	for(o = gdl_first(&head->ors); o != NULL; o = gdl_next(&head->ors, o))
-		if (o->code != NULL)
-			count++;
-	return count;
-}
-
-static void rebuild(void)
-{
-	int and_first = 1;
-	gds_t s;
-	expr1_t *a, *o;
-	gds_init(&s);
-
-	for(a = gdl_first(&sdlg.wizard); a != NULL; a = gdl_next(&sdlg.wizard, a)) {
-		int or_first = 1;
-		int ors = num_ors(a);
-		if (ors == 0)
-			continue;
-
-		/* add the && if needed */
-		if (!and_first)
-			gds_append_str(&s, " && ");
-		and_first = 0;
-
-		if (ors > 1)
-			gds_append_str(&s, "(");
-
-		if (a->code != NULL) {
-			gds_append_str(&s, a->code);
-			or_first = 0;
-		}
-
-		for(o = gdl_first(&a->ors); o != NULL; o = gdl_next(&a->ors, o)) {
-			if (o->code != NULL) {
-				if (!or_first)
-					gds_append_str(&s, " || ");
-				or_first = 0;
-				gds_append_str(&s, o->code);
-			}
-		}
-
-		if (ors > 1)
-			gds_append_str(&s, ")");
-	}
-	gtk_entry_set_text(GTK_ENTRY(sdlg.expr), s.array);
-	gds_uninit(&s);
-}
-
-/* button callbacks */
-static void new_row_cb(GtkWidget *button, void *data)
-{
-	append_row();
-	gtk_widget_show_all(sdlg.window);
-}
-
-static void remove_row_cb(GtkWidget *button, void *data)
-{
-	expr1_t *row = (expr1_t *)data;
-	remove_row(row);
-	rebuild();
-	gtk_widget_show_all(sdlg.window);
-}
-
-static void remove_expr_cb(GtkWidget *button, void *data)
-{
-	remove_expr((expr1_t *)data);
-	rebuild();
-	gtk_widget_show_all(sdlg.window);
-}
-
-static void edit_expr_cb(GtkWidget *button, void *data)
-{
-	expr_wizard_dialog((expr1_t *)data);
-}
-
-static void new_col_cb(GtkWidget *button, void *data)
-{
-	expr1_t *row = (expr1_t *)data;
-	append_col(row);
-	gtk_widget_show_all(sdlg.window);
-}
-
-static void wizard_toggle_cb(GtkCheckButton *button, void *data)
-{
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) {
-		gtk_widget_show(sdlg.wizard_vbox);
-		gtk_widget_set_sensitive(sdlg.new_row, 1);
-		gtk_widget_set_sensitive(sdlg.expr, 0);
-
-	}
-	else {
-		gtk_widget_hide(sdlg.wizard_vbox);
-		gtk_widget_set_sensitive(sdlg.new_row, 0);
-		gtk_widget_set_sensitive(sdlg.expr, 1);
-	}
-}
-
-
-/* Run the expression wizard dialog box */
-#include "ghid-search-tab.h"
-
-static void expr_wizard_init_model()
-{
-	const expr_wizard_t *w;
-	expr_wizard_op_t *o;
-	const char **s;
-
-	if (expr_wizard_dlg.md_left != NULL)
-		return;
-
-	/* render operator models */
-	for(o = op_tab; o->ops != NULL; o++) {
-		o->model = gtk_list_store_newv(1, model_op);
-		for(s = o->ops; *s != NULL; s++)
-			gtk_list_store_insert_with_values(o->model, NULL, -1,  0, *s,  -1);
-	}
-
-	/* render right constant models */
-	for(o = right_const_tab; o->ops != NULL; o++) {
-		o->model = gtk_list_store_newv(1, model_op);
-		for(s = o->ops; *s != NULL; s++)
-			gtk_list_store_insert_with_values(o->model, NULL, -1,  0, *s,  -1);
-	}
-
-	{ /* create the left tree model */
-		GtkTreeIter *parent = NULL, iter, iparent;
-		expr_wizard_dlg.md_left = gtk_tree_store_newv(2, model_op);
-		for(w = expr_tab; w->left_desc != NULL; w++) {
-			if (w->left_var == NULL)
-				parent = NULL;
-			gtk_tree_store_append(expr_wizard_dlg.md_left, &iter, parent);
-			gtk_tree_store_set(expr_wizard_dlg.md_left, &iter, 0,w->left_desc, 1,w, -1);
-			if (w->left_var == NULL) {
-				/* new section */
-				iparent = iter;
-				parent = &iparent;
-			}
-		}
-	}
-}
-
-static void right_hide(void)
-{
-	gtk_widget_hide(expr_wizard_dlg.right_str);
-	gtk_widget_hide(expr_wizard_dlg.right_int);
-	gtk_widget_hide(expr_wizard_dlg.right_coord);
-	gtk_widget_hide(expr_wizard_dlg.tr_right);
-}
-
-static const expr_wizard_t *left_get_wiz(void)
-{
-	const expr_wizard_t *w;
-	GtkTreeSelection *tsel;
-	GtkTreeModel *tm;
-	GtkTreeIter iter;
-
-	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(expr_wizard_dlg.tr_left));
-	if (tsel == NULL)
-		return NULL;
-
-	gtk_tree_selection_get_selected(tsel, &tm, &iter);
-	if (iter.stamp == 0)
-		return NULL;
-
-	gtk_tree_model_get(tm, &iter, 1, &w, -1);
-	return w;
-}
-
-/* Returns the string current value of a single-column-string-tree */
-static const char *wiz_get_tree_str(GtkWidget *tr)
-{
-	const char *s;
-	GtkTreeSelection *tsel;
-	GtkTreeModel *tm;
-	GtkTreeIter iter;
-
-	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tr));
-	if (tsel == NULL)
-		return NULL;
-
-	gtk_tree_selection_get_selected(tsel, &tm, &iter);
-	if (iter.stamp == 0)
-		return NULL;
-
-	gtk_tree_model_get(tm, &iter, 0, &s, -1);
-	return s;
-}
-
-static void left_chg_cb(GtkTreeView *t, gpointer *data)
-{
-	const expr_wizard_t *w = left_get_wiz();
-
-	right_hide();
-
-	if ((w == NULL) || (w->left_var == NULL))
-		return;
-
-	gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_op), GTK_TREE_MODEL(w->ops->model));
-
-	switch(w->rtype) {
-		case RIGHT_INT: gtk_widget_show(expr_wizard_dlg.right_int); break;
-		case RIGHT_STR: gtk_widget_show(expr_wizard_dlg.right_str); break;
-		case RIGHT_COORD: gtk_widget_show(expr_wizard_dlg.right_coord); break;
-		case RIGHT_CONST:
-			gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_right), GTK_TREE_MODEL(w->right_const->model));
-			gtk_widget_show(expr_wizard_dlg.tr_right);
-			break;
-	}
-}
-
-static char *expr_wizard_result(int desc)
-{
-	gds_t s;
-	char tmp[128];
-	const char *cs;
-	const expr_wizard_t *parent, *w = left_get_wiz();
-
-	if ((w == NULL) || (w->left_var == NULL))
-		return NULL;
-
-
-	gds_init(&s);
-	if (desc) {
-		/* search the parent */
-		for(parent = w; parent >= expr_tab; parent--)
-			if (parent->left_var == NULL)
-				break;
-
-		if (parent->left_desc != NULL)
-			pcb_append_printf(&s, "%s\t%s", parent->left_desc, w->left_desc);
-		else
-			pcb_append_printf(&s, "%s", w->left_desc);
-	}
-	else
-		pcb_append_printf(&s, "(%s", w->left_var);
-
-	cs = wiz_get_tree_str(expr_wizard_dlg.tr_op);
-	if (cs == NULL)
-		goto err;
-
-	if (desc)
-		pcb_append_printf(&s, "\n%s\n", cs);
-	else
-		pcb_append_printf(&s, " %s ", cs);
-
-	switch(w->rtype) {
-		case RIGHT_INT: pcb_append_printf(&s, "%.0f", gtk_adjustment_get_value(expr_wizard_dlg.right_adj)); break;
-		case RIGHT_STR:
-			if (!desc)
-				gds_append_str(&s, "\"");
-			pcb_append_printf(&s, "%s", gtk_entry_get_text(GTK_ENTRY(expr_wizard_dlg.right_str)));
-			if (!desc)
-				gds_append_str(&s, "\"");
-			break;
-		case RIGHT_COORD:
-			ghid_coord_entry_get_value_str(GHID_COORD_ENTRY(expr_wizard_dlg.right_coord), tmp, sizeof(tmp));
-			pcb_append_printf(&s, "%s", tmp);
-			break;
-		case RIGHT_CONST:
-			cs = wiz_get_tree_str(expr_wizard_dlg.tr_right);
-			if (cs == NULL)
-				goto err;
-			pcb_append_printf(&s, "%s", cs);
-			break;
-	}
-
-	if (!desc)
-		gds_append_str(&s, ")");
-
-	return s.array;
-
-	err:;
-	free(s.array);
-	return NULL;
-}
-
-/* look up a tab entry with a slow linear search */
-static const expr_wizard_t *find_tab_entry(const expr_wizard_t *start_at, const char *desc, int need_hdr, int *idx)
-{
-	const expr_wizard_t *w;
-	int i = 0, initial = 1;
-
-	for(w = start_at; w->left_desc != NULL; w++) {
-		if (need_hdr) {
-			if (w->left_var != NULL) {
-				if (initial)
-					i++;
-				continue;
-			}
-			else
-				initial = 0;
-		}
-		else {
-			if (w->left_var == NULL)
-				return NULL;
-		}
-		if (strcmp(w->left_desc, desc) == 0) {
-			*idx = i;
-			return w;
-		}
-		i++;
-	}
-
-	return NULL;
-}
-
-/* Set enum-like tree cursor from a string; returns 0 if not found, 1 if found. */
-static int set_tree_from_enum(GtkWidget *tree, const char **vals, const char *target)
-{
-	int n, found;
-	const char **s;
-	for(n = 0, found = 0, s = vals; *s != NULL; s++, n++) {
-		if (strcmp(*s, target) == 0) {
-			found = 1;
-			break;
-		}
-	}
-	if (found) {
-		GtkTreePath *path = gtk_tree_path_new_from_indices(n, -1);
-		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree), path, NULL, FALSE);
-		gtk_tree_path_free(path);
-	}
-	return found;
-}
-
-/* Set the value of expr wizard widgets to match the button text from the previous set */
-void expr_wizard_import(const char *desc_)
-{
-	char *desc, *left, *left_parent, *left_desc, *op, *right, *sep;
-	const expr_wizard_t *w;
-	int l1idx = -1, l2idx = -1;
-
-	if (desc_ == NULL)
-		return;
-
-	/* split the string into left, op and right */
-	desc = pcb_strdup(desc_);
-	left = desc;
-
-	op = strchr(left, '\n');
-	if (op == NULL) goto fail;
-	*op = '\0';
-	op++;
-
-	right = strchr(op, '\n');
-	if (right == NULL) goto fail;
-	*right = '\0';
-	right++;
-
-	/* split left */
-	sep = strchr(left, '\t');
-	if (sep != NULL) {
-		*sep = '\0';
-		sep++;
-		left_parent = left;
-		left_desc = sep;
-	}
-	else {
-		left_parent = NULL;
-		left_desc = left;
-	}
-
-/*	printf("lp='%s' ld='%s' op='%s' r='%s'\n", left_parent, left_desc, op, right);*/
-	/* Find the tab entry */
-	
-	if (left_parent != NULL) {
-		w = find_tab_entry(expr_tab, left_parent, 1, &l1idx);
-		if (w == NULL) goto fail;
-		w++;
-	}
-	else
-		w = expr_tab;
-	w = find_tab_entry(w, left_desc, 0, &l2idx);
-	if (w == NULL) goto fail;
-
-	/* set left tree widget cursor */
-	{
-		GtkTreePath *path;
-		if (left_parent != NULL)
-			path = gtk_tree_path_new_from_indices(l1idx, l2idx, -1);
-		else
-			path = gtk_tree_path_new_from_indices(l2idx, -1);
-
-		gtk_tree_view_expand_to_path(GTK_TREE_VIEW(expr_wizard_dlg.tr_left), path);
-		gtk_tree_view_set_cursor(GTK_TREE_VIEW(expr_wizard_dlg.tr_left), path, NULL, FALSE);
-		gtk_tree_path_free(path);
-	}
-
-	/* set op cursor */
-	set_tree_from_enum(expr_wizard_dlg.tr_op, w->ops->ops, op);
-
-	/* set value field */
-	{
-		switch(w->rtype) {
-			case RIGHT_STR:
-				gtk_entry_set_text(GTK_ENTRY(expr_wizard_dlg.right_str), right);
-				break;
-			case RIGHT_INT:
-			{
-				char *end;
-				double d = strtod(right, &end);
-				if (*end == '\0')
-					gtk_spin_button_set_value(GTK_SPIN_BUTTON(expr_wizard_dlg.right_int), d);
-				break;
-			}
-			case RIGHT_COORD:
-			{
-				pcb_bool succ;
-				double d = pcb_get_value_ex(right, NULL, NULL, NULL, "mm", &succ);
-				if (succ)
-					ghid_coord_entry_set_value(GHID_COORD_ENTRY(expr_wizard_dlg.right_coord), d);
-				break;
-			}
-			case RIGHT_CONST:
-				set_tree_from_enum(expr_wizard_dlg.tr_right, w->right_const->ops, right);
-				break;
-		}
-	}
-
-	fail:;
-	free(desc);
-}
-
-static void expr_wizard_dialog(expr1_t *e)
-{
-	GtkWidget *dialog, *vbox, *hbox;
-	GtkCellRenderer *renderer;
-	gboolean response;
-
-	expr_wizard_init_model();
-
-	/* Create the dialog */
-	dialog = gtk_dialog_new_with_buttons("Expression wizard",
-	                                     GTK_WINDOW(gport->top_window),
-	                                     GTK_DIALOG_MODAL,
-	                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
-	hbox = gtk_hbox_new(FALSE, 4);
-	gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
-
-	/* left */
-	vbox = gtk_vbox_new(FALSE, 4);
-	expr_wizard_dlg.tr_left = gtk_tree_view_new();
-	renderer = gtk_cell_renderer_text_new();
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(expr_wizard_dlg.tr_left), -1, "variable", renderer, "text",0,  NULL);
-	gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_left), GTK_TREE_MODEL(expr_wizard_dlg.md_left));
-	g_signal_connect(G_OBJECT(expr_wizard_dlg.tr_left), "cursor-changed", G_CALLBACK(left_chg_cb), NULL);
-	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.tr_left, FALSE, TRUE, 4);
-
-
-	expr_wizard_dlg.entry_left = gtk_entry_new();
-	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.entry_left, FALSE, TRUE, 4);
-
-	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 4);
-
-	/* operator */
-	vbox = gtk_vbox_new(FALSE, 4);
-
-	expr_wizard_dlg.tr_op = gtk_tree_view_new();
-	renderer = gtk_cell_renderer_text_new();
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(expr_wizard_dlg.tr_op), -1, "op", renderer, "text", 0, NULL);
-	gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_op), GTK_TREE_MODEL(op_tab[OPS_ANY].model));
-	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.tr_op, FALSE, FALSE, 4);
-
-	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 4);
-
-	/* right */
-	vbox = gtk_vbox_new(FALSE, 4);
-
-	expr_wizard_dlg.tr_right = gtk_tree_view_new();
-	renderer = gtk_cell_renderer_text_new();
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(expr_wizard_dlg.tr_right), -1, "constant", renderer, "text", 0, NULL);
-/*	gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_right), GTK_TREE_MODEL(expr_wizard_dlg.md_objtype));*/
-	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.tr_right, FALSE, TRUE, 4);
-
-	expr_wizard_dlg.right_str = gtk_entry_new();
-	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.right_str, FALSE, TRUE, 4);
-
-	expr_wizard_dlg.right_adj = GTK_ADJUSTMENT(gtk_adjustment_new(10,
-	                                                              0, /* min */
-	                                                              8,
-	                                                              1, 1, /* steps */
-	                                                              0.0));
-/*	g_signal_connect(G_OBJECT(expr_wizard_dlg.right_adj), "value-changed", G_CALLBACK(config_auto_idx_changed_cb), NULL); */
-	expr_wizard_dlg.right_int = gtk_spin_button_new(expr_wizard_dlg.right_adj, 1, 8);
-	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.right_int, FALSE, TRUE, 4);
-
-	expr_wizard_dlg.right_coord = ghid_coord_entry_new(0, PCB_MM_TO_COORD(2100), 0, conf_core.editor.grid_unit, CE_MEDIUM);
-	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.right_coord, FALSE, TRUE, 4);
-
-	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 4);
-
-	/* pack content */
-	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
-	gtk_widget_show_all(dialog);
-	right_hide();
-
-	/* Run the dialog */
-	expr_wizard_import(gtk_button_get_label(GTK_BUTTON(e->content)));
-	response = gtk_dialog_run(GTK_DIALOG(dialog));
-	if (response == GTK_RESPONSE_OK) {
-		char *res = expr_wizard_result(1);
-		if (res != NULL) {
-			gtk_button_set_label(GTK_BUTTON(e->content), res);
-			free(res);
-		}
-		if (e->code != NULL)
-			free(e->code);
-		e->code = expr_wizard_result(0);
-		gtk_button_set_image(GTK_BUTTON(e->content), gtk_image_new_from_icon_name("gtk-refresh", GTK_ICON_SIZE_MENU));
-		rebuild();
-	}
-	gtk_widget_destroy(dialog);
-}
-
-
-/******** Advanced search window creation and administration ********/
-static void dialog_cb(GtkDialog *dlg, gint response_id, gpointer *data)
-{
-	const char *act, *script;
-
-	switch(response_id) {
-		case GTK_RESPONSE_APPLY:
-			script = gtk_entry_get_text(GTK_ENTRY(sdlg.expr));
-			act = gtk_combo_box_get_active_text(GTK_COMBO_BOX(sdlg.action));
-			pcb_hid_actionl("query", act, script, NULL);
-			break;
-		case GTK_RESPONSE_CLOSE:
-			gtk_widget_destroy(GTK_WIDGET(dlg));
-			break;
-	}
-}
-
-static void ghid_search_window_create()
-{
-	GtkWidget *vbox_win, *lab, *vbox;
-	GtkWidget *content_area, *top_window = gport->top_window;
-	const char *actions[] = { "select", "unselect", NULL };
-	const char **s;
-	int ver;
-
-	ver = pcb_hid_actionl("query", "version", NULL);
-	if (ver < 0100) {
-		sdlg.window = NULL;
-		pcb_message(PCB_MSG_ERROR, "The query plugin is not avaialble, can not do advanced search.\n");
-		return;
-	}
-
-	/* make sure the list is empty */
-	memset(&sdlg.wizard, 0, sizeof(sdlg.wizard));
-
-	sdlg.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	sdlg.window = gtk_dialog_new_with_buttons(_("Advanced search"),
-																			 GTK_WINDOW(top_window),
-																			 GTK_DIALOG_DESTROY_WITH_PARENT,
-																			 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, NULL);
-
-	g_signal_connect(sdlg.window, "response", G_CALLBACK(dialog_cb), NULL);
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(sdlg.window));
-
-	vbox_win = gtk_vbox_new(FALSE, 4);
-	gtk_container_add(GTK_CONTAINER(content_area), vbox_win);
-
-	lab = gtk_label_new("Query expression:");
-	gtk_box_pack_start(GTK_BOX(vbox_win), lab, FALSE, FALSE, 0);
-	gtk_misc_set_alignment(GTK_MISC(lab), -1, 0.);
-
-/* expr entry */
-	sdlg.expr = gtk_entry_new();
-	gtk_box_pack_start(GTK_BOX(vbox_win), sdlg.expr, FALSE, FALSE, 0);
-
-	{
-		GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
-
-		sdlg.action = gtk_combo_box_new_text();
-		gtk_widget_set_tooltip_text(sdlg.action, "Do this with any object matching the query expression");
-		for(s = actions; *s != NULL; s++)
-			gtk_combo_box_append_text(GTK_COMBO_BOX(sdlg.action), *s);
-		gtk_box_pack_start(GTK_BOX(hbox), sdlg.action, FALSE, FALSE, 0);
-		gtk_combo_box_set_active(GTK_COMBO_BOX(sdlg.action), 0);
-
-		gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("matching items"), FALSE, FALSE, 0);
-
-		gtk_box_pack_start(GTK_BOX(vbox_win), hbox, FALSE, FALSE, 0);
-	}
-
-	sdlg.wizard_enable = gtk_check_button_new_with_label("Enable wizard");
-	g_signal_connect(sdlg.wizard_enable, "toggled", G_CALLBACK(wizard_toggle_cb), NULL);
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdlg.wizard_enable), 1);
-	gtk_box_pack_start(GTK_BOX(vbox_win), sdlg.wizard_enable, FALSE, FALSE, 0);
-
-/* */
-	vbox = ghid_framed_vbox(vbox_win, "wizard", 1, TRUE, 4, 10);
-
-	sdlg.wizard_vbox = gtk_vbox_new(FALSE, 6);
-	gtk_box_pack_start(GTK_BOX(vbox), sdlg.wizard_vbox, TRUE, TRUE, 4);
-
-	sdlg.new_row = gtk_button_new_with_label("Add new row");
-	g_signal_connect(sdlg.new_row, "clicked", G_CALLBACK(new_row_cb), NULL);
-	gtk_box_pack_start(GTK_BOX(vbox), sdlg.new_row, FALSE, FALSE, 0);
-	gtk_button_set_image(GTK_BUTTON(sdlg.new_row), gtk_image_new_from_icon_name("gtk-new", GTK_ICON_SIZE_MENU));
-	gtk_widget_set_tooltip_text(sdlg.new_row, "Append a row of expressions to the query with AND");
-
-
-/* Add one row of wizard to save a click in the most common case */
-	append_row();
-
-	gtk_widget_realize(sdlg.window);
-}
-
-void ghid_search_window_show(gboolean raise)
-{
-	ghid_search_window_create();
-	if (sdlg.window == NULL)
-		return;
-	gtk_widget_show_all(sdlg.window);
-	wplc_place(WPLC_SEARCH, sdlg.window);
-	if (raise)
-		gtk_window_present(GTK_WINDOW(sdlg.window));
-}
diff --git a/src_plugins/hid_gtk/ghid-search.h b/src_plugins/hid_gtk/ghid-search.h
deleted file mode 100644
index cf90ffa..0000000
--- a/src_plugins/hid_gtk/ghid-search.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  pcb-rnd, interactive printed circuit board design
- *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* advanced search dialog */
-void ghid_search_window_show(gboolean raise);
-
-
diff --git a/src_plugins/hid_gtk/gtkhid-gdk.c b/src_plugins/hid_gtk/gtkhid-gdk.c
index 4989b30..701bcfb 100644
--- a/src_plugins/hid_gtk/gtkhid-gdk.c
+++ b/src_plugins/hid_gtk/gtkhid-gdk.c
@@ -62,26 +62,33 @@ int ghid_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, unsigned
 {
 	int idx = group;
 	if (idx >= 0 && idx < pcb_max_group) {
-		int n = PCB->LayerGroups.Number[group];
+		int n = PCB->LayerGroups.grp[group].len;
 		for (idx = 0; idx < n - 1; idx++) {
-			int ni = PCB->LayerGroups.Entries[group][idx];
-			if (ni >= 0 && ni < pcb_max_copper_layer + 2 && PCB->Data->Layer[ni].On)
+			int ni = PCB->LayerGroups.grp[group].lid[idx];
+			if (ni >= 0 && ni < pcb_max_layer && PCB->Data->Layer[ni].On)
 				break;
 		}
-		idx = PCB->LayerGroups.Entries[group][idx];
+		idx = PCB->LayerGroups.grp[group].lid[idx];
 	}
 
-	if (idx >= 0 && idx < pcb_max_copper_layer && ((flags & PCB_LYT_ANYTHING) != PCB_LYT_SILK))
+	/* non-virtual layers with special visibility */
+	switch (flags & PCB_LYT_ANYTHING) {
+		case PCB_LYT_MASK:
+			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags) /*&& !pinout */ )
+				return conf_core.editor.show_mask;
+			return 0;
+		case PCB_LYT_PASTE: /* Never draw the paste layer */
+			return 0;
+	}
+
+	if (idx >= 0 && idx < pcb_max_layer && ((flags & PCB_LYT_ANYTHING) != PCB_LYT_SILK))
 		return /*pinout ? 1 : */ PCB->Data->Layer[idx].On;
 
+	/* virtual layers */
 	{
 		switch (flags & PCB_LYT_ANYTHING) {
 		case PCB_LYT_INVIS:
 			return /* pinout ? 0 : */ PCB->InvisibleObjectsOn;
-		case PCB_LYT_MASK:
-			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags) /*&& !pinout */ )
-				return conf_core.editor.show_mask;
-			return 0;
 		case PCB_LYT_SILK:
 			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags) /*|| pinout */ )
 				return PCB->ElementOn;
@@ -165,9 +172,9 @@ static inline void ghid_draw_grid_global(void)
 		x1 += grd;
 	if (Vy(y1) < 0)
 		y1 += grd;
-	if (Vx(x2) >= gport->width)
+	if (Vx(x2) >= gport->view.canvas_width)
 		x2 -= grd;
-	if (Vy(y2) >= gport->height)
+	if (Vy(y2) >= gport->view.canvas_height)
 		y2 -= grd;
 
 
@@ -380,7 +387,7 @@ void ghid_use_mask(int use_it)
 
 	case HID_MASK_CLEAR:
 		if (!gport->mask)
-			gport->mask = gdk_pixmap_new(0, gport->width, gport->height, 1);
+			gport->mask = gdk_pixmap_new(0, gport->view.canvas_width, gport->view.canvas_height, 1);
 		gport->drawable = gport->mask;
 		mask_seq = 0;
 		if (!priv->mask_gc) {
@@ -390,7 +397,7 @@ void ghid_use_mask(int use_it)
 		}
 		color.pixel = 1;
 		gdk_gc_set_foreground(priv->mask_gc, &color);
-		gdk_draw_rectangle(gport->drawable, priv->mask_gc, TRUE, 0, 0, gport->width, gport->height);
+		gdk_draw_rectangle(gport->drawable, priv->mask_gc, TRUE, 0, 0, gport->view.canvas_width, gport->view.canvas_height);
 		color.pixel = 0;
 		gdk_gc_set_foreground(priv->mask_gc, &color);
 		break;
@@ -598,7 +605,7 @@ void ghid_draw_line(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t
 	dx2 = Vx((double) x2);
 	dy2 = Vy((double) y2);
 
-	if (!pcb_line_clip(0, 0, gport->width, gport->height, &dx1, &dy1, &dx2, &dy2, gc->width / gport->view.coord_per_px))
+	if (!pcb_line_clip(0, 0, gport->view.canvas_width, gport->view.canvas_height, &dx1, &dy1, &dx2, &dy2, gc->width / gport->view.coord_per_px))
 		return;
 
 	USE_GC(gc);
@@ -607,12 +614,12 @@ void ghid_draw_line(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t
 
 void ghid_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t xradius, pcb_coord_t yradius, pcb_angle_t start_angle, pcb_angle_t delta_angle)
 {
-	gint vrx, vry;
-	gint w, h, radius;
+	gint vrx2, vry2;
+	double w, h, radius;
 	render_priv *priv = gport->render_priv;
 
-	w = gport->width * gport->view.coord_per_px;
-	h = gport->height * gport->view.coord_per_px;
+	w = gport->view.canvas_width * gport->view.coord_per_px;
+	h = gport->view.canvas_height * gport->view.coord_per_px;
 	radius = (xradius > yradius) ? xradius : yradius;
 	if (SIDE_X(cx) < gport->view.x0 - radius
 			|| SIDE_X(cx) > gport->view.x0 + w + radius
@@ -620,8 +627,13 @@ void ghid_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t
 		return;
 
 	USE_GC(gc);
-	vrx = Vz(xradius);
-	vry = Vz(yradius);
+	vrx2 = Vz(xradius*2.0);
+	vry2 = Vz(yradius*2.0);
+
+	if ((delta_angle > 360.0) || (delta_angle < -360.0)) {
+		start_angle = 0;
+		delta_angle = 360;
+	}
 
 	if (conf_core.editor.view.flip_x) {
 		start_angle = 180 - start_angle;
@@ -637,7 +649,9 @@ void ghid_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t
 		start_angle -= 360;
 
 	gdk_draw_arc(gport->drawable, priv->u_gc, 0,
-							 Vx(cx) - vrx, Vy(cy) - vry, vrx * 2, vry * 2, (start_angle + 180) * 64, delta_angle * 64);
+							 pcb_round(Vxd(cx) - Vzd(xradius) + 0.5), pcb_round(Vyd(cy) - Vzd(yradius) + 0.5),
+							 pcb_round(vrx2), pcb_round(vry2),
+							 (start_angle + 180) * 64, delta_angle * 64);
 }
 
 void ghid_draw_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2)
@@ -646,8 +660,8 @@ void ghid_draw_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t
 	render_priv *priv = gport->render_priv;
 
 	lw = gc->width;
-	w = gport->width * gport->view.coord_per_px;
-	h = gport->height * gport->view.coord_per_px;
+	w = gport->view.canvas_width * gport->view.coord_per_px;
+	h = gport->view.canvas_height * gport->view.coord_per_px;
 
 	if ((SIDE_X(x1) < gport->view.x0 - lw && SIDE_X(x2) < gport->view.x0 - lw)
 			|| (SIDE_X(x1) > gport->view.x0 + w + lw && SIDE_X(x2) > gport->view.x0 + w + lw)
@@ -681,8 +695,8 @@ void ghid_fill_circle(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord
 	gint w, h, vr;
 	render_priv *priv = gport->render_priv;
 
-	w = gport->width * gport->view.coord_per_px;
-	h = gport->height * gport->view.coord_per_px;
+	w = gport->view.canvas_width * gport->view.coord_per_px;
+	h = gport->view.canvas_height * gport->view.coord_per_px;
 	if (SIDE_X(cx) < gport->view.x0 - radius
 			|| SIDE_X(cx) > gport->view.x0 + w + radius
 			|| SIDE_Y(cy) < gport->view.y0 - radius || SIDE_Y(cy) > gport->view.y0 + h + radius)
@@ -718,8 +732,8 @@ void ghid_fill_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t
 	render_priv *priv = gport->render_priv;
 
 	lw = gc->width;
-	w = gport->width * gport->view.coord_per_px;
-	h = gport->height * gport->view.coord_per_px;
+	w = gport->view.canvas_width * gport->view.coord_per_px;
+	h = gport->view.canvas_height * gport->view.coord_per_px;
 
 	if ((SIDE_X(x1) < gport->view.x0 - lw && SIDE_X(x2) < gport->view.x0 - lw)
 			|| (SIDE_X(x1) > gport->view.x0 + w + lw && SIDE_X(x2) > gport->view.x0 + w + lw)
@@ -748,7 +762,7 @@ void ghid_fill_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t
 static void redraw_region(GdkRectangle * rect)
 {
 	int eleft, eright, etop, ebottom;
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 	render_priv *priv = gport->render_priv;
 
 	if (!gport->pixmap)
@@ -761,8 +775,8 @@ static void redraw_region(GdkRectangle * rect)
 	else {
 		priv->clip_rect.x = 0;
 		priv->clip_rect.y = 0;
-		priv->clip_rect.width = gport->width;
-		priv->clip_rect.height = gport->height;
+		priv->clip_rect.width = gport->view.canvas_width;
+		priv->clip_rect.height = gport->view.canvas_height;
 		priv->clip = pcb_false;
 	}
 
@@ -771,15 +785,18 @@ static void redraw_region(GdkRectangle * rect)
 	set_clip(priv, priv->mask_gc);
 	set_clip(priv, priv->grid_gc);
 
-	region.X1 = MIN(Px(priv->clip_rect.x), Px(priv->clip_rect.x + priv->clip_rect.width + 1));
-	region.Y1 = MIN(Py(priv->clip_rect.y), Py(priv->clip_rect.y + priv->clip_rect.height + 1));
-	region.X2 = MAX(Px(priv->clip_rect.x), Px(priv->clip_rect.x + priv->clip_rect.width + 1));
-	region.Y2 = MAX(Py(priv->clip_rect.y), Py(priv->clip_rect.y + priv->clip_rect.height + 1));
+	ctx.view.X1 = MIN(Px(priv->clip_rect.x), Px(priv->clip_rect.x + priv->clip_rect.width + 1));
+	ctx.view.Y1 = MIN(Py(priv->clip_rect.y), Py(priv->clip_rect.y + priv->clip_rect.height + 1));
+	ctx.view.X2 = MAX(Px(priv->clip_rect.x), Px(priv->clip_rect.x + priv->clip_rect.width + 1));
+	ctx.view.Y2 = MAX(Py(priv->clip_rect.y), Py(priv->clip_rect.y + priv->clip_rect.height + 1));
 
-	region.X1 = MAX(0, MIN(PCB->MaxWidth, region.X1));
-	region.X2 = MAX(0, MIN(PCB->MaxWidth, region.X2));
-	region.Y1 = MAX(0, MIN(PCB->MaxHeight, region.Y1));
-	region.Y2 = MAX(0, MIN(PCB->MaxHeight, region.Y2));
+	ctx.view.X1 = MAX(0, MIN(PCB->MaxWidth, ctx.view.X1));
+	ctx.view.X2 = MAX(0, MIN(PCB->MaxWidth, ctx.view.X2));
+	ctx.view.Y1 = MAX(0, MIN(PCB->MaxHeight, ctx.view.Y1));
+	ctx.view.Y2 = MAX(0, MIN(PCB->MaxHeight, ctx.view.Y2));
+	
+	ctx.force = 0;
+	ctx.content.elem = NULL;
 
 	eleft = Vx(0);
 	eright = Vx(PCB->MaxWidth);
@@ -797,27 +814,27 @@ static void redraw_region(GdkRectangle * rect)
 	}
 
 	if (eleft > 0)
-		gdk_draw_rectangle(gport->drawable, priv->offlimits_gc, 1, 0, 0, eleft, gport->height);
+		gdk_draw_rectangle(gport->drawable, priv->offlimits_gc, 1, 0, 0, eleft, gport->view.canvas_height);
 	else
 		eleft = 0;
-	if (eright < gport->width)
-		gdk_draw_rectangle(gport->drawable, priv->offlimits_gc, 1, eright, 0, gport->width - eright, gport->height);
+	if (eright < gport->view.canvas_width)
+		gdk_draw_rectangle(gport->drawable, priv->offlimits_gc, 1, eright, 0, gport->view.canvas_width - eright, gport->view.canvas_height);
 	else
-		eright = gport->width;
+		eright = gport->view.canvas_width;
 	if (etop > 0)
 		gdk_draw_rectangle(gport->drawable, priv->offlimits_gc, 1, eleft, 0, eright - eleft + 1, etop);
 	else
 		etop = 0;
-	if (ebottom < gport->height)
-		gdk_draw_rectangle(gport->drawable, priv->offlimits_gc, 1, eleft, ebottom, eright - eleft + 1, gport->height - ebottom);
+	if (ebottom < gport->view.canvas_height)
+		gdk_draw_rectangle(gport->drawable, priv->offlimits_gc, 1, eleft, ebottom, eright - eleft + 1, gport->view.canvas_height - ebottom);
 	else
-		ebottom = gport->height;
+		ebottom = gport->view.canvas_height;
 
 	gdk_draw_rectangle(gport->drawable, priv->bg_gc, 1, eleft, etop, eright - eleft + 1, ebottom - etop + 1);
 
 	ghid_draw_bg_image();
 
-	pcb_hid_expose_callback(&ghid_hid, &region, 0);
+	pcb_hid_expose_all(&ghid_hid, &ctx);
 	ghid_draw_grid();
 
 	/* In some cases we are called with the crosshair still off */
@@ -864,8 +881,10 @@ void ghid_invalidate_lr(pcb_coord_t left, pcb_coord_t right, pcb_coord_t top, pc
 
 void ghid_invalidate_all()
 {
-	redraw_region(NULL);
-	ghid_screen_update();
+	if (ghidgui && ghidgui->menu_bar) {
+		redraw_region(NULL);
+		ghid_screen_update();
+	}
 }
 
 void ghid_notify_crosshair_change(pcb_bool changes_complete)
@@ -940,8 +959,8 @@ static void draw_right_cross(GdkGC * xor_gc, gint x, gint y)
 {
 	GdkWindow *window = gtk_widget_get_window(gport->drawing_area);
 
-	gdk_draw_line(window, xor_gc, x, 0, x, gport->height);
-	gdk_draw_line(window, xor_gc, 0, y, gport->width, y);
+	gdk_draw_line(window, xor_gc, x, 0, x, gport->view.canvas_height);
+	gdk_draw_line(window, xor_gc, 0, y, gport->view.canvas_width, y);
 }
 
 static void draw_slanted_cross(GdkGC * xor_gc, gint x, gint y)
@@ -949,24 +968,24 @@ static void draw_slanted_cross(GdkGC * xor_gc, gint x, gint y)
 	GdkWindow *window = gtk_widget_get_window(gport->drawing_area);
 	gint x0, y0, x1, y1;
 
-	x0 = x + (gport->height - y);
-	x0 = MAX(0, MIN(x0, gport->width));
+	x0 = x + (gport->view.canvas_height - y);
+	x0 = MAX(0, MIN(x0, gport->view.canvas_width));
 	x1 = x - y;
-	x1 = MAX(0, MIN(x1, gport->width));
-	y0 = y + (gport->width - x);
-	y0 = MAX(0, MIN(y0, gport->height));
+	x1 = MAX(0, MIN(x1, gport->view.canvas_width));
+	y0 = y + (gport->view.canvas_width - x);
+	y0 = MAX(0, MIN(y0, gport->view.canvas_height));
 	y1 = y - x;
-	y1 = MAX(0, MIN(y1, gport->height));
+	y1 = MAX(0, MIN(y1, gport->view.canvas_height));
 	gdk_draw_line(window, xor_gc, x0, y0, x1, y1);
 
-	x0 = x - (gport->height - y);
-	x0 = MAX(0, MIN(x0, gport->width));
+	x0 = x - (gport->view.canvas_height - y);
+	x0 = MAX(0, MIN(x0, gport->view.canvas_width));
 	x1 = x + y;
-	x1 = MAX(0, MIN(x1, gport->width));
+	x1 = MAX(0, MIN(x1, gport->view.canvas_width));
 	y0 = y + x;
-	y0 = MAX(0, MIN(y0, gport->height));
-	y1 = y - (gport->width - x);
-	y1 = MAX(0, MIN(y1, gport->height));
+	y0 = MAX(0, MIN(y0, gport->view.canvas_height));
+	y1 = y - (gport->view.canvas_width - x);
+	y1 = MAX(0, MIN(y1, gport->view.canvas_height));
 	gdk_draw_line(window, xor_gc, x0, y0, x1, y1);
 }
 
@@ -976,44 +995,44 @@ static void draw_dozen_cross(GdkGC * xor_gc, gint x, gint y)
 	gint x0, y0, x1, y1;
 	gdouble tan60 = sqrt(3);
 
-	x0 = x + (gport->height - y) / tan60;
-	x0 = MAX(0, MIN(x0, gport->width));
+	x0 = x + (gport->view.canvas_height - y) / tan60;
+	x0 = MAX(0, MIN(x0, gport->view.canvas_width));
 	x1 = x - y / tan60;
-	x1 = MAX(0, MIN(x1, gport->width));
-	y0 = y + (gport->width - x) * tan60;
-	y0 = MAX(0, MIN(y0, gport->height));
+	x1 = MAX(0, MIN(x1, gport->view.canvas_width));
+	y0 = y + (gport->view.canvas_width - x) * tan60;
+	y0 = MAX(0, MIN(y0, gport->view.canvas_height));
 	y1 = y - x * tan60;
-	y1 = MAX(0, MIN(y1, gport->height));
+	y1 = MAX(0, MIN(y1, gport->view.canvas_height));
 	gdk_draw_line(window, xor_gc, x0, y0, x1, y1);
 
-	x0 = x + (gport->height - y) * tan60;
-	x0 = MAX(0, MIN(x0, gport->width));
+	x0 = x + (gport->view.canvas_height - y) * tan60;
+	x0 = MAX(0, MIN(x0, gport->view.canvas_width));
 	x1 = x - y * tan60;
-	x1 = MAX(0, MIN(x1, gport->width));
-	y0 = y + (gport->width - x) / tan60;
-	y0 = MAX(0, MIN(y0, gport->height));
+	x1 = MAX(0, MIN(x1, gport->view.canvas_width));
+	y0 = y + (gport->view.canvas_width - x) / tan60;
+	y0 = MAX(0, MIN(y0, gport->view.canvas_height));
 	y1 = y - x / tan60;
-	y1 = MAX(0, MIN(y1, gport->height));
+	y1 = MAX(0, MIN(y1, gport->view.canvas_height));
 	gdk_draw_line(window, xor_gc, x0, y0, x1, y1);
 
-	x0 = x - (gport->height - y) / tan60;
-	x0 = MAX(0, MIN(x0, gport->width));
+	x0 = x - (gport->view.canvas_height - y) / tan60;
+	x0 = MAX(0, MIN(x0, gport->view.canvas_width));
 	x1 = x + y / tan60;
-	x1 = MAX(0, MIN(x1, gport->width));
+	x1 = MAX(0, MIN(x1, gport->view.canvas_width));
 	y0 = y + x * tan60;
-	y0 = MAX(0, MIN(y0, gport->height));
-	y1 = y - (gport->width - x) * tan60;
-	y1 = MAX(0, MIN(y1, gport->height));
+	y0 = MAX(0, MIN(y0, gport->view.canvas_height));
+	y1 = y - (gport->view.canvas_width - x) * tan60;
+	y1 = MAX(0, MIN(y1, gport->view.canvas_height));
 	gdk_draw_line(window, xor_gc, x0, y0, x1, y1);
 
-	x0 = x - (gport->height - y) * tan60;
-	x0 = MAX(0, MIN(x0, gport->width));
+	x0 = x - (gport->view.canvas_height - y) * tan60;
+	x0 = MAX(0, MIN(x0, gport->view.canvas_width));
 	x1 = x + y * tan60;
-	x1 = MAX(0, MIN(x1, gport->width));
+	x1 = MAX(0, MIN(x1, gport->view.canvas_width));
 	y0 = y + x / tan60;
-	y0 = MAX(0, MIN(y0, gport->height));
-	y1 = y - (gport->width - x) / tan60;
-	y1 = MAX(0, MIN(y1, gport->height));
+	y0 = MAX(0, MIN(y0, gport->view.canvas_height));
+	y1 = y - (gport->view.canvas_width - x) / tan60;
+	y1 = MAX(0, MIN(y1, gport->view.canvas_height));
 	gdk_draw_line(window, xor_gc, x0, y0, x1, y1);
 }
 
@@ -1039,7 +1058,7 @@ static void show_crosshair(gboolean paint_new_location)
 	static GdkGC *xor_gc;
 	static GdkColor cross_color;
 
-	if (gport->crosshair_x < 0 || ghidgui->creating || !gport->has_entered)
+	if (gport->view.crosshair_x < 0 || ghidgui->creating || !gport->view.has_entered)
 		return;
 
 	if (!xor_gc) {
@@ -1051,8 +1070,8 @@ static void show_crosshair(gboolean paint_new_location)
 		/* FIXME: when CrossColor changed from config */
 		ghid_map_color_string(conf_core.appearance.color.cross, &cross_color);
 	}
-	x = DRAW_X(gport->crosshair_x);
-	y = DRAW_Y(gport->crosshair_y);
+	x = DRAW_X(&gport->view, gport->view.crosshair_x);
+	y = DRAW_Y(&gport->view, gport->view.crosshair_y);
 
 	gdk_gc_set_foreground(xor_gc, &cross_color);
 
@@ -1081,7 +1100,7 @@ void ghid_shutdown_renderer(GHidPort * port)
 	port->render_priv = NULL;
 }
 
-void ghid_init_drawing_widget(GtkWidget * widget, GHidPort * port)
+void ghid_init_drawing_widget(GtkWidget * widget, void * port)
 {
 }
 
@@ -1103,7 +1122,7 @@ void ghid_drawing_area_configure_hook(GHidPort * port)
 
 	if (port->mask) {
 		gdk_pixmap_unref(port->mask);
-		port->mask = gdk_pixmap_new(0, port->width, port->height, 1);
+		port->mask = gdk_pixmap_new(0, port->view.canvas_width, port->view.canvas_height, 1);
 	}
 }
 
@@ -1115,7 +1134,7 @@ void ghid_screen_update(void)
 	if (gport->pixmap == NULL)
 		return;
 
-	gdk_draw_drawable(window, priv->bg_gc, gport->pixmap, 0, 0, 0, 0, gport->width, gport->height);
+	gdk_draw_drawable(window, priv->bg_gc, gport->pixmap, 0, 0, 0, 0, gport->view.canvas_width, gport->view.canvas_height);
 	show_crosshair(TRUE);
 }
 
@@ -1134,50 +1153,98 @@ void ghid_port_drawing_realize_cb(GtkWidget * widget, gpointer data)
 {
 }
 
-gboolean ghid_pinout_preview_expose(GtkWidget * widget, GdkEventExpose * ev)
+gboolean ghid_preview_expose(GtkWidget * widget, GdkEventExpose * ev, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx)
 {
-	GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW(widget);
 	GdkWindow *window = gtk_widget_get_window(widget);
 	GdkDrawable *save_drawable;
 	GtkAllocation allocation;
-	view_data save_view;
+	pcb_gtk_view_t save_view;
 	int save_width, save_height;
-	double xz, yz;
+	double xz, yz, vw, vh;
 	render_priv *priv = gport->render_priv;
 
+	vw = ctx->view.X2 - ctx->view.X1;
+	vh = ctx->view.Y2 - ctx->view.Y1;
+
 	/* Setup drawable and zoom factor for drawing routines
 	 */
 	save_drawable = gport->drawable;
 	save_view = gport->view;
-	save_width = gport->width;
-	save_height = gport->height;
+	save_width = gport->view.canvas_width;
+	save_height = gport->view.canvas_height;
 
 	gtk_widget_get_allocation(widget, &allocation);
-	xz = (double) pinout->x_max / allocation.width;
-	yz = (double) pinout->y_max / allocation.height;
+	xz = vw / (double)allocation.width;
+	yz = vh / (double)allocation.height;
 	if (xz > yz)
 		gport->view.coord_per_px = xz;
 	else
 		gport->view.coord_per_px = yz;
 
 	gport->drawable = window;
-	gport->width = allocation.width;
-	gport->height = allocation.height;
+	gport->view.canvas_width = allocation.width;
+	gport->view.canvas_height = allocation.height;
 	gport->view.width = allocation.width * gport->view.coord_per_px;
 	gport->view.height = allocation.height * gport->view.coord_per_px;
-	gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
-	gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
+	gport->view.x0 = (vw - gport->view.width) / 2 + ctx->view.X1;
+	gport->view.y0 = (vh - gport->view.height) / 2 + ctx->view.Y1;
 
 	/* clear background */
 	gdk_draw_rectangle(window, priv->bg_gc, TRUE, 0, 0, allocation.width, allocation.height);
 
 	/* call the drawing routine */
-	pcb_hid_expose_callback(&ghid_hid, NULL, &pinout->element);
+	expcall(&ghid_hid, ctx);
 
 	gport->drawable = save_drawable;
 	gport->view = save_view;
-	gport->width = save_width;
-	gport->height = save_height;
+	gport->view.canvas_width = save_width;
+	gport->view.canvas_height = save_height;
+
+	return FALSE;
+}
+
+gboolean ghid_preview_draw(GtkWidget * widget, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx)
+{
+	GdkWindow *window = gtk_widget_get_window(widget);
+	GdkDrawable *save_drawable;
+	GtkAllocation allocation;
+	pcb_gtk_view_t save_view;
+	int save_width, save_height;
+	double xz, yz, vw, vh;
+
+	vw = ctx->view.X2 - ctx->view.X1;
+	vh = ctx->view.Y2 - ctx->view.Y1;
+
+	/* Setup drawable and zoom factor for drawing routines
+	 */
+	save_drawable = gport->drawable;
+	save_view = gport->view;
+	save_width = gport->view.canvas_width;
+	save_height = gport->view.canvas_height;
+
+	gtk_widget_get_allocation(widget, &allocation);
+	xz = vw / (double)allocation.width;
+	yz = vh / (double)allocation.height;
+	if (xz > yz)
+		gport->view.coord_per_px = xz;
+	else
+		gport->view.coord_per_px = yz;
+
+	gport->drawable = window;
+	gport->view.canvas_width = allocation.width;
+	gport->view.canvas_height = allocation.height;
+	gport->view.width = allocation.width * gport->view.coord_per_px;
+	gport->view.height = allocation.height * gport->view.coord_per_px;
+	gport->view.x0 = (vw - gport->view.width) / 2 + ctx->view.X1;
+	gport->view.y0 = (vh - gport->view.height) / 2 + ctx->view.Y1;
+
+	/* call the drawing routine */
+	expcall(&ghid_hid, ctx);
+
+	gport->drawable = save_drawable;
+	gport->view = save_view;
+	gport->view.canvas_width = save_width;
+	gport->view.canvas_height = save_height;
 
 	return FALSE;
 }
@@ -1186,15 +1253,15 @@ GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height
 {
 	GdkPixmap *pixmap;
 	GdkDrawable *save_drawable;
-	view_data save_view;
+	pcb_gtk_view_t save_view;
 	int save_width, save_height;
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ectx;
 	render_priv *priv = gport->render_priv;
 
 	save_drawable = gport->drawable;
 	save_view = gport->view;
-	save_width = gport->width;
-	save_height = gport->height;
+	save_width = gport->view.canvas_width;
+	save_height = gport->view.canvas_height;
 
 	pixmap = gdk_pixmap_new(NULL, width, height, depth);
 
@@ -1203,8 +1270,8 @@ GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height
 
 	gport->drawable = pixmap;
 	gport->view.coord_per_px = zoom;
-	gport->width = width;
-	gport->height = height;
+	gport->view.canvas_width = width;
+	gport->view.canvas_height = height;
 	gport->view.width = width * gport->view.coord_per_px;
 	gport->view.height = height * gport->view.coord_per_px;
 	gport->view.x0 = conf_core.editor.view.flip_x ? PCB->MaxWidth - cx : cx;
@@ -1216,22 +1283,25 @@ GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height
 	gdk_draw_rectangle(pixmap, priv->bg_gc, TRUE, 0, 0, width, height);
 
 	/* call the drawing routine */
-	region.X1 = MIN(Px(0), Px(gport->width + 1));
-	region.Y1 = MIN(Py(0), Py(gport->height + 1));
-	region.X2 = MAX(Px(0), Px(gport->width + 1));
-	region.Y2 = MAX(Py(0), Py(gport->height + 1));
+	ectx.view.X1 = MIN(Px(0), Px(gport->view.canvas_width + 1));
+	ectx.view.Y1 = MIN(Py(0), Py(gport->view.canvas_height + 1));
+	ectx.view.X2 = MAX(Px(0), Px(gport->view.canvas_width + 1));
+	ectx.view.Y2 = MAX(Py(0), Py(gport->view.canvas_height + 1));
 
-	region.X1 = MAX(0, MIN(PCB->MaxWidth, region.X1));
-	region.X2 = MAX(0, MIN(PCB->MaxWidth, region.X2));
-	region.Y1 = MAX(0, MIN(PCB->MaxHeight, region.Y1));
-	region.Y2 = MAX(0, MIN(PCB->MaxHeight, region.Y2));
+	ectx.view.X1 = MAX(0, MIN(PCB->MaxWidth, ectx.view.X1));
+	ectx.view.X2 = MAX(0, MIN(PCB->MaxWidth, ectx.view.X2));
+	ectx.view.Y1 = MAX(0, MIN(PCB->MaxHeight, ectx.view.Y1));
+	ectx.view.Y2 = MAX(0, MIN(PCB->MaxHeight, ectx.view.Y2));
 
-	pcb_hid_expose_callback(&ghid_hid, &region, NULL);
+	ectx.force = 0;
+	ectx.content.elem = NULL;
+
+	pcb_hid_expose_all(&ghid_hid, &ectx);
 
 	gport->drawable = save_drawable;
 	gport->view = save_view;
-	gport->width = save_width;
-	gport->height = save_height;
+	gport->view.canvas_width = save_width;
+	gport->view.canvas_height = save_height;
 
 	return pixmap;
 }
@@ -1256,23 +1326,6 @@ void ghid_finish_debug_draw(void)
 	 */
 }
 
-pcb_bool ghid_event_to_pcb_coords(int event_x, int event_y, pcb_coord_t * pcb_x, pcb_coord_t * pcb_y)
-{
-	*pcb_x = EVENT_TO_PCB_X(event_x);
-	*pcb_y = EVENT_TO_PCB_Y(event_y);
-
-	return pcb_true;
-}
-
-pcb_bool ghid_pcb_to_event_coords(pcb_coord_t pcb_x, pcb_coord_t pcb_y, int *event_x, int *event_y)
-{
-	*event_x = DRAW_X(pcb_x);
-	*event_y = DRAW_Y(pcb_y);
-
-	return pcb_true;
-}
-
-
 #define LEAD_USER_WIDTH           0.2	/* millimeters */
 #define LEAD_USER_PERIOD          (1000 / 5)	/* 5fps (in ms) */
 #define LEAD_USER_VELOCITY        3.	/* millimeters per second */
diff --git a/src_plugins/hid_gtk/gtkhid-gl.c b/src_plugins/hid_gtk/gtkhid-gl.c
index 2df05c1..ffddc24 100644
--- a/src_plugins/hid_gtk/gtkhid-gl.c
+++ b/src_plugins/hid_gtk/gtkhid-gl.c
@@ -6,7 +6,6 @@
 #include "crosshair.h"
 #include "clip.h"
 #include "gui.h"
-#include "gui-pinout-preview.h"
 
 /* The Linux OpenGL ABI 1.0 spec requires that we define
  * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
@@ -111,7 +110,7 @@ int ghid_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, unsigned
 		int n = PCB->LayerGroups.Number[group];
 		for (idx = 0; idx < n - 1; idx++) {
 			int ni = PCB->LayerGroups.Entries[group][idx];
-			if (ni >= 0 && ni < pcb_max_copper_layer + 2 && PCB->Data->Layer[ni].On)
+			if (ni >= 0 && ni < pcb_max_layer && PCB->Data->Layer[ni].On)
 				break;
 		}
 		idx = PCB->LayerGroups.Entries[group][idx];
@@ -120,19 +119,27 @@ int ghid_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, unsigned
 	end_subcomposite();
 	start_subcomposite();
 
-	if (idx >= 0 && idx < pcb_max_copper_layer + 2) {
+	/* non-virtual layers with special visibility */
+	switch (flags & PCB_LYT_ANYTHING) {
+		case PCB_LYT_MASK:
+			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags))
+				return PCB_FLAG_TEST(PCB_SHOWMASKFLAG, PCB);
+			return 0;
+		case PCB_LYT_PASTE: /* Never draw the paste layer */
+			return 0;
+	}
+
+	/* normal layers */
+	if (idx >= 0 && idx < pcb_max_layer) {
 		priv->trans_lines = pcb_true;
 		return PCB->Data->Layer[idx].On;
 	}
 
+	/* virtual layers */
 	{
 		switch (flags & PCB_LYT_ANYTHING) {
 		case PCB_LYT_INVIS:
 			return PCB->InvisibleObjectsOn;
-		case PCB_LYT_MASK:
-			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags))
-				return PCB_FLAG_TEST(PCB_SHOWMASKFLAG, PCB);
-			return 0;
 		case PCB_LYT_SILK:
 			priv->trans_lines = pcb_true;
 			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags))
@@ -550,7 +557,8 @@ void ghid_invalidate_lr(pcb_coord_t left, pcb_coord_t right, pcb_coord_t top, pc
 
 void ghid_invalidate_all()
 {
-	ghid_draw_area_update(gport, NULL);
+	if (ghidgui && ghidgui->menu_bar)
+		ghid_draw_area_update(gport, NULL);
 }
 
 void ghid_notify_crosshair_change(bool changes_complete)
@@ -684,8 +692,8 @@ void ghid_show_crosshair(gboolean paint_new_location)
 		/* FIXME: when CrossColor changed from config */
 		ghid_map_color_string(conf_core.appearance.color.cross, &cross_color);
 	}
-	x = gport->crosshair_x;
-	y = gport->crosshair_y;
+	x = gport->view.crosshair_x;
+	y = gport->view.crosshair_y;
 	z = 0;
 
 	glEnable(GL_COLOR_LOGIC_OP);
@@ -730,8 +738,9 @@ void ghid_shutdown_renderer(GHidPort * port)
 	port->render_priv = NULL;
 }
 
-void ghid_init_drawing_widget(GtkWidget * widget, GHidPort * port)
+void ghid_init_drawing_widget(GtkWidget * widget, void * port_)
 {
+	GHidPort *port = port_;
 	render_priv *priv = port->render_priv;
 
 	gtk_widget_set_gl_capability(widget, priv->glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
@@ -781,7 +790,7 @@ gboolean ghid_drawing_area_expose_cb(GtkWidget * widget, GdkEventExpose * ev, GH
 {
 	render_priv *priv = port->render_priv;
 	GtkAllocation allocation;
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 
 	gtk_widget_get_allocation(widget, &allocation);
 
@@ -829,15 +838,15 @@ gboolean ghid_drawing_area_expose_cb(GtkWidget * widget, GdkEventExpose * ev, GH
 	glStencilMask(0);
 	glStencilFunc(GL_ALWAYS, 0, 0);
 
-	region.X1 = MIN(Px(ev->area.x), Px(ev->area.x + ev->area.width + 1));
-	region.X2 = MAX(Px(ev->area.x), Px(ev->area.x + ev->area.width + 1));
-	region.Y1 = MIN(Py(ev->area.y), Py(ev->area.y + ev->area.height + 1));
-	region.Y2 = MAX(Py(ev->area.y), Py(ev->area.y + ev->area.height + 1));
+	ctx.view.X1 = MIN(Px(ev->area.x), Px(ev->area.x + ev->area.width + 1));
+	ctx.view.X2 = MAX(Px(ev->area.x), Px(ev->area.x + ev->area.width + 1));
+	ctx.view.Y1 = MIN(Py(ev->area.y), Py(ev->area.y + ev->area.height + 1));
+	ctx.view.Y2 = MAX(Py(ev->area.y), Py(ev->area.y + ev->area.height + 1));
 
-	region.X1 = MAX(0, MIN(PCB->MaxWidth, region.X1));
-	region.X2 = MAX(0, MIN(PCB->MaxWidth, region.X2));
-	region.Y1 = MAX(0, MIN(PCB->MaxHeight, region.Y1));
-	region.Y2 = MAX(0, MIN(PCB->MaxHeight, region.Y2));
+	ctx.view.X1 = MAX(0, MIN(PCB->MaxWidth, ctx.view.X1));
+	ctx.view.X2 = MAX(0, MIN(PCB->MaxWidth, ctx.view.X2));
+	ctx.view.Y1 = MAX(0, MIN(PCB->MaxHeight, ctx.view.Y1));
+	ctx.view.Y2 = MAX(0, MIN(PCB->MaxHeight, ctx.view.Y2));
 
 	glColor3f(port->bg_color.red / 65535., port->bg_color.green / 65535., port->bg_color.blue / 65535.);
 
@@ -852,10 +861,10 @@ gboolean ghid_drawing_area_expose_cb(GtkWidget * widget, GdkEventExpose * ev, GH
 
 	hidgl_init_triangle_array(&buffer);
 	ghid_invalidate_current_gc();
-	pcb_hid_expose_callback(&ghid_hid, &region, 0);
+	pcb_hid_expose_all(&ghid_hid, &ctx.view);
 	hidgl_flush_triangles(&buffer);
 
-	ghid_draw_grid(&region);
+	ghid_draw_grid(&ctx.view);
 
 	ghid_invalidate_current_gc();
 
@@ -891,36 +900,39 @@ void ghid_port_drawing_realize_cb(GtkWidget * widget, gpointer data)
 	return;
 }
 
-gboolean ghid_pinout_preview_expose(GtkWidget * widget, GdkEventExpose * ev)
+gboolean ghid_preview_expose(GtkWidget * widget, GdkEventExpose * ev, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx)
 {
 	GdkGLContext *pGlContext = gtk_widget_get_gl_context(widget);
 	GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable(widget);
-	GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW(widget);
 	GtkAllocation allocation;
-	view_data save_view;
+	pcb_gtk_view_t save_view;
 	int save_width, save_height;
-	double xz, yz;
+	double xz, yz, vw, vh;
+
+	vw = ctx->view.X2 - ctx->view.X1;
+	vh = ctx->view.Y2 - ctx->view.Y1;
 
 	save_view = gport->view;
-	save_width = gport->width;
-	save_height = gport->height;
+	save_width = gport->view.canvas_width;
+	save_height = gport->view.canvas_height;
 
 	/* Setup zoom factor for drawing routines */
 
 	gtk_widget_get_allocation(widget, &allocation);
-	xz = (double) pinout->x_max / allocation.width;
-	yz = (double) pinout->y_max / allocation.height;
+	save_width = gport->view.canvas_width;
+	save_height = gport->view.canvas_height;
+
 	if (xz > yz)
 		gport->view.coord_per_px = xz;
 	else
 		gport->view.coord_per_px = yz;
 
-	gport->width = allocation.width;
-	gport->height = allocation.height;
+	gport->view.canvas_width = allocation.width;
+	gport->view.canvas_height = allocation.height;
 	gport->view.width = allocation.width * gport->view.coord_per_px;
 	gport->view.height = allocation.height * gport->view.coord_per_px;
-	gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
-	gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
+	gport->view.x0 = (vw - gport->view.width) / 2 + ctx->view.X1;
+	gport->view.y0 = (vh - gport->view.height) / 2 + ctx->view.Y1;
 
 	/* make GL-context "current" */
 	if (!gdk_gl_drawable_gl_begin(pGlDrawable, pGlContext)) {
@@ -958,7 +970,9 @@ gboolean ghid_pinout_preview_expose(GtkWidget * widget, GdkEventExpose * ev)
 					 (conf_core.editor.view.flip_y ? -1. : 1.) / gport->view.coord_per_px, 1);
 	glTranslatef(conf_core.editor.view.flip_x ? gport->view.x0 - PCB->MaxWidth :
 							 -gport->view.x0, conf_core.editor.view.flip_y ? gport->view.y0 - PCB->MaxHeight : -gport->view.y0, 0);
-	pcb_hid_expose_callback(&ghid_hid, NULL, &pinout->element);
+
+	expcall(&ghid_hid, ctx);
+
 	hidgl_flush_triangles(&buffer);
 	glPopMatrix();
 
@@ -972,8 +986,100 @@ gboolean ghid_pinout_preview_expose(GtkWidget * widget, GdkEventExpose * ev)
 	gdk_gl_drawable_gl_end(pGlDrawable);
 
 	gport->view = save_view;
-	gport->width = save_width;
-	gport->height = save_height;
+	gport->view.canvas_width = save_width;
+	gport->view.canvas_height = save_height;
+
+	return FALSE;
+}
+
+gboolean ghid_preview_draw(GtkWidget * widget, GdkEventExpose * ev, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx)
+{
+	GdkGLContext *pGlContext = gtk_widget_get_gl_context(widget);
+	GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable(widget);
+	GtkAllocation allocation;
+	pcb_gtk_view_t save_view;
+	int save_width, save_height;
+	double xz, yz, vw, vh;
+
+	vw = ctx->view.X2 - ctx->view.X1;
+	vh = ctx->view.Y2 - ctx->view.Y1;
+
+	save_view = gport->view;
+	save_width = gport->view.canvas_width;
+	save_height = gport->view.canvas_height;
+
+	/* Setup zoom factor for drawing routines */
+
+	gtk_widget_get_allocation(widget, &allocation);
+	save_width = gport->view.canvas_width;
+	save_height = gport->view.canvas_height;
+
+	if (xz > yz)
+		gport->view.coord_per_px = xz;
+	else
+		gport->view.coord_per_px = yz;
+
+	gport->view.canvas_width = allocation.width;
+	gport->view.canvas_height = allocation.height;
+	gport->view.width = allocation.width * gport->view.coord_per_px;
+	gport->view.height = allocation.height * gport->view.coord_per_px;
+	gport->view.x0 = (vw - gport->view.width) / 2 + ctx->view.X1;
+	gport->view.y0 = (vh - gport->view.height) / 2 + ctx->view.Y1;
+
+	/* make GL-context "current" */
+	if (!gdk_gl_drawable_gl_begin(pGlDrawable, pGlContext)) {
+		return FALSE;
+	}
+	gport->render_priv->in_context = pcb_true;
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	glViewport(0, 0, allocation.width, allocation.height);
+
+	glEnable(GL_SCISSOR_TEST);
+	glScissor(ev->area.x, allocation.height - ev->area.height - ev->area.y, ev->area.width, ev->area.height);
+
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	glOrtho(0, allocation.width, allocation.height, 0, 0, 100);
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+	glTranslatef(0.0f, 0.0f, -Z_NEAR);
+
+	glClearColor(gport->bg_color.red / 65535., gport->bg_color.green / 65535., gport->bg_color.blue / 65535., 1.);
+	glStencilMask(~0);
+	glClearStencil(0);
+	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+	hidgl_reset_stencil_usage();
+#error TODO: remove clearing
+	/* call the drawing routine */
+	hidgl_init_triangle_array(&buffer);
+	ghid_invalidate_current_gc();
+	glPushMatrix();
+	glScalef((conf_core.editor.view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
+					 (conf_core.editor.view.flip_y ? -1. : 1.) / gport->view.coord_per_px, 1);
+	glTranslatef(conf_core.editor.view.flip_x ? gport->view.x0 - PCB->MaxWidth :
+							 -gport->view.x0, conf_core.editor.view.flip_y ? gport->view.y0 - PCB->MaxHeight : -gport->view.y0, 0);
+
+	expcall(&ghid_hid, ctx);
+
+	hidgl_flush_triangles(&buffer);
+	glPopMatrix();
+
+	if (gdk_gl_drawable_is_double_buffered(pGlDrawable))
+		gdk_gl_drawable_swap_buffers(pGlDrawable);
+	else
+		glFlush();
+
+	/* end drawing to current GL-context */
+	gport->render_priv->in_context = pcb_false;
+	gdk_gl_drawable_gl_end(pGlDrawable);
+
+	gport->view = save_view;
+	gport->view.canvas_width = save_width;
+	gport->view.canvas_height = save_height;
 
 	return FALSE;
 }
@@ -986,13 +1092,13 @@ GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height
 	GdkGLPixmap *glpixmap;
 	GdkGLContext *glcontext;
 	GdkGLDrawable *gldrawable;
-	view_data save_view;
+	pcb_gtk_view_t save_view;
 	int save_width, save_height;
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 
 	save_view = gport->view;
-	save_width = gport->width;
-	save_height = gport->height;
+	save_width = gport->view.canvas_width;
+	save_height = gport->view.canvas_height;
 
 	/* Setup rendering context for drawing routines
 	 */
@@ -1007,8 +1113,8 @@ GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height
 	/* Setup zoom factor for drawing routines */
 
 	gport->view.coord_per_px = zoom;
-	gport->width = width;
-	gport->height = height;
+	gport->view.canvas_width = width;
+	gport->view.canvas_height = height;
 	gport->view.width = width * gport->view.coord_per_px;
 	gport->view.height = height * gport->view.coord_per_px;
 	gport->view.x0 = conf_core.editor.view.flip_x ? PCB->MaxWidth - cx : cx;
@@ -1052,17 +1158,17 @@ GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height
 	glTranslatef(gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
 							 -gport->view.x0, gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight : -gport->view.y0, 0);
 
-	region.X1 = MIN(Px(0), Px(gport->width + 1));
-	region.Y1 = MIN(Py(0), Py(gport->height + 1));
-	region.X2 = MAX(Px(0), Px(gport->width + 1));
-	region.Y2 = MAX(Py(0), Py(gport->height + 1));
+	ctx.view.X1 = MIN(Px(0), Px(gport->view.canvas_width + 1));
+	ctx.view.Y1 = MIN(Py(0), Py(gport->view.canvas_height + 1));
+	ctx.view.X2 = MAX(Px(0), Px(gport->view.canvas_width + 1));
+	ctx.view.Y2 = MAX(Py(0), Py(gport->view.canvas_height + 1));
 
-	region.X1 = MAX(0, MIN(PCB->MaxWidth, region.X1));
-	region.X2 = MAX(0, MIN(PCB->MaxWidth, region.X2));
-	region.Y1 = MAX(0, MIN(PCB->MaxHeight, region.Y1));
-	region.Y2 = MAX(0, MIN(PCB->MaxHeight, region.Y2));
+	ctx.view.X1 = MAX(0, MIN(PCB->MaxWidth, ctx.view.X1));
+	ctx.view.X2 = MAX(0, MIN(PCB->MaxWidth, ctx.view.X2));
+	ctx.view.Y1 = MAX(0, MIN(PCB->MaxHeight, ctx.view.Y1));
+	ctx.view.Y2 = MAX(0, MIN(PCB->MaxHeight, ctx.view.Y2));
 
-	pcb_hid_expose_callback(&ghid_hid, &region, NULL);
+	pcb_hid_expose_all(&ghid_hid, &ctx.view);
 	hidgl_flush_triangles(&buffer);
 	glPopMatrix();
 
@@ -1078,8 +1184,8 @@ GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height
 	g_object_unref(glcontext);
 
 	gport->view = save_view;
-	gport->width = save_width;
-	gport->height = save_height;
+	gport->view.canvas_width = save_width;
+	gport->view.canvas_height = save_height;
 
 	return pixmap;
 }
@@ -1139,23 +1245,6 @@ void ghid_finish_debug_draw(void)
 	ghid_end_drawing(gport);
 }
 
-bool ghid_event_to_pcb_coords(int event_x, int event_y, pcb_coord_t * pcb_x, pcb_coord_t * pcb_y)
-{
-	*pcb_x = EVENT_TO_PCB_X(event_x);
-	*pcb_y = EVENT_TO_PCB_Y(event_y);
-
-	return pcb_true;
-}
-
-bool ghid_pcb_to_event_coords(pcb_coord_t pcb_x, pcb_coord_t pcb_y, int *event_x, int *event_y)
-{
-	*event_x = DRAW_X(pcb_x);
-	*event_y = DRAW_Y(pcb_y);
-
-	return pcb_true;
-}
-
-
 #define LEAD_USER_WIDTH           0.2	/* millimeters */
 #define LEAD_USER_PERIOD          (1000 / 20)	/* 20fps (in ms) */
 #define LEAD_USER_VELOCITY        3.	/* millimeters per second */
diff --git a/src_plugins/hid_gtk/gtkhid-main.c b/src_plugins/hid_gtk/gtkhid-main.c
index ac4f232..b03668a 100644
--- a/src_plugins/hid_gtk/gtkhid-main.c
+++ b/src_plugins/hid_gtk/gtkhid-main.c
@@ -25,36 +25,48 @@
 #include "misc_util.h"
 #include "compat_misc.h"
 #include "layer.h"
-#include "ghid-search.h"
 #include "compat_nls.h"
 #include "layer_vis.h"
 
-#include "gtkhid.h"
+#include "gtkhid-main.h"
+
+/* AV: Care to circular includes !!!? */
+#include "../src_plugins/lib_gtk_common/act_fileio.h"
+#include "../src_plugins/lib_gtk_common/act_print.h"
+#include "../src_plugins/lib_gtk_common/bu_status_line.h"
+#include "../src_plugins/lib_gtk_common/ui_zoompan.h"
+#include "../src_plugins/lib_gtk_common/util_block_hook.h"
+#include "../src_plugins/lib_gtk_common/util_timer.h"
+#include "../src_plugins/lib_gtk_common/util_watch.h"
+#include "../src_plugins/lib_gtk_common/dlg_about.h"
+#include "../src_plugins/lib_gtk_common/dlg_attribute.h"
+#include "../src_plugins/lib_gtk_common/dlg_confirm.h"
+#include "../src_plugins/lib_gtk_common/dlg_export.h"
+#include "../src_plugins/lib_gtk_common/dlg_file_chooser.h"
+#include "../src_plugins/lib_gtk_common/dlg_input.h"
+#include "../src_plugins/lib_gtk_common/dlg_message.h"
+#include "../src_plugins/lib_gtk_common/dlg_print.h"
+#include "../src_plugins/lib_gtk_common/dlg_progress.h"
+#include "../src_plugins/lib_gtk_common/dlg_report.h"
+#include "../src_plugins/lib_gtk_common/dlg_pinout.h"
+#include "../src_plugins/lib_gtk_common/dlg_search.h"
+#include "../src_plugins/lib_gtk_common/in_mouse.h"
+
+const char *ghid_cookie = "gtk hid";
+const char *ghid_menu_cookie = "gtk hid menu";
 
 conf_hid_id_t ghid_conf_id = -1;
 conf_hid_id_t ghid_menuconf_id = -1;
 GdkModifierType ghid_glob_mask;
 
-static void pan_common(GHidPort * port)
+static void ghid_get_view_size(pcb_coord_t * width, pcb_coord_t * height)
 {
-	int event_x, event_y;
-
-	/* We need to fix up the PCB coordinates corresponding to the last
-	 * event so convert it back to event coordinates temporarily. */
-	ghid_pcb_to_event_coords(gport->pcb_x, gport->pcb_y, &event_x, &event_y);
-
-	/* Don't pan so far the board is completely off the screen */
-	port->view.x0 = MAX(-port->view.width, port->view.x0);
-	port->view.y0 = MAX(-port->view.height, port->view.y0);
-	port->view.x0 = MIN(port->view.x0, PCB->MaxWidth);
-	port->view.y0 = MIN(port->view.y0, PCB->MaxHeight);
-
-	/* Fix up noted event coordinates to match where we clamped. Alternatively
-	 * we could call ghid_note_event_location (NULL); to get a new pointer
-	 * location, but this costs us an xserver round-trip (on X11 platforms)
-	 */
-	ghid_event_to_pcb_coords(event_x, event_y, &gport->pcb_x, &gport->pcb_y);
+	*width = gport->view.width;
+	*height = gport->view.height;
+}
 
+void ghid_pan_common(void)
+{
 	ghidgui->adjustment_changed_holdoff = TRUE;
 	gtk_range_set_value(GTK_RANGE(ghidgui->h_range), gport->view.x0);
 	gtk_range_set_value(GTK_RANGE(ghidgui->v_range), gport->view.y0);
@@ -63,183 +75,30 @@ static void pan_common(GHidPort * port)
 	ghid_port_ranges_changed();
 }
 
-static void ghid_pan_view_abs(pcb_coord_t pcb_x, pcb_coord_t pcb_y, int widget_x, int widget_y)
-{
-	gport->view.x0 = SIDE_X(pcb_x) - widget_x * gport->view.coord_per_px;
-	gport->view.y0 = SIDE_Y(pcb_y) - widget_y * gport->view.coord_per_px;
-
-	pan_common(gport);
-}
-
-void ghid_pan_view_rel(pcb_coord_t dx, pcb_coord_t dy)
+void ghid_port_button_press_main(void)
 {
-	gport->view.x0 += dx;
-	gport->view.y0 += dy;
-
-	pan_common(gport);
+	ghid_invalidate_all();
+	ghid_window_set_name_label(PCB->Name);
+	ghid_set_status_line_label();
+	if (!gport->view.panning)
+		g_idle_add(ghid_idle_cb, NULL);
 }
 
-
-/* gport->view.coord_per_px:
- * zoom value is PCB units per screen pixel.  Larger numbers mean zooming
- * out - the largest value means you are looking at the whole board.
- *
- * gport->view_width and gport->view_height are in PCB coordinates
- */
-
-#define ALLOW_ZOOM_OUT_BY 10		/* Arbitrary, and same as the lesstif HID MAX_ZOOM_SCALE */
-static void ghid_zoom_view_abs(pcb_coord_t center_x, pcb_coord_t center_y, double new_zoom)
+void ghid_port_button_release_main(void)
 {
-	double min_zoom, max_zoom;
-	double xtmp, ytmp;
-	pcb_coord_t cmaxx, cmaxy;
-
-	/* Limit the "minimum" zoom constant (maximum zoom), at 1 pixel per PCB
-	 * unit, and set the "maximum" zoom constant (minimum zoom), such that
-	 * the entire board just fits inside the viewport
-	 */
-	min_zoom = 200;
-	max_zoom = MAX(PCB->MaxWidth / gport->width, PCB->MaxHeight / gport->height) * ALLOW_ZOOM_OUT_BY;
-	new_zoom = MIN(MAX(min_zoom, new_zoom), max_zoom);
-
-	if ((new_zoom > max_zoom) || (new_zoom < min_zoom))
-		return;
-
-	if (gport->view.coord_per_px == new_zoom)
-		return;
-
-	/* Do not allow zoom level that'd overflow the coord type */
-	cmaxx = gport->width  * (new_zoom / 2.0);
-	cmaxy = gport->height * (new_zoom / 2.0);
-	if ((cmaxx >= COORD_MAX/2) || (cmaxy >= COORD_MAX/2)) {
-		return;
-	}
-
-	xtmp = (SIDE_X(center_x) - gport->view.x0) / (double) gport->view.width;
-	ytmp = (SIDE_Y(center_y) - gport->view.y0) / (double) gport->view.height;
-
-	gport->view.coord_per_px = new_zoom;
-	pcb_pixel_slop = new_zoom;
-	ghid_port_ranges_scale();
-
-	gport->view.x0 = SIDE_X(center_x) - xtmp * gport->view.width;
-	gport->view.y0 = SIDE_Y(center_y) - ytmp * gport->view.height;
-
-	pan_common(gport);
+	pcb_adjust_attached_objects();
+	ghid_invalidate_all();
 
+	ghid_window_set_name_label(PCB->Name);
 	ghid_set_status_line_label();
+	g_idle_add(ghid_idle_cb, NULL);
 }
 
-static void ghid_zoom_view_rel(pcb_coord_t center_x, pcb_coord_t center_y, double factor)
+void ghid_mode_cursor_main(int mode)
 {
-	ghid_zoom_view_abs(center_x, center_y, gport->view.coord_per_px * factor);
+	ghid_mode_cursor(&gport->mouse, mode);
 }
 
-static void ghid_zoom_view_fit(void)
-{
-	ghid_pan_view_abs(SIDE_X(0), SIDE_Y(0), 0, 0);
-	ghid_zoom_view_abs(SIDE_X(0), SIDE_Y(0), MAX(PCB->MaxWidth / gport->width, PCB->MaxHeight / gport->height));
-}
-
-static void ghid_flip_view(pcb_coord_t center_x, pcb_coord_t center_y, pcb_bool flip_x, pcb_bool flip_y)
-{
-	int widget_x, widget_y;
-
-	pcb_draw_inhibit_inc();
-
-	/* Work out where on the screen the flip point is */
-	ghid_pcb_to_event_coords(center_x, center_y, &widget_x, &widget_y);
-
-	conf_set_design("editor/view/flip_x", "%d", conf_core.editor.view.flip_x != flip_x);
-	conf_set_design("editor/view/flip_y", "%d", conf_core.editor.view.flip_y != flip_y);
-
-	/* Pan the board so the center location remains in the same place */
-	ghid_pan_view_abs(center_x, center_y, widget_x, widget_y);
-
-	pcb_draw_inhibit_dec();
-
-	ghid_invalidate_all();
-}
-
-/* ------------------------------------------------------------ */
-
-static const char zoom_syntax[] = "Zoom()\n" "Zoom(factor)";
-
-
-static const char zoom_help[] = N_("Various zoom factor changes.");
-
-/* %start-doc actions Zoom
-Changes the zoom (magnification) of the view of the board.  If no
-arguments are passed, the view is scaled such that the board just fits
-inside the visible window (i.e. ``view all'').  Otherwise,
- at var{factor} specifies a change in zoom factor.  It may be prefixed by
- at code{+}, @code{-}, or @code{=} to change how the zoom factor is
-modified.  The @var{factor} is a floating point number, such as
- at code{1.5} or @code{0.75}.
-
- at table @code
-
- at item + at var{factor}
-Values greater than 1.0 cause the board to be drawn smaller; more of
-the board will be visible.  Values between 0.0 and 1.0 cause the board
-to be drawn bigger; less of the board will be visible.
-
- at item - at var{factor}
-Values greater than 1.0 cause the board to be drawn bigger; less of
-the board will be visible.  Values between 0.0 and 1.0 cause the board
-to be drawn smaller; more of the board will be visible.
-
- at item =@var{factor}
-
-The @var{factor} is an absolute zoom factor; the unit for this value
-is "PCB units per screen pixel".  Since PCB units are 0.01 mil, a
- at var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
-about the actual resolution of most screens - resulting in an "actual
-size" board.  Similarly, a @var{factor} of 100 gives you a 10x actual
-size.
-
- at end table
-
-Note that zoom factors of zero are silently ignored.
-
-
-
-%end-doc */
-
-static int Zoom(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	const char *vp;
-	double v;
-
-	if (argc > 1)
-		PCB_AFAIL(zoom);
-
-	if (argc < 1) {
-		ghid_zoom_view_fit();
-		return 0;
-	}
-
-	vp = argv[0];
-	if (*vp == '+' || *vp == '-' || *vp == '=')
-		vp++;
-	v = g_ascii_strtod(vp, 0);
-	if (v <= 0)
-		return 1;
-	switch (argv[0][0]) {
-	case '-':
-		ghid_zoom_view_rel(x, y, 1 / v);
-		break;
-	default:
-	case '+':
-		ghid_zoom_view_rel(x, y, v);
-		break;
-	case '=':
-		ghid_zoom_view_abs(x, y, v);
-		break;
-	}
-
-	return 0;
-}
 
 /* ------------------------------------------------------------ */
 
@@ -250,7 +109,7 @@ void ghid_calibrate(double xval, double yval)
 
 static int ghid_gui_is_up = 0;
 
-void ghid_notify_gui_is_up()
+void ghid_notify_gui_is_up(void)
 {
 	ghid_gui_is_up = 1;
 }
@@ -312,10 +171,10 @@ void ghid_set_crosshair(int x, int y, int action)
 
 	ghid_draw_grid_local(x, y);
 
-	if (gport->crosshair_x != x || gport->crosshair_y != y) {
-		ghid_set_cursor_position_labels();
-		gport->crosshair_x = x;
-		gport->crosshair_y = y;
+	if (gport->view.crosshair_x != x || gport->view.crosshair_y != y) {
+		ghid_set_cursor_position_labels(&ghidgui->cps, conf_hid_gtk.plugins.hid_gtk.compact_vertical);
+		gport->view.crosshair_x = x;
+		gport->view.crosshair_y = y;
 
 		/* FIXME - does this trigger the idle_proc stuff?  It is in the
 		 * lesstif HID.  Maybe something is needed here?
@@ -348,8 +207,8 @@ void ghid_set_crosshair(int x, int y, int action)
 		widget_x = pointer_x - offset_x;
 		widget_y = pointer_y - offset_y;
 
-		ghid_event_to_pcb_coords(widget_x, widget_y, &pcb_x, &pcb_y);
-		ghid_pan_view_abs(pcb_x, pcb_y, widget_x, widget_y);
+		pcb_gtk_coords_event2pcb(&gport->view, widget_x, widget_y, &pcb_x, &pcb_y);
+		pcb_gtk_pan_view_abs(&gport->view, pcb_x, pcb_y, widget_x, widget_y);
 
 		/* Just in case we couldn't pan the board the whole way,
 		 * we warp the pointer to where the crosshair DID land.
@@ -359,7 +218,7 @@ void ghid_set_crosshair(int x, int y, int action)
 	case HID_SC_WARP_POINTER:
 		screen = gdk_display_get_default_screen(display);
 
-		ghid_pcb_to_event_coords(x, y, &widget_x, &widget_y);
+		pcb_gtk_coords_pcb2event(&gport->view, x, y, &widget_x, &widget_y);
 
 		pointer_x = offset_x + widget_x;
 		pointer_y = offset_y + widget_y;
@@ -370,241 +229,31 @@ void ghid_set_crosshair(int x, int y, int action)
 	}
 }
 
-typedef struct {
-	void (*func) (pcb_hidval_t);
-	guint id;
-	pcb_hidval_t user_data;
-} GuiTimer;
-
-	/* We need a wrapper around the hid timer because a gtk timer needs
-	   |  to return FALSE else the timer will be restarted.
-	 */
-static gboolean ghid_timer(GuiTimer * timer)
-{
-	(*timer->func) (timer->user_data);
-	ghid_mode_cursor(conf_core.editor.mode);
-	return FALSE;									/* Turns timer off */
-}
-
-pcb_hidval_t ghid_add_timer(void (*func) (pcb_hidval_t user_data), unsigned long milliseconds, pcb_hidval_t user_data)
-{
-	GuiTimer *timer = g_new0(GuiTimer, 1);
-	pcb_hidval_t ret;
-
-	timer->func = func;
-	timer->user_data = user_data;
-	timer->id = g_timeout_add(milliseconds, (GSourceFunc) ghid_timer, timer);
-	ret.ptr = (void *) timer;
-	return ret;
-}
-
-void ghid_stop_timer(pcb_hidval_t timer)
-{
-	void *ptr = timer.ptr;
-
-	g_source_remove(((GuiTimer *) ptr)->id);
-	g_free(ptr);
-}
-
-typedef struct {
-	void (*func) (pcb_hidval_t, int, unsigned int, pcb_hidval_t);
-	pcb_hidval_t user_data;
-	int fd;
-	GIOChannel *channel;
-	gint id;
-} GuiWatch;
-
-	/* We need a wrapper around the hid file watch to pass the correct flags
-	 */
-static gboolean ghid_watch(GIOChannel * source, GIOCondition condition, gpointer data)
-{
-	unsigned int pcb_condition = 0;
-	pcb_hidval_t x;
-	GuiWatch *watch = (GuiWatch *) data;
-
-	if (condition & G_IO_IN)
-		pcb_condition |= PCB_WATCH_READABLE;
-	if (condition & G_IO_OUT)
-		pcb_condition |= PCB_WATCH_WRITABLE;
-	if (condition & G_IO_ERR)
-		pcb_condition |= PCB_WATCH_ERROR;
-	if (condition & G_IO_HUP)
-		pcb_condition |= PCB_WATCH_HANGUP;
-
-	x.ptr = (void *) watch;
-	watch->func(x, watch->fd, pcb_condition, watch->user_data);
-	ghid_mode_cursor(conf_core.editor.mode);
-
-	return TRUE;									/* Leave watch on */
-}
-
-pcb_hidval_t
-ghid_watch_file(int fd, unsigned int condition, void (*func) (pcb_hidval_t watch, int fd, unsigned int condition, pcb_hidval_t user_data),
-								pcb_hidval_t user_data)
-{
-	GuiWatch *watch = g_new0(GuiWatch, 1);
-	pcb_hidval_t ret;
-	unsigned int glib_condition = 0;
-
-	if (condition & PCB_WATCH_READABLE)
-		glib_condition |= G_IO_IN;
-	if (condition & PCB_WATCH_WRITABLE)
-		glib_condition |= G_IO_OUT;
-	if (condition & PCB_WATCH_ERROR)
-		glib_condition |= G_IO_ERR;
-	if (condition & PCB_WATCH_HANGUP)
-		glib_condition |= G_IO_HUP;
-
-	watch->func = func;
-	watch->user_data = user_data;
-	watch->fd = fd;
-	watch->channel = g_io_channel_unix_new(fd);
-	watch->id = g_io_add_watch(watch->channel, (GIOCondition) glib_condition, ghid_watch, watch);
-
-	ret.ptr = (void *) watch;
-	return ret;
-}
-
-void ghid_unwatch_file(pcb_hidval_t data)
-{
-	GuiWatch *watch = (GuiWatch *) data.ptr;
-
-	g_io_channel_shutdown(watch->channel, TRUE, NULL);
-	g_io_channel_unref(watch->channel);
-	g_free(watch);
-}
-
-typedef struct {
-	GSource source;
-	void (*func) (pcb_hidval_t user_data);
-	pcb_hidval_t user_data;
-} BlockHookSource;
-
-static gboolean ghid_block_hook_prepare(GSource * source, gint * timeout);
-static gboolean ghid_block_hook_check(GSource * source);
-static gboolean ghid_block_hook_dispatch(GSource * source, GSourceFunc callback, gpointer user_data);
-
-static GSourceFuncs ghid_block_hook_funcs = {
-	ghid_block_hook_prepare,
-	ghid_block_hook_check,
-	ghid_block_hook_dispatch,
-	NULL													/* No destroy notification */
-};
-
-static gboolean ghid_block_hook_prepare(GSource * source, gint * timeout)
-{
-	pcb_hidval_t data = ((BlockHookSource *) source)->user_data;
-	((BlockHookSource *) source)->func(data);
-	return FALSE;
-}
-
-static gboolean ghid_block_hook_check(GSource * source)
-{
-	return FALSE;
-}
-
-static gboolean ghid_block_hook_dispatch(GSource * source, GSourceFunc callback, gpointer user_data)
-{
-	return FALSE;
-}
-
-static pcb_hidval_t ghid_add_block_hook(void (*func) (pcb_hidval_t data), pcb_hidval_t user_data)
-{
-	pcb_hidval_t ret;
-	BlockHookSource *source;
-
-	source = (BlockHookSource *) g_source_new(&ghid_block_hook_funcs, sizeof(BlockHookSource));
-
-	source->func = func;
-	source->user_data = user_data;
-
-	g_source_attach((GSource *) source, NULL);
-
-	ret.ptr = (void *) source;
-	return ret;
-}
-
-static void ghid_stop_block_hook(pcb_hidval_t mlpoll)
-{
-	GSource *source = (GSource *) mlpoll.ptr;
-	g_source_destroy(source);
-}
-
 int ghid_confirm_dialog(const char *msg, ...)
 {
-	int rv = 0;
+	int res;
 	va_list ap;
-	const char *cancelmsg = NULL, *okmsg = NULL;
-	static gint x = -1, y = -1;
-	GtkWidget *dialog;
-	GHidPort *out = &ghid_port;
-
 	va_start(ap, msg);
-	cancelmsg = va_arg(ap, char *);
-	okmsg = va_arg(ap, char *);
+	res = pcb_gtk_dlg_confirm_open(ghid_port.top_window, msg, ap);
 	va_end(ap);
-
-	if (!cancelmsg) {
-		cancelmsg = _("_Cancel");
-		okmsg = _("_OK");
-	}
-
-	dialog = gtk_message_dialog_new(GTK_WINDOW(out->top_window),
-																	(GtkDialogFlags) (GTK_DIALOG_MODAL |
-																										GTK_DIALOG_DESTROY_WITH_PARENT),
-																	GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", msg);
-	gtk_dialog_add_button(GTK_DIALOG(dialog), cancelmsg, GTK_RESPONSE_CANCEL);
-	if (okmsg) {
-		gtk_dialog_add_button(GTK_DIALOG(dialog), okmsg, GTK_RESPONSE_OK);
-	}
-
-	if (x != -1) {
-		gtk_window_move(GTK_WINDOW(dialog), x, y);
-	}
-
-	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
-		rv = 1;
-
-	gtk_window_get_position(GTK_WINDOW(dialog), &x, &y);
-
-	gtk_widget_destroy(dialog);
-	return rv;
+	return res;
 }
 
-int ghid_close_confirm_dialog()
+int ghid_close_confirm_dialog(void)
 {
-	switch (ghid_dialog_close_confirm()) {
-	case GUI_DIALOG_CLOSE_CONFIRM_SAVE:
-		{
-			if (pcb_hid_actionl("Save", NULL)) {	/* Save failed */
-				return 0;								/* Cancel */
-			}
-			else {
-				return 1;								/* Close */
-			}
-		}
-	case GUI_DIALOG_CLOSE_CONFIRM_NOSAVE:
-		{
-			return 1;									/* Close */
-		}
-	case GUI_DIALOG_CLOSE_CONFIRM_CANCEL:
-	default:
-		{
-			return 0;									/* Cancel */
-		}
-	}
+	return pcb_gtk_dlg_confirm_close(ghid_port.top_window);
 }
 
 void ghid_report_dialog(const char *title, const char *msg)
 {
-	ghid_dialog_report(title, msg);
+	pcb_gtk_dlg_report(ghid_port.top_window, title, msg, FALSE);
 }
 
 char *ghid_prompt_for(const char *msg, const char *default_string)
 {
 	char *grv, *rv;
 
-	grv = ghid_dialog_input(msg, default_string);
+	grv = pcb_gtk_dlg_input(msg, default_string, GTK_WINDOW(ghid_port.top_window));
 
 	/* can't assume the caller will do g_free() on it */
 	rv = pcb_strdup(grv);
@@ -612,18 +261,6 @@ char *ghid_prompt_for(const char *msg, const char *default_string)
 	return rv;
 }
 
-/* FIXME -- implement a proper file select dialog */
-#ifdef FIXME
-char *ghid_fileselect(const char *title, const char *descr,
-											const char *default_file, const char *default_ext, const char *history_tag, int flags)
-{
-	char *rv;
-
-	rv = ghid_dialog_input(title, default_file);
-	return rv;
-}
-#endif
-
 void ghid_show_item(void *item)
 {
 	ghid_pinout_window_show(&ghid_port, (pcb_element_t *) item);
@@ -634,173 +271,24 @@ void ghid_beep()
 	gdk_beep();
 }
 
-struct progress_dialog {
-	GtkWidget *dialog;
-	GtkWidget *message;
-	GtkWidget *progress;
-	gint response_id;
-	GMainLoop *loop;
-	gboolean destroyed;
-	gboolean started;
-	GTimer *timer;
-
-	gulong response_handler;
-	gulong destroy_handler;
-	gulong delete_handler;
-};
-
-static void run_response_handler(GtkDialog * dialog, gint response_id, gpointer data)
-{
-	struct progress_dialog *pd = data;
-
-	pd->response_id = response_id;
-}
-
-static gint run_delete_handler(GtkDialog * dialog, GdkEventAny * event, gpointer data)
-{
-	struct progress_dialog *pd = data;
-
-	pd->response_id = GTK_RESPONSE_DELETE_EVENT;
-
-	return TRUE;									/* Do not destroy */
-}
-
-static void run_destroy_handler(GtkDialog * dialog, gpointer data)
-{
-	struct progress_dialog *pd = data;
-
-	pd->destroyed = TRUE;
-}
-
-static struct progress_dialog *make_progress_dialog(void)
+int ghid_progress(int so_far, int total, const char *message)
 {
-	struct progress_dialog *pd;
-	GtkWidget *content_area;
-	GtkWidget *alignment;
-	GtkWidget *vbox;
-
-	pd = g_new0(struct progress_dialog, 1);
-	pd->response_id = GTK_RESPONSE_NONE;
-
-	pd->dialog = gtk_dialog_new_with_buttons(_("Progress"), GTK_WINDOW(gport->top_window),
-																					 /* Modal so nothing else can get events whilst
-																					    the main mainloop isn't running */
-																					 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-																					 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
-
-	gtk_window_set_deletable(GTK_WINDOW(pd->dialog), FALSE);
-	gtk_window_set_skip_pager_hint(GTK_WINDOW(pd->dialog), TRUE);
-	gtk_window_set_skip_taskbar_hint(GTK_WINDOW(pd->dialog), TRUE);
-	gtk_widget_set_size_request(pd->dialog, 300, -1);
-
-	pd->message = gtk_label_new(NULL);
-	gtk_misc_set_alignment(GTK_MISC(pd->message), 0., 0.);
-
-	pd->progress = gtk_progress_bar_new();
-	gtk_widget_set_size_request(pd->progress, -1, 26);
-
-	vbox = gtk_vbox_new(pcb_false, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), pd->message, pcb_true, pcb_true, 8);
-	gtk_box_pack_start(GTK_BOX(vbox), pd->progress, pcb_false, pcb_true, 8);
-
-	alignment = gtk_alignment_new(0., 0., 1., 1.);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 8, 8, 8, 8);
-	gtk_container_add(GTK_CONTAINER(alignment), vbox);
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(pd->dialog));
-	gtk_box_pack_start(GTK_BOX(content_area), alignment, pcb_true, pcb_true, 0);
-
-	gtk_widget_show_all(alignment);
-
-	g_object_ref(pd->dialog);
-	gtk_window_present(GTK_WINDOW(pd->dialog));
-
-	pd->response_handler = g_signal_connect(pd->dialog, "response", G_CALLBACK(run_response_handler), pd);
-	pd->delete_handler = g_signal_connect(pd->dialog, "delete-event", G_CALLBACK(run_delete_handler), pd);
-	pd->destroy_handler = g_signal_connect(pd->dialog, "destroy", G_CALLBACK(run_destroy_handler), pd);
-
-	pd->loop = g_main_loop_new(NULL, FALSE);
-	pd->timer = g_timer_new();
-
-	return pd;
+	return pcb_gtk_dlg_progress(ghid_port.top_window, so_far, total, message);
 }
 
-static void destroy_progress_dialog(struct progress_dialog *pd)
+static char *ghid_fileselect(const char *title, const char *descr, const char *default_file, const char *default_ext, const char *history_tag, int flags)
 {
-	if (pd == NULL)
-		return;
-
-	if (!pd->destroyed) {
-		g_signal_handler_disconnect(pd->dialog, pd->response_handler);
-		g_signal_handler_disconnect(pd->dialog, pd->delete_handler);
-		g_signal_handler_disconnect(pd->dialog, pd->destroy_handler);
-	}
-
-	g_timer_destroy(pd->timer);
-	g_object_unref(pd->dialog);
-	g_main_loop_unref(pd->loop);
-
-	gtk_widget_destroy(pd->dialog);
-
-	pd->loop = NULL;
-	g_free(pd);
+	return pcb_gtk_fileselect(ghid_port.top_window, title, descr, default_file, default_ext, history_tag, flags);
 }
 
-static void handle_progress_dialog_events(struct progress_dialog *pd)
-{
-	GMainContext *context = g_main_loop_get_context(pd->loop);
-
-	/* Process events */
-	while (g_main_context_pending(context)) {
-		g_main_context_iteration(context, FALSE);
-	}
-}
 
-#define MIN_TIME_SEPARATION (50./1000.)	/* 50ms */
-static int ghid_progress(int so_far, int total, const char *message)
+static int ghid_propedit_start(void *pe, int num_props,
+															 const char *(*query) (void *pe, const char *cmd, const char *key, const char *val, int idx))
 {
-	static struct progress_dialog *pd = NULL;
-
-	/* If we are finished, destroy any dialog */
-	if (so_far == 0 && total == 0 && message == NULL) {
-		destroy_progress_dialog(pd);
-		pd = NULL;
-		return 0;
-	}
-
-	if (pd == NULL)
-		pd = make_progress_dialog();
-
-	/* We don't want to keep the underlying process too busy whilst we
-	 * process events. If we get called quickly after the last progress
-	 * update, wait a little bit before we respond - perhaps the next
-	 * time progress is reported.
-
-	 * The exception here is that we always want to process the first
-	 * batch of events after having shown the dialog for the first time
-	 */
-	if (pd->started && g_timer_elapsed(pd->timer, NULL) < MIN_TIME_SEPARATION)
-		return 0;
-
-	gtk_label_set_text(GTK_LABEL(pd->message), message);
-	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pd->progress), (double) so_far / (double) total);
 
-	handle_progress_dialog_events(pd);
-	g_timer_start(pd->timer);
-
-	pd->started = TRUE;
-
-	return (pd->response_id == GTK_RESPONSE_CANCEL || pd->response_id == GTK_RESPONSE_DELETE_EVENT) ? 1 : 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int ghid_propedit_start(void *pe, int num_props, const char *(*query)(void *pe, const char *cmd, const char *key, const char *val, int idx))
-{
-
-	ghidgui->propedit_widget = ghid_propedit_dialog_create(&ghidgui->propedit_dlg);
-	ghidgui->propedit_query = query;
-	ghidgui->propedit_pe = pe;
+	ghidgui->propedit_widget = pcb_gtk_dlg_propedit_create(&ghidgui->propedit_dlg, gport->top_window);
+	ghidgui->propedit_dlg.propedit_query = query;
+	ghidgui->propedit_dlg.propedit_pe = pe;
 	return 0;
 }
 
@@ -811,197 +299,17 @@ static void ghid_propedit_end(void *pe)
 	gtk_widget_destroy(ghidgui->propedit_widget);
 }
 
-static void ghid_propedit_add_stat(void *pe, const char *propname, void *propctx, const char *most_common, const char *min, const char *max, const char *avg)
-{
-	ghid_propedit_prop_add(&ghidgui->propedit_dlg, propname, most_common, min, max, avg);
-}
-
-/* ---------------------------------------------------------------------- */
-
-
-typedef struct {
-	GtkWidget *del;
-	GtkWidget *w_name;
-	GtkWidget *w_value;
-} AttrRow;
-
-static AttrRow *attr_row = 0;
-static int attr_num_rows = 0;
-static int attr_max_rows = 0;
-static pcb_attribute_list_t *attributes_list;
-static GtkWidget *attributes_dialog, *attr_table;
-
-static void attributes_delete_callback(GtkWidget * w, void *v);
-
-#define GA_RESPONSE_REVERT	1
-#define GA_RESPONSE_NEW		2
-
-static void ghid_attr_set_table_size()
-{
-	gtk_table_resize(GTK_TABLE(attr_table), attr_num_rows > 0 ? attr_num_rows : 1, 3);
-}
-
-static void ghid_attributes_need_rows(int new_max)
+static void ghid_propedit_add_stat(void *pe, const char *propname, void *propctx, const char *most_common, const char *min,
+																	 const char *max, const char *avg)
 {
-	if (attr_max_rows < new_max) {
-		if (attr_row)
-			attr_row = (AttrRow *) realloc(attr_row, new_max * sizeof(AttrRow));
-		else
-			attr_row = (AttrRow *) malloc(new_max * sizeof(AttrRow));
-	}
-	while (attr_max_rows < new_max) {
-		/* add [attr_max_rows] */
-		attr_row[attr_max_rows].del = gtk_button_new_with_label("del");
-		gtk_table_attach(GTK_TABLE(attr_table), attr_row[attr_max_rows].del,
-										 0, 1, attr_max_rows, attr_max_rows + 1, (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), GTK_FILL, 0, 0);
-		g_signal_connect(G_OBJECT(attr_row[attr_max_rows].del), "clicked",
-										 G_CALLBACK(attributes_delete_callback), GINT_TO_POINTER(attr_max_rows));
-
-		attr_row[attr_max_rows].w_name = gtk_entry_new();
-		gtk_table_attach(GTK_TABLE(attr_table), attr_row[attr_max_rows].w_name,
-										 1, 2, attr_max_rows, attr_max_rows + 1, (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), GTK_FILL, 0, 0);
-
-		attr_row[attr_max_rows].w_value = gtk_entry_new();
-		gtk_table_attach(GTK_TABLE(attr_table), attr_row[attr_max_rows].w_value,
-										 2, 3, attr_max_rows, attr_max_rows + 1, (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), GTK_FILL, 0, 0);
-
-		attr_max_rows++;
-	}
-
-	/* Manage any previously unused rows we now need to show.  */
-	while (attr_num_rows < new_max) {
-		/* manage attr_num_rows */
-		gtk_widget_show(attr_row[attr_num_rows].del);
-		gtk_widget_show(attr_row[attr_num_rows].w_name);
-		gtk_widget_show(attr_row[attr_num_rows].w_value);
-		attr_num_rows++;
-	}
-}
-
-static void ghid_attributes_revert()
-{
-	int i;
-
-	ghid_attributes_need_rows(attributes_list->Number);
-
-	/* Unmanage any previously used rows we don't need.  */
-	while (attr_num_rows > attributes_list->Number) {
-		attr_num_rows--;
-		gtk_widget_hide(attr_row[attr_num_rows].del);
-		gtk_widget_hide(attr_row[attr_num_rows].w_name);
-		gtk_widget_hide(attr_row[attr_num_rows].w_value);
-	}
-
-	/* Fill in values */
-	for (i = 0; i < attributes_list->Number; i++) {
-		/* create row [i] */
-		gtk_entry_set_text(GTK_ENTRY(attr_row[i].w_name), attributes_list->List[i].name);
-		gtk_entry_set_text(GTK_ENTRY(attr_row[i].w_value), attributes_list->List[i].value);
-#if 0
-#endif
-	}
-	ghid_attr_set_table_size();
-}
-
-static void attributes_delete_callback(GtkWidget * w, void *v)
-{
-	int i, n;
-
-	n = GPOINTER_TO_INT(v);
-
-	for (i = n; i < attr_num_rows - 1; i++) {
-		gtk_entry_set_text(GTK_ENTRY(attr_row[i].w_name), gtk_entry_get_text(GTK_ENTRY(attr_row[i + 1].w_name)));
-		gtk_entry_set_text(GTK_ENTRY(attr_row[i].w_value), gtk_entry_get_text(GTK_ENTRY(attr_row[i + 1].w_value)));
-	}
-	attr_num_rows--;
-
-	gtk_widget_hide(attr_row[attr_num_rows].del);
-	gtk_widget_hide(attr_row[attr_num_rows].w_name);
-	gtk_widget_hide(attr_row[attr_num_rows].w_value);
-
-	ghid_attr_set_table_size();
+	pcb_gtk_dlg_propedit_prop_add(&ghidgui->propedit_dlg, propname, most_common, min, max, avg);
 }
 
 static void ghid_attributes(const char *owner, pcb_attribute_list_t * attrs)
 {
-	GtkWidget *content_area;
-	int response;
-
-	attributes_list = attrs;
-
-	attr_max_rows = 0;
-	attr_num_rows = 0;
-
-	attributes_dialog = gtk_dialog_new_with_buttons(owner,
-																									GTK_WINDOW(ghid_port.top_window),
-																									GTK_DIALOG_MODAL,
-																									GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-																									"Revert", GA_RESPONSE_REVERT,
-																									"New", GA_RESPONSE_NEW, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-	attr_table = gtk_table_new(attrs->Number, 3, 0);
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(attributes_dialog));
-	gtk_box_pack_start(GTK_BOX(content_area), attr_table, FALSE, FALSE, 0);
-
-	gtk_widget_show(attr_table);
-
-	ghid_attributes_revert();
-
-	while (1) {
-		response = gtk_dialog_run(GTK_DIALOG(attributes_dialog));
-
-		if (response == GTK_RESPONSE_CANCEL)
-			break;
-
-		if (response == GTK_RESPONSE_OK) {
-			int i;
-			/* Copy the values back */
-			for (i = 0; i < attributes_list->Number; i++) {
-				if (attributes_list->List[i].name)
-					free(attributes_list->List[i].name);
-				if (attributes_list->List[i].value)
-					free(attributes_list->List[i].value);
-			}
-			if (attributes_list->Max < attr_num_rows) {
-				int sz = attr_num_rows * sizeof(pcb_attribute_t);
-				if (attributes_list->List == NULL)
-					attributes_list->List = (pcb_attribute_t *) malloc(sz);
-				else
-					attributes_list->List = (pcb_attribute_t *) realloc(attributes_list->List, sz);
-				attributes_list->Max = attr_num_rows;
-			}
-			for (i = 0; i < attr_num_rows; i++) {
-				attributes_list->List[i].name = pcb_strdup(gtk_entry_get_text(GTK_ENTRY(attr_row[i].w_name)));
-				attributes_list->List[i].value = pcb_strdup(gtk_entry_get_text(GTK_ENTRY(attr_row[i].w_value)));
-				attributes_list->Number = attr_num_rows;
-			}
-
-			break;
-		}
-
-		if (response == GA_RESPONSE_REVERT) {
-			/* Revert */
-			ghid_attributes_revert();
-		}
-
-		if (response == GA_RESPONSE_NEW) {
-			ghid_attributes_need_rows(attr_num_rows + 1);	/* also bumps attr_num_rows */
-
-			gtk_entry_set_text(GTK_ENTRY(attr_row[attr_num_rows - 1].w_name), "");
-			gtk_entry_set_text(GTK_ENTRY(attr_row[attr_num_rows - 1].w_value), "");
-
-			ghid_attr_set_table_size();
-		}
-	}
-
-	gtk_widget_destroy(attributes_dialog);
-	free(attr_row);
-	attr_row = NULL;
+	pcb_gtk_dlg_attributes(ghid_port.top_window, owner, attrs);
 }
 
-/* ---------------------------------------------------------------------- */
-
 pcb_hid_drc_gui_t ghid_drc_gui = {
 	1,														/* log_drc_overview */
 	0,														/* log_drc_details */
@@ -1010,16 +318,12 @@ pcb_hid_drc_gui_t ghid_drc_gui = {
 	ghid_drc_window_throw_dialog,
 };
 
-extern pcb_hid_attribute_t *ghid_get_export_options(int *);
-
-
 /* ------------------------------------------------------------
  *
  * Actions specific to the GTK HID follow from here
  *
  */
 
-
 /* ------------------------------------------------------------ */
 static const char about_syntax[] = "About()";
 
@@ -1035,7 +339,7 @@ This just pops up a dialog telling the user which version of
 
 static int About(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
-	ghid_dialog_about();
+	pcb_gtk_dlg_about(gport->top_window);
 	return 0;
 }
 
@@ -1063,9 +367,9 @@ static void PointCursor(pcb_bool grabbed)
 		return;
 
 	if (grabbed > 0)
-		ghid_point_cursor();
+		ghid_point_cursor(&gport->mouse);
 	else
-		ghid_mode_cursor(conf_core.editor.mode);
+		ghid_mode_cursor(&gport->mouse, conf_core.editor.mode);
 }
 
 /* ---------------------------------------------------------------------- */
@@ -1075,9 +379,10 @@ static void RouteStylesChanged(void *user_data, int argc, pcb_event_arg_t argv[]
 	if (!ghidgui || !ghidgui->route_style_selector)
 		return;
 
-	ghid_route_style_selector_sync
-		(GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector),
-		 conf_core.design.line_thickness, conf_core.design.via_drilling_hole, conf_core.design.via_thickness, conf_core.design.clearance);
+	pcb_gtk_route_style_sync
+		(GHID_ROUTE_STYLE(ghidgui->route_style_selector),
+		 conf_core.design.line_thickness, conf_core.design.via_drilling_hole, conf_core.design.via_thickness,
+		 conf_core.design.clearance);
 
 	return;
 }
@@ -1096,13 +401,13 @@ static void ev_pcb_changed(void *user_data, int argc, pcb_event_arg_t argv[])
 		return;
 
 	if (ghidgui->route_style_selector) {
-		ghid_route_style_selector_empty(GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector));
-		make_route_style_buttons(GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector));
+		pcb_gtk_route_style_empty(GHID_ROUTE_STYLE(ghidgui->route_style_selector));
+		make_route_style_buttons(GHID_ROUTE_STYLE(ghidgui->route_style_selector));
 	}
 	RouteStylesChanged(0, 0, NULL);
 
 	ghid_port_ranges_scale();
-	ghid_zoom_view_fit();
+	pcb_gtk_zoom_view_fit(&gport->view);
 	ghid_sync_with_new_layout();
 }
 
@@ -1122,355 +427,11 @@ static int Command(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 	return 0;
 }
 
-/* ---------------------------------------------------------------------- */
-
-static char *dup_cwd()
-{
-#if defined (PATH_MAX)
-	char tmp[PATH_MAX+1];
-#else
-	char tmp[8193];
-#endif
-	return pcb_strdup(getcwd(tmp, sizeof(tmp)));
-}
-
-static int Load(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	const char *function;
-	char *name = NULL;
-
-	static gchar *current_element_dir = NULL;
-	static gchar *current_layout_dir = NULL;
-	static gchar *current_netlist_dir = NULL;
-
-	if (!current_element_dir)
-		current_element_dir = dup_cwd();
-	if (!current_layout_dir)
-		current_layout_dir = dup_cwd();
-	if (!current_netlist_dir)
-		current_netlist_dir = dup_cwd();
-
-	/* we've been given the file name */
-	if (argc > 1)
-		return pcb_hid_actionv("LoadFrom", argc, argv);
-
-	function = argc ? argv[0] : "Layout";
-
-	if (pcb_strcasecmp(function, "Netlist") == 0) {
-		name = ghid_dialog_file_select_open(_("Load netlist file"), &current_netlist_dir, conf_core.rc.file_path);
-	}
-	else if (pcb_strcasecmp(function, "ElementToBuffer") == 0) {
-		gchar *path = (gchar *)pcb_fp_default_search_path();
-		name = ghid_dialog_file_select_open(_("Load element to buffer"), &current_element_dir, path);
-	}
-	else if (pcb_strcasecmp(function, "LayoutToBuffer") == 0) {
-		name = ghid_dialog_file_select_open(_("Load layout file to buffer"), &current_layout_dir, conf_core.rc.file_path);
-	}
-	else if (pcb_strcasecmp(function, "Layout") == 0) {
-		name = ghid_dialog_file_select_open(_("Load layout file"), &current_layout_dir, conf_core.rc.file_path);
-	}
-
-	if (name) {
-		if (conf_core.rc.verbose)
-			fprintf(stderr, "Load:  Calling LoadFrom(%s, %s)\n", function, name);
-		pcb_hid_actionl("LoadFrom", function, name, NULL);
-		g_free(name);
-	}
-
-	return 0;
-}
-
-
-/* ---------------------------------------------------------------------- */
-static const char save_syntax[] =
-	"Save()\n" "Save(Layout|LayoutAs)\n" "Save(AllConnections|AllUnusedPins|ElementConnections)\n" "Save(PasteBuffer)";
-
-static const char save_help[] = N_("Save layout and/or element data to a user-selected file.");
-
-/* %start-doc actions Save
-
-This action is a GUI front-end to the core's @code{SaveTo} action
-(@pxref{SaveTo Action}).  If you happen to pass a filename, like
- at code{SaveTo}, then @code{SaveTo} is called directly.  Else, the
-user is prompted for a filename to save, and then @code{SaveTo} is
-called with that filename.
-
-%end-doc */
-
-static int Save(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	const char *function;
-	char *name, *name_in = NULL;
-	const char *prompt;
-	pcb_io_formats_t avail;
-	const char **formats_param = NULL, **extensions_param = NULL;
-	int fmt, *fmt_param = NULL;
-
-	static gchar *current_dir = NULL;
-
-	if (!current_dir)
-		current_dir = dup_cwd();
-
-	if (argc > 1)
-		return pcb_hid_actionv("SaveTo", argc, argv);
-
-	function = argc ? argv[0] : "Layout";
-
-	if (pcb_strcasecmp(function, "Layout") == 0)
-		if (PCB->Filename)
-			return pcb_hid_actionl("SaveTo", "Layout", PCB->Filename, NULL);
-
-	if (pcb_strcasecmp(function, "PasteBuffer") == 0) {
-		int num_fmts, n;
-		prompt = _("Save element as");
-		num_fmts = pcb_io_list(&avail, PCB_IOT_BUFFER, 1, 1, PCB_IOL_EXT_FP);
-		if (num_fmts > 0) {
-			formats_param = (const char **)avail.digest;
-			extensions_param = (const char **)avail.extension;
-			fmt_param = &fmt;
-			fmt = 0;
-			for(n = 0; n < num_fmts; n++) {
-				if (strstr(avail.plug[n]->description, "mainline") != NULL) {
-					fmt = n;
-					name_in = pcb_concat("unnamed.fp", NULL);
-				}
-			}
-		}
-		else {
-			pcb_message(PCB_MSG_ERROR, "Error: no IO plugin avaialble for saving a buffer.");
-			return -1;
-		}
-	}
-	else {
-		int num_fmts, n;
-		prompt = _("Save layout as");
-		num_fmts = pcb_io_list(&avail, PCB_IOT_PCB, 1, 1, PCB_IOL_EXT_BOARD);
-		if (num_fmts > 0) {
-			formats_param = (const char **)avail.digest;
-			extensions_param = (const char **)avail.extension;
-			fmt_param = &fmt;
-			fmt = 0;
-			if (PCB->Data->loader != NULL) {
-				for(n = 0; n < num_fmts; n++) {
-					if (avail.plug[n] == PCB->Data->loader) {
-						fmt = n;
-						break;
-					}
-				}
-			}
-		}
-		else {
-			pcb_message(PCB_MSG_ERROR, "Error: no IO plugin avaialble for saving a buffer.");
-			return -1;
-		}
-	}
-
-	{ /* invent an input file name if needed and run the save dialog to get an output file name */
-		if (name_in == NULL) {
-			if (PCB->Filename == NULL)
-				name_in = pcb_concat("unnamed", extensions_param[fmt], NULL);
-			else
-				name_in = pcb_strdup(PCB->Filename);
-		}
-		name = ghid_dialog_file_select_save(prompt, &current_dir, name_in, conf_core.rc.file_path, formats_param, extensions_param, fmt_param);
-		free(name_in);
-	}
-
-	if (name) {
-		if (conf_core.rc.verbose)
-			fprintf(stderr, "Save:  Calling SaveTo(%s, %s)\n", function, name);
-
-		if (pcb_strcasecmp(function, "PasteBuffer") == 0) {
-			pcb_hid_actionl("PasteBuffer", "Save", name, avail.plug[fmt]->description, "1", NULL);
-
-		}
-		else {
-			const char *sfmt = NULL;
-			/*
-			 * if we got this far and the function is Layout, then
-			 * we really needed it to be a LayoutAs.  Otherwise
-			 * ActionSaveTo() will ignore the new file name we
-			 * just obtained.
-			 */
-			if (fmt_param != NULL)
-				sfmt = avail.plug[fmt]->description;
-			if (pcb_strcasecmp(function, "Layout") == 0)
-				pcb_hid_actionl("SaveTo", "LayoutAs", name, sfmt, NULL);
-			else
-				pcb_hid_actionl("SaveTo", function, name, sfmt, NULL);
-		}
-		g_free(name);
-		pcb_io_list_free(&avail);
-	}
-	else {
-		pcb_io_list_free(&avail);
-		return 1;
-	}
-
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-static const char swapsides_syntax[] = "SwapSides(|v|h|r)";
-
-static const char swapsides_help[] = N_("Swaps the side of the board you're looking at.");
-
-/* %start-doc actions SwapSides
-
-This action changes the way you view the board.
-
- at table @code
-
- at item v
-Flips the board over vertically (up/down).
-
- at item h
-Flips the board over horizontally (left/right), like flipping pages in
-a book.
-
- at item r
-Rotates the board 180 degrees without changing sides.
-
- at end table
-
-If no argument is given, the board isn't moved but the opposite side
-is shown.
-
-Normally, this action changes which pads and silk layer are drawn as
-pcb_true silk, and which are drawn as the "invisible" layer.  It also
-determines which solder mask you see.
-
-As a special case, if the layer group for the side you're looking at
-is visible and currently active, and the layer group for the opposite
-is not visible (i.e. disabled), then this action will also swap which
-layer group is visible and active, effectively swapping the ``working
-side'' of the board.
-
-%end-doc */
-
-
-static int SwapSides(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	pcb_layergrp_id_t active_group = pcb_layer_get_group(pcb_layer_stack[0]);
-	pcb_layergrp_id_t comp_group = pcb_layer_get_group(pcb_component_silk_layer);
-	pcb_layergrp_id_t solder_group = pcb_layer_get_group(pcb_solder_silk_layer);
-	pcb_bool comp_on = LAYER_PTR(PCB->LayerGroups.Entries[comp_group][0])->On;
-	pcb_bool solder_on = LAYER_PTR(PCB->LayerGroups.Entries[solder_group][0])->On;
-
-	pcb_draw_inhibit_inc();
-	if (argc > 0) {
-		switch (argv[0][0]) {
-		case 'h':
-		case 'H':
-			ghid_flip_view(gport->pcb_x, gport->pcb_y, pcb_true, pcb_false);
-			break;
-		case 'v':
-		case 'V':
-			ghid_flip_view(gport->pcb_x, gport->pcb_y, pcb_false, pcb_true);
-			break;
-		case 'r':
-		case 'R':
-			ghid_flip_view(gport->pcb_x, gport->pcb_y, pcb_true, pcb_true);
-			conf_toggle_editor(show_solder_side); /* Swapped back below */
-			break;
-		default:
-			pcb_draw_inhibit_dec();
-			return 1;
-		}
-	}
-
-	conf_toggle_editor(show_solder_side);
-
-	if ((active_group == comp_group && comp_on && !solder_on) || (active_group == solder_group && solder_on && !comp_on)) {
-		pcb_bool new_solder_vis = conf_core.editor.show_solder_side;
-
-		pcb_layervis_change_group_vis(PCB->LayerGroups.Entries[comp_group][0], !new_solder_vis, !new_solder_vis);
-		pcb_layervis_change_group_vis(PCB->LayerGroups.Entries[solder_group][0], new_solder_vis, new_solder_vis);
-	}
-
-	pcb_draw_inhibit_dec();
-
-	ghid_invalidate_all();
-
-	return 0;
-}
-
 /* ------------------------------------------------------------ */
 
-static const char print_syntax[] = "Print()";
-
-static const char print_help[] = N_("Print the layout.");
-
-/* %start-doc actions Print
-
-This will find the default printing HID, prompt the user for its
-options, and print the layout.
-
-%end-doc */
-
-static int Print(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+int pcb_gtk_act_print_(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
-	pcb_hid_t **hids;
-	int i;
-	pcb_hid_t *printer = NULL;
-
-	hids = pcb_hid_enumerate();
-	for (i = 0; hids[i]; i++) {
-		if (hids[i]->printer)
-			printer = hids[i];
-	}
-
-	if (printer == NULL) {
-		pcb_gui->log(_("Can't find a suitable printer HID"));
-		return -1;
-	}
-
-	/* check if layout is empty */
-	if (!pcb_data_is_empty(PCB->Data)) {
-		ghid_dialog_print(printer);
-	}
-	else
-		pcb_gui->log(_("Can't print empty layout"));
-
-	return 0;
-}
-
-
-/* ------------------------------------------------------------ */
-
-static pcb_hid_attribute_t printer_calibrate_attrs[] = {
-	{N_("Enter Values here:"), "",
-	 HID_Label, 0, 0, {0, 0, 0}, 0, 0},
-	{N_("x-calibration"), N_("X scale for calibrating your printer"),
-	 HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0},
-	{N_("y-calibration"), N_("Y scale for calibrating your printer"),
-	 HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0}
-};
-
-static pcb_hid_attr_val_t printer_calibrate_values[3];
-
-static const char printcalibrate_syntax[] = "PrintCalibrate()";
-
-static const char printcalibrate_help[] = N_("Calibrate the printer.");
-
-/* %start-doc actions PrintCalibrate
-
-This will print a calibration page, which you would measure and type
-the measurements in, so that future printouts will be more precise.
-
-%end-doc */
-
-static int PrintCalibrate(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	pcb_hid_t *printer = pcb_hid_find_printer();
-	printer->calibrate(0.0, 0.0);
-
-	if (pcb_gui->attribute_dialog(printer_calibrate_attrs, 3,
-														printer_calibrate_values,
-														_("Printer Calibration Values"), _("Enter calibration values for your printer")))
-		return 1;
-	printer->calibrate(printer_calibrate_values[1].real_value, printer_calibrate_values[2].real_value);
-	return 0;
+	return pcb_gtk_act_print(gport->top_window, argc, argv, x, y);
 }
 
 /* ------------------------------------------------------------ */
@@ -1480,7 +441,7 @@ static int ExportGUI(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 
 	/* check if layout is empty */
 	if (!pcb_data_is_empty(PCB->Data)) {
-		ghid_dialog_export();
+		ghid_dialog_export(ghid_port.top_window);
 	}
 	else
 		pcb_gui->log(_("Can't export empty layout"));
@@ -1515,136 +476,8 @@ static int Benchmark(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 
 /* ------------------------------------------------------------ */
 
-static const char center_syntax[] = "Center()\n";
-
-static const char center_help[] = N_("Moves the pointer to the center of the window.");
-
-/* %start-doc actions Center
-
-Move the pointer to the center of the window, but only if it's
-currently within the window already.
-
-%end-doc */
-
-static int Center(int argc, const char **argv, pcb_coord_t pcb_x, pcb_coord_t pcb_y)
-{
-	GdkDisplay *display;
-	GdkScreen *screen;
-	int offset_x, offset_y;
-	int widget_x, widget_y;
-	int pointer_x, pointer_y;
-
-	if (argc != 0)
-		PCB_AFAIL(center);
-
-	/* Aim to put the given x, y PCB coordinates in the center of the widget */
-	widget_x = gport->width / 2;
-	widget_y = gport->height / 2;
-
-	ghid_pan_view_abs(pcb_x, pcb_y, widget_x, widget_y);
-
-	/* Now move the mouse pointer to the place where the board location
-	 * actually ended up.
-	 *
-	 * XXX: Should only do this if we confirm we are inside our window?
-	 */
-
-	ghid_pcb_to_event_coords(pcb_x, pcb_y, &widget_x, &widget_y);
-	gdk_window_get_origin(gtk_widget_get_window(gport->drawing_area), &offset_x, &offset_y);
-
-	pointer_x = offset_x + widget_x;
-	pointer_y = offset_y + widget_y;
-
-	display = gdk_display_get_default();
-	screen = gdk_display_get_default_screen(display);
-	gdk_display_warp_pointer(display, screen, pointer_x, pointer_y);
-
-	return 0;
-}
-
-/* ------------------------------------------------------------ */
-static const char cursor_syntax[] = "Cursor(Type,DeltaUp,DeltaRight,Units)";
-
-static const char cursor_help[] = N_("Move the cursor.");
-
-/* %start-doc actions Cursor
-
-This action moves the mouse cursor.  Unlike other actions which take
-coordinates, this action's coordinates are always relative to the
-user's view of the board.  Thus, a positive @var{DeltaUp} may move the
-cursor towards the board origin if the board is inverted.
-
-Type is one of @samp{Pan} or @samp{Warp}.  @samp{Pan} causes the
-viewport to move such that the crosshair is under the mouse cursor.
- at samp{Warp} causes the mouse cursor to move to be above the crosshair.
-
- at var{Units} can be one of the following:
-
- at table @samp
-
- at item mil
- at itemx mm
-The cursor is moved by that amount, in board units.
-
- at item grid
-The cursor is moved by that many grid points.
-
- at item view
-The values are percentages of the viewport's view.  Thus, a pan of
- at samp{100} would scroll the viewport by exactly the width of the
-current view.
-
- at item board
-The values are percentages of the board size.  Thus, a move of
- at samp{50,50} moves you halfway across the board.
-
- at end table
-
-%end-doc */
-
-static int CursorAction(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	pcb_unit_list_t extra_units_x = {
-		{"grid", PCB->Grid, 0},
-		{"view", gport->view.width, UNIT_PERCENT},
-		{"board", PCB->MaxWidth, UNIT_PERCENT},
-		{"", 0, 0}
-	};
-	pcb_unit_list_t extra_units_y = {
-		{"grid", PCB->Grid, 0},
-		{"view", gport->view.height, UNIT_PERCENT},
-		{"board", PCB->MaxHeight, UNIT_PERCENT},
-		{"", 0, 0}
-	};
-	int pan_warp = HID_SC_DO_NOTHING;
-	double dx, dy;
-
-	if (argc != 4)
-		PCB_AFAIL(cursor);
-
-	if (pcb_strcasecmp(argv[0], "pan") == 0)
-		pan_warp = HID_SC_PAN_VIEWPORT;
-	else if (pcb_strcasecmp(argv[0], "warp") == 0)
-		pan_warp = HID_SC_WARP_POINTER;
-	else
-		PCB_AFAIL(cursor);
-
-	dx = pcb_get_value_ex(argv[1], argv[3], NULL, extra_units_x, "", NULL);
-	if (conf_core.editor.view.flip_x)
-		dx = -dx;
-	dy = pcb_get_value_ex(argv[2], argv[3], NULL, extra_units_y, "", NULL);
-	if (!conf_core.editor.view.flip_y)
-		dy = -dy;
-
-	pcb_event_move_crosshair(pcb_crosshair.X + dx, pcb_crosshair.Y + dy);
-	pcb_gui->set_crosshair(pcb_crosshair.X, pcb_crosshair.Y, pan_warp);
-
-	return 0;
-}
-
-/* ------------------------------------------------------------ */
-
-static const char dowindows_syntax[] = "DoWindows(1|2|3|4|5|6|7,[false])\n" "DoWindows(Layout|Library|Log|Netlist|Preferences|DRC,[false])";
+static const char dowindows_syntax[] =
+	"DoWindows(1|2|3|4|5|6|7,[false])\n" "DoWindows(Layout|Library|Log|Netlist|Preferences|DRC,[false])";
 
 static const char dowindows_help[] = N_("Open various GUI windows. With false, do not raise the window (no focus stealing).");
 
@@ -1714,7 +547,7 @@ static int DoWindows(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 		ghid_drc_window_show(raise);
 	}
 	else if (strcmp(a, "7") == 0 || pcb_strcasecmp(a, "search") == 0) {
-		ghid_search_window_show(raise);
+		ghid_search_window_show(gport->top_window, raise);
 	}
 	else {
 		PCB_AFAIL(dowindows);
@@ -1766,89 +599,6 @@ static int SetUnits(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 }
 
 /* ------------------------------------------------------------ */
-static const char scroll_syntax[] = "Scroll(up|down|left|right, [div])";
-
-static const char scroll_help[] = N_("Scroll the viewport.");
-
-/* % start-doc actions Scroll
-
- at item up|down|left|right
-Specifies the direction to scroll
-
- at item div
-Optional.  Specifies how much to scroll by.  The viewport is scrolled
-by 1/div of what is visible, so div = 1 scrolls a whole page. If not
-default is given, div=40.
-
-%end-doc */
-
-static int ScrollAction(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	gdouble dx = 0.0, dy = 0.0;
-	int div = 40;
-
-	if (!ghidgui)
-		return 0;
-
-	if (argc != 1 && argc != 2)
-		PCB_AFAIL(scroll);
-
-	if (argc == 2)
-		div = atoi(argv[1]);
-
-	if (pcb_strcasecmp(argv[0], "up") == 0)
-		dy = -gport->view.height / div;
-	else if (pcb_strcasecmp(argv[0], "down") == 0)
-		dy = gport->view.height / div;
-	else if (pcb_strcasecmp(argv[0], "right") == 0)
-		dx = gport->view.width / div;
-	else if (pcb_strcasecmp(argv[0], "left") == 0)
-		dx = -gport->view.width / div;
-	else
-		PCB_AFAIL(scroll);
-
-	ghid_pan_view_rel(dx, dy);
-
-	return 0;
-}
-
-/* ------------------------------------------------------------ */
-static const char pan_syntax[] = "Pan([thumb], Mode)";
-
-static const char pan_help[] =
-N_("Start or stop panning (Mode = 1 to start, 0 to stop)\n" "Optional thumb argument is ignored for now in gtk hid.\n");
-
-/* %start-doc actions Pan
-
-Start or stop panning.  To start call with Mode = 1, to stop call with
-Mode = 0.
-
-%end-doc */
-
-static int PanAction(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	int mode;
-
-	if (!ghidgui)
-		return 0;
-
-	if (argc != 1 && argc != 2)
-		PCB_AFAIL(pan);
-
-	if (argc == 1)
-		mode = atoi(argv[0]);
-	else {
-		mode = atoi(argv[1]);
-		pcb_message(PCB_MSG_WARNING, _("The gtk gui currently ignores the optional first argument "
-							"to the Pan action.\nFeel free to provide patches.\n"));
-	}
-
-	gport->panning = mode;
-
-	return 0;
-}
-
-/* ------------------------------------------------------------ */
 static const char popup_syntax[] = "Popup(MenuName, [Button])";
 
 static const char popup_help[] =
@@ -1869,7 +619,7 @@ static int Popup(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 	if (argc != 1 && argc != 2)
 		PCB_AFAIL(popup);
 
-	if (strlen(argv[0]) < sizeof(name)-32) {
+	if (strlen(argv[0]) < sizeof(name) - 32) {
 		lht_node_t *menu_node;
 		sprintf(name, "/popups/%s", argv[0]);
 		menu_node = pcb_hid_cfg_get_menu(ghid_cfg, name);
@@ -1890,64 +640,96 @@ static int Popup(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 }
 
 /* ------------------------------------------------------------ */
-static const char importgui_syntax[] = "ImportGUI()";
-
-static const char importgui_help[] = N_("Asks user which schematics to import into PCB.\n");
+static const char savewingeo_syntax[] = "SaveWindowGeometry()";
 
-/* %start-doc actions ImportGUI
+static const char savewingeo_help[] = N_("Saves window geometry in the config.\n");
 
-Asks user which schematics to import into PCB.
+static int SaveWinGeo(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	ghid_wgeo_save(1, 0);
+	return 0;
+}
 
-%end-doc */
 
+/* ------------------------------------------------------------ */
+static void ghid_Busy(void *user_data, int argc, pcb_event_arg_t argv[])
+{
+	ghid_watch_cursor(&gport->mouse);
+}
 
-static int ImportGUI(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+static int Zoom(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
-	char *name = NULL;
-	static gchar *current_layout_dir = NULL;
-	static int I_am_recursing = 0;
-	int rv;
+	return pcb_gtk_zoom(&gport->view, argc, argv, x, y);
+}
 
-	if (!current_layout_dir)
-		current_layout_dir = dup_cwd();
+int Center(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	int offset_x, offset_y, pointer_x, pointer_y;
+	GdkDisplay *display = gdk_display_get_default();
+	GdkScreen *screen = gdk_display_get_default_screen(display);
 
-	if (I_am_recursing)
-		return 1;
+	gdk_window_get_origin(gtk_widget_get_window(gport->drawing_area), &offset_x, &offset_y);
+	pcb_gtk_act_center(&gport->view, argc, argv, x, y, offset_x, offset_y, &pointer_x, &pointer_y);
+	gdk_display_warp_pointer(display, screen, pointer_x, pointer_y);
+	return 0;
+}
 
+static int SwapSides(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	return pcb_gtk_swap_sides(&gport->view, argc, argv, x, y);
+}
 
-	name = ghid_dialog_file_select_open(_("Load schematics"), &current_layout_dir, conf_core.rc.file_path);
+static int ScrollAction(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	if (ghidgui == NULL)
+		return 0;
 
-#ifdef DEBUG
-	printf("File selected = %s\n", name);
-#endif
+	return pcb_gtk_act_scroll(&gport->view, argc, argv, x, y);
+}
 
-	pcb_attrib_put(PCB, "import::src0", name);
-	free(name);
+static int PanAction(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	if (ghidgui == NULL)
+		return 0;
 
-	I_am_recursing = 1;
-	rv = pcb_hid_action("Import");
-	I_am_recursing = 0;
+	return pcb_gtk_act_pan(&gport->view, argc, argv, x, y);
+}
 
-	return rv;
+static void ghid_get_coords(const char *msg, pcb_coord_t * x, pcb_coord_t * y)
+{
+	pcb_gtk_get_coords(&gport->mouse, &gport->view, msg, x, y);
 }
 
-/* ------------------------------------------------------------ */
-static const char savewingeo_syntax[] = "SaveWindowGeometry()";
+int act_load(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	return pcb_gtk_act_load(ghid_port.top_window, argc, argv, x, y);
+}
 
-static const char savewingeo_help[] = N_("Saves window geometry in the config.\n");
+int act_save(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	return pcb_gtk_act_save(ghid_port.top_window, argc, argv, x, y);
+}
 
-static int SaveWinGeo(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+int act_importgui(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
-	ghid_wgeo_save(1, 0);
-	return 0;
+	return pcb_gtk_act_importgui(ghid_port.top_window, argc, argv, x, y);
 }
 
+void ghid_status_line_set_text(const gchar *text)
+{
+	if (!ghidgui->command_entry_status_line_active)
+		ghid_status_line_set_text_(ghidgui->status_line_label, text);
+}
 
+void ghid_set_status_line_label(void)
+{
+	if (!ghidgui->command_entry_status_line_active) \
+		ghid_set_status_line_label_(ghidgui->status_line_label, conf_hid_gtk.plugins.hid_gtk.compact_horizontal); \
+}
 
-/* ------------------------------------------------------------ */
-static void ghid_Busy(void *user_data, int argc, pcb_event_arg_t argv[])
+void ghid_draw_area_update(GHidPort *port, GdkRectangle *rect)
 {
-	ghid_watch_cursor();
+	gdk_window_invalidate_rect(gtk_widget_get_window(port->drawing_area), rect, FALSE);
 }
 
 pcb_hid_action_t ghid_main_action_list[] = {
@@ -1955,49 +737,44 @@ pcb_hid_action_t ghid_main_action_list[] = {
 	,
 	{"Benchmark", 0, Benchmark}
 	,
-	{"Center", N_("Click on a location to center"), Center, center_help, center_syntax}
+	{"Center", N_("Click on a location to center"), Center, pcb_acth_center, pcb_acts_center}
 	,
 	{"Command", 0, Command}
 	,
-	{"Cursor", 0, CursorAction, cursor_help, cursor_syntax}
-	,
 	{"DoWindows", 0, DoWindows, dowindows_help, dowindows_syntax}
 	,
 	{"ExportGUI", 0, ExportGUI}
 	,
 	{"GetXY", "", GetXY, getxy_help, getxy_syntax}
 	,
-	{"ImportGUI", 0, ImportGUI, importgui_help, importgui_syntax}
+	{"ImportGUI", 0, act_importgui, pcb_gtk_acth_importgui, pcb_gtk_acts_importgui}
 	,
 	{"LayerGroupsChanged", 0, LayerGroupsChanged}
 	,
-	{"Load", 0, Load}
+	{"Load", 0, act_load }
 	,
-	{"Pan", 0, PanAction, pan_help, pan_syntax}
+	{"Pan", 0, PanAction, pcb_acth_pan, pcb_acts_pan}
 	,
 	{"Popup", 0, Popup, popup_help, popup_syntax}
 	,
-	{"Print", 0, Print,
-	 print_help, print_syntax}
+	{"Print", 0, pcb_gtk_act_print_, pcb_gtk_acth_print, pcb_gtk_acts_print}
 	,
-	{"PrintCalibrate", 0, PrintCalibrate,
-	 printcalibrate_help, printcalibrate_syntax}
+	{"PrintCalibrate", 0, pcb_gtk_act_printcalibrate, pcb_gtk_acth_printcalibrate, pcb_gtk_acts_printcalibrate}
 	,
-	{"Save", 0, Save, save_help, save_syntax}
+	{"Save", 0, act_save, pcb_gtk_acth_save, pcb_gtk_acts_save}
 	,
 	{"SaveWindowGeometry", 0, SaveWinGeo, savewingeo_help, savewingeo_syntax}
 	,
-	{"Scroll", N_("Click on a place to scroll"), ScrollAction, scroll_help, scroll_syntax}
+	{"Scroll", N_("Click on a place to scroll"), ScrollAction, pcb_acth_scroll, pcb_acts_scroll}
 	,
 	{"SetUnits", 0, SetUnits, setunits_help, setunits_syntax}
 	,
-	{"SwapSides", 0, SwapSides, swapsides_help, swapsides_syntax}
+	{"SwapSides", 0, SwapSides, pcb_acth_swapsides, pcb_acts_swapsides}
 	,
-	{"Zoom", N_("Click on zoom focus"), Zoom, zoom_help, zoom_syntax}
+	{"Zoom", N_("Click on zoom focus"), Zoom, pcb_acth_zoom, pcb_acts_zoom}
 };
 
 PCB_REGISTER_ACTIONS(ghid_main_action_list, ghid_cookie)
-
 #include "dolists.h"
 /*
  * We will need these for finding the windows installation
@@ -2008,10 +785,9 @@ PCB_REGISTER_ACTIONS(ghid_main_action_list, ghid_cookie)
 #include <windows.h>
 #include <winreg.h>
 #endif
+		 pcb_hid_t ghid_hid;
 
-pcb_hid_t ghid_hid;
-
-static void init_conf_watch(conf_hid_callbacks_t *cbs, const char *path, void (*func)(conf_native_t *))
+		 static void init_conf_watch(conf_hid_callbacks_t * cbs, const char *path, void (*func) (conf_native_t *))
 {
 	conf_native_t *n = conf_get_field(path);
 	if (n != NULL) {
@@ -2025,10 +801,10 @@ static void ghid_conf_regs()
 {
 	static conf_hid_callbacks_t cbs_refraction, cbs_direction, cbs_fullscreen, cbs_show_sside;
 
-	init_conf_watch(&cbs_direction,   "editor/all_direction_lines",  ghid_confchg_all_direction_lines);
-	init_conf_watch(&cbs_refraction,  "editor/line_refraction",      ghid_confchg_line_refraction);
- 	init_conf_watch(&cbs_fullscreen,  "editor/fullscreen",           ghid_confchg_fullscreen);
-	init_conf_watch(&cbs_show_sside,  "editor/show_solder_side",     ghid_confchg_flip);
+	init_conf_watch(&cbs_direction, "editor/all_direction_lines", ghid_confchg_all_direction_lines);
+	init_conf_watch(&cbs_refraction, "editor/line_refraction", ghid_confchg_line_refraction);
+	init_conf_watch(&cbs_fullscreen, "editor/fullscreen", ghid_confchg_fullscreen);
+	init_conf_watch(&cbs_show_sside, "editor/show_solder_side", ghid_confchg_flip);
 }
 
 void hid_hid_gtk_uninit()
@@ -2040,6 +816,13 @@ void hid_hid_gtk_uninit()
 
 void GhidNetlistChanged(void *user_data, int argc, pcb_event_arg_t argv[]);
 
+static int ghid_attribute_dialog_(pcb_hid_attribute_t * attrs, int n_attrs, pcb_hid_attr_val_t * results, const char *title,
+																	const char *descr)
+{
+	return ghid_attribute_dialog(ghid_port.top_window, attrs, n_attrs, results, title, descr);
+}
+
+
 pcb_uninit_t hid_hid_gtk_init()
 {
 #ifdef WIN32
@@ -2106,7 +889,9 @@ pcb_uninit_t hid_hid_gtk_init()
 	ghid_hid.calibrate = ghid_calibrate;
 	ghid_hid.shift_is_pressed = ghid_shift_is_pressed;
 	ghid_hid.control_is_pressed = ghid_control_is_pressed;
-	ghid_hid.mod1_is_pressed = ghid_mod1_is_pressed, ghid_hid.get_coords = ghid_get_coords;
+	ghid_hid.mod1_is_pressed = ghid_mod1_is_pressed;
+	ghid_hid.get_coords = ghid_get_coords;
+	ghid_hid.get_view_size = ghid_get_view_size;
 	ghid_hid.set_crosshair = ghid_set_crosshair;
 	ghid_hid.add_timer = ghid_add_timer;
 	ghid_hid.stop_timer = ghid_stop_timer;
@@ -2122,7 +907,7 @@ pcb_uninit_t hid_hid_gtk_init()
 	ghid_hid.report_dialog = ghid_report_dialog;
 	ghid_hid.prompt_for = ghid_prompt_for;
 	ghid_hid.fileselect = ghid_fileselect;
-	ghid_hid.attribute_dialog = ghid_attribute_dialog;
+	ghid_hid.attribute_dialog = ghid_attribute_dialog_;
 	ghid_hid.show_item = ghid_show_item;
 	ghid_hid.beep = ghid_beep;
 	ghid_hid.progress = ghid_progress;
@@ -2175,11 +960,11 @@ int gtkhid_active = 0;
 void gtkhid_begin(void)
 {
 	PCB_REGISTER_ACTIONS(ghid_main_action_list, ghid_cookie)
-	PCB_REGISTER_ACTIONS(ghid_netlist_action_list, ghid_cookie)
-	PCB_REGISTER_ACTIONS(ghid_log_action_list, ghid_cookie)
-	PCB_REGISTER_ACTIONS(gtk_topwindow_action_list, ghid_cookie)
-	PCB_REGISTER_ACTIONS(ghid_menu_action_list, ghid_cookie)
-	gtkhid_active = 1;
+		PCB_REGISTER_ACTIONS(ghid_netlist_action_list, ghid_cookie)
+		PCB_REGISTER_ACTIONS(ghid_log_action_list, ghid_cookie)
+		PCB_REGISTER_ACTIONS(gtk_topwindow_action_list, ghid_cookie)
+		PCB_REGISTER_ACTIONS(ghid_menu_action_list, ghid_cookie)
+		gtkhid_active = 1;
 }
 
 void gtkhid_end(void)
diff --git a/src_plugins/hid_gtk/gtkhid-main.h b/src_plugins/hid_gtk/gtkhid-main.h
new file mode 100644
index 0000000..1853243
--- /dev/null
+++ b/src_plugins/hid_gtk/gtkhid-main.h
@@ -0,0 +1,14 @@
+#ifndef PCB_GTKHID_MAIN_H
+#define PCB_GTKHID_MAIN_H
+
+#include "conf_hid.h"
+extern conf_hid_id_t ghid_conf_id;
+
+void ghid_notify_gui_is_up(void);
+extern int gtkhid_active;
+
+void gtkhid_begin(void);
+void gtkhid_end(void);
+
+
+#endif
diff --git a/src_plugins/hid_gtk/gtkhid.h b/src_plugins/hid_gtk/gtkhid.h
deleted file mode 100644
index 8fa9ed6..0000000
--- a/src_plugins/hid_gtk/gtkhid.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef PCB_HID_GTK_GTKHID_H
-#define PCB_HID_GTK_GTKHID_H
-
-#include "conf_hid.h"
-
-void ghid_notify_gui_is_up(void);
-
-extern int gtkhid_active;
-void gtkhid_begin(void);
-void gtkhid_end(void);
-
-extern conf_hid_id_t ghid_conf_id;
-
-#endif /* PCB_HID_GTK_GTKHID_H */
diff --git a/src_plugins/hid_gtk/gui-command-window.c b/src_plugins/hid_gtk/gui-command-window.c
index 2acb926..20e7c1a 100644
--- a/src_plugins/hid_gtk/gui-command-window.c
+++ b/src_plugins/hid_gtk/gui-command-window.c
@@ -37,6 +37,10 @@
 #include "hid_gtk_conf.h"
 #include "compat_nls.h"
 
+#include "../src_plugins/lib_gtk_common/bu_text_view.h"
+#include "../src_plugins/lib_gtk_common/bu_status_line.h"
+#include "../src_plugins/lib_gtk_common/util_str.h"
+
 static GtkWidget *command_window;
 static GtkWidget *combo_vbox;
 static GList *history_list;
@@ -186,7 +190,8 @@ static void command_entry_activate_cb(GtkWidget * widget, gpointer data)
 {
 	gchar *command;
 
-	command = g_strdup(ghid_entry_get_text(GTK_WIDGET(ghidgui->command_entry)));
+	/*command = g_strdup(ghid_entry_get_text(GTK_WIDGET(ghidgui->command_entry))); */
+	command = g_strdup(pcb_str_strip_left(gtk_entry_get_text(GTK_ENTRY(ghidgui->command_entry))));
 	gtk_entry_set_text(ghidgui->command_entry, "");
 
 	if (*command)
@@ -413,7 +418,8 @@ void ghid_handle_user_command(gboolean raise)
 	if (conf_hid_gtk.plugins.hid_gtk.use_command_window)
 		ghid_command_window_show(raise);
 	else {
-		command = ghid_command_entry_get(_("Enter command:"), (conf_core.editor.save_last_command && previous) ? previous : (gchar *) "");
+		command =
+			ghid_command_entry_get(_("Enter command:"), (conf_core.editor.save_last_command && previous) ? previous : (gchar *) "");
 		if (command != NULL) {
 			/* copy new comand line to save buffer */
 			g_free(previous);
diff --git a/src_plugins/hid_gtk/gui-config.c b/src_plugins/hid_gtk/gui-config.c
index 10f5afd..7c1e1b9 100644
--- a/src_plugins/hid_gtk/gui-config.c
+++ b/src_plugins/hid_gtk/gui-config.c
@@ -30,9 +30,8 @@
 #include <genht/hash.h>
 
 #include "gui.h"
-#include "win_place.h"
 #include "hid.h"
-#include "gtkhid.h"
+#include "gtkhid-main.h"
 
 #include "action_helper.h"
 #include "change.h"
@@ -47,11 +46,24 @@
 #include "gtk_conf_list.h"
 #include "paths.h"
 #include "plug_footprint.h"
+#include "stub_draw_csect.h"
 #include "compat_misc.h"
 #include "compat_nls.h"
 #include "fptr_cast.h"
 #include <liblihata/tree.h>
 
+#include "../src_plugins/lib_gtk_common/util_str.h"
+#include "../src_plugins/lib_gtk_common/wt_preview.h"
+#include "../src_plugins/lib_gtk_common/bu_box.h"
+#include "../src_plugins/lib_gtk_common/bu_entry.h"
+#include "../src_plugins/lib_gtk_common/bu_notebook.h"
+#include "../src_plugins/lib_gtk_common/bu_text_view.h"
+#include "../src_plugins/lib_gtk_common/bu_check_button.h"
+#include "../src_plugins/lib_gtk_common/bu_status_line.h"
+#include "../src_plugins/lib_gtk_common/win_place.h"
+#include "../src_plugins/lib_gtk_common/bu_spin_button.h"
+
+
 #if 0
 #include <locale.h>
 #endif
@@ -103,10 +115,12 @@ void ghid_wgeo_save(int save_to_file, int skip_user)
 	}
 }
 
-static void wgeo_save_direct(GtkButton *widget, const char *ctx)
+static void wgeo_save_direct(GtkButton * widget, const char *ctx)
 {
 	if (ctx == NULL) {
-		GtkWidget *fcd = gtk_file_chooser_dialog_new("Save window geometry to...", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+		GtkWidget *fcd =
+			gtk_file_chooser_dialog_new("Save window geometry to...", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
+																	GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
 		if (gtk_dialog_run(GTK_DIALOG(fcd)) == GTK_RESPONSE_ACCEPT) {
 			char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fcd));
 			conf_reset(CFR_file, "<wgeo_save_direct>");
@@ -118,19 +132,19 @@ static void wgeo_save_direct(GtkButton *widget, const char *ctx)
 		}
 	}
 	else if (*ctx == '*') {
-		switch(ctx[1]) {
-			case 'd':
-				GHID_WGEO_ALL(hid_gtk_wgeo_save_, CFR_DESIGN);
-				conf_save_file(NULL, (PCB == NULL ? NULL : PCB->Filename), CFR_DESIGN, NULL);
-				break;
-			case 'p':
-				GHID_WGEO_ALL(hid_gtk_wgeo_save_, CFR_PROJECT);
-				conf_save_file(NULL, (PCB == NULL ? NULL : PCB->Filename), CFR_PROJECT, NULL);
-				break;
-			case 'u':
-				GHID_WGEO_ALL(hid_gtk_wgeo_save_, CFR_USER);
-				conf_save_file(NULL, (PCB == NULL ? NULL : PCB->Filename), CFR_USER, NULL);
-				break;
+		switch (ctx[1]) {
+		case 'd':
+			GHID_WGEO_ALL(hid_gtk_wgeo_save_, CFR_DESIGN);
+			conf_save_file(NULL, (PCB == NULL ? NULL : PCB->Filename), CFR_DESIGN, NULL);
+			break;
+		case 'p':
+			GHID_WGEO_ALL(hid_gtk_wgeo_save_, CFR_PROJECT);
+			conf_save_file(NULL, (PCB == NULL ? NULL : PCB->Filename), CFR_PROJECT, NULL);
+			break;
+		case 'u':
+			GHID_WGEO_ALL(hid_gtk_wgeo_save_, CFR_USER);
+			conf_save_file(NULL, (PCB == NULL ? NULL : PCB->Filename), CFR_USER, NULL);
+			break;
 		}
 	}
 }
@@ -199,7 +213,7 @@ typedef struct {
 	void *value;
 } ConfigAttribute;
 
-extern void ghid_set_special_colors(conf_native_t *cfg);
+extern void ghid_set_special_colors(conf_native_t * cfg);
 
 void ghid_config_init(void)
 {
@@ -224,7 +238,7 @@ struct tvmap_s {
 	tvmap_t *next;
 };
 
-static void tvmap(GtkTreeView *tree, GtkTreePath *path, gpointer user_data)
+static void tvmap(GtkTreeView * tree, GtkTreePath * path, gpointer user_data)
 {
 	tvmap_t **first = user_data, *m = malloc(sizeof(tvmap_t));
 	m->path = gtk_tree_path_copy(path);
@@ -237,15 +251,15 @@ static void tvmap(GtkTreeView *tree, GtkTreePath *path, gpointer user_data)
    - a path to a config filed that presents in the hash (not a ha:subtree)
    - a subtree or multiple subtrees matching a prefix (e.g. "*appearance/color")
 */
-void config_any_replace(save_ctx_t *ctx, const char **paths)
+void config_any_replace(save_ctx_t * ctx, const char **paths)
 {
 	const char **p;
 	int need_update = 0;
 
-	for(p = paths; *p != NULL; p++) {
+	for (p = paths; *p != NULL; p++) {
 		/* wildcards - match subtree */
 		if (**p == '*') {
-			const char *wildp = (*p)+1;
+			const char *wildp = (*p) + 1;
 			int pl = strlen(wildp);
 			htsp_entry_t *e;
 			conf_fields_foreach(e) {
@@ -262,7 +276,7 @@ void config_any_replace(save_ctx_t *ctx, const char **paths)
 		else {
 			/* plain node */
 			if (conf_replace_subtree(ctx->dst_role, *p, ctx->src_role, *p) != 0)
-					pcb_message(PCB_MSG_ERROR, "Error: failed to save config item %s\n", *p);
+				pcb_message(PCB_MSG_ERROR, "Error: failed to save config item %s\n", *p);
 			if (ctx->dst_role < CFR_max_real) {
 				conf_update(*p);
 				need_update++;
@@ -272,7 +286,9 @@ void config_any_replace(save_ctx_t *ctx, const char **paths)
 
 	/* present a file choose dialog box on save to custom file */
 	if (ctx->dst_role == CFR_file) {
-		GtkWidget *fcd = gtk_file_chooser_dialog_new("Save config settings to...", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+		GtkWidget *fcd =
+			gtk_file_chooser_dialog_new("Save config settings to...", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
+																	GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
 		if (gtk_dialog_run(GTK_DIALOG(fcd)) == GTK_RESPONSE_ACCEPT) {
 			char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fcd));
 			conf_export_to_file(fn, CFR_file, "/");
@@ -292,7 +308,7 @@ void config_any_replace(save_ctx_t *ctx, const char **paths)
 	if ((ctx->dst_role == CFR_USER) || (ctx->dst_role == CFR_PROJECT))
 		conf_save_file(NULL, (PCB == NULL ? NULL : PCB->Filename), ctx->dst_role, NULL);
 
-	if (need_update) { /* need to reopen the preferences dialog to show the new settings */
+	if (need_update) {						/* need to reopen the preferences dialog to show the new settings */
 		tvmap_t *first = NULL, *next;
 		int page;
 
@@ -304,7 +320,7 @@ void config_any_replace(save_ctx_t *ctx, const char **paths)
 		ghid_config_window_show();
 
 		/* restore expansions and notebook states */
-		for(; first != NULL; first = next) {
+		for (; first != NULL; first = next) {
 /*			printf("exp2 %s\n", gtk_tree_path_to_string(first->path));*/
 			next = first->next;
 			gtk_tree_view_expand_to_path(gui_config_treeview, first->path);
@@ -319,13 +335,13 @@ void config_any_replace(save_ctx_t *ctx, const char **paths)
 */
 static GtkWidget *config_window;
 
-static void config_user_role_section(GtkWidget * vbox, void (*save_cb)(GtkButton *widget, save_ctx_t *sctx))
+static void config_user_role_section(GtkWidget * vbox, void (*save_cb) (GtkButton * widget, save_ctx_t * sctx))
 {
 	GtkWidget *config_color_warn_label, *button, *hbox, *vbox2;
 	static save_ctx_t ctx_all2project = { CFR_PROJECT, CFR_binary };
-	static save_ctx_t ctx_all2user    = { CFR_USER, CFR_binary };
-	static save_ctx_t ctx_all2file    = { CFR_file, CFR_binary };
-	static save_ctx_t ctx_int2design  = { CFR_DESIGN, CFR_INTERNAL };
+	static save_ctx_t ctx_all2user = { CFR_USER, CFR_binary };
+	static save_ctx_t ctx_all2file = { CFR_file, CFR_binary };
+	static save_ctx_t ctx_int2design = { CFR_DESIGN, CFR_INTERNAL };
 
 	hbox = gtk_hbox_new(FALSE, 4);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 4);
@@ -333,7 +349,8 @@ static void config_user_role_section(GtkWidget * vbox, void (*save_cb)(GtkButton
 	config_color_warn_label = gtk_label_new("");
 	gtk_label_set_use_markup(GTK_LABEL(config_color_warn_label), TRUE);
 	gtk_label_set_markup(GTK_LABEL(config_color_warn_label),
-											 _("<small>The above are <i>design-level</i>\nconfiguration, <u>saved</u> with the\npcb file. Use these buttons\nto save all the above settings:</small>"));
+											 _
+											 ("<small>The above are <i>design-level</i>\nconfiguration, <u>saved</u> with the\npcb file. Use these buttons\nto save all the above settings:</small>"));
 	gtk_box_pack_start(GTK_BOX(hbox), config_color_warn_label, FALSE, FALSE, 4);
 
 	vbox2 = gtk_vbox_new(FALSE, 0);
@@ -404,9 +421,11 @@ static void pref_auto_place_update(void)
 {
 	const char *warn;
 	if (conf_core.editor.auto_place)
-		warn = "Restoring window geometry is <b>enabled</b>:\npcb-rnd will attempt to move and resize windows.\nIt can be disabled in General/";
+		warn =
+			"Restoring window geometry is <b>enabled</b>:\npcb-rnd will attempt to move and resize windows.\nIt can be disabled in General/";
 	else
-		warn = "Restoring window geometry is <b>disabled</b>:\npcb-rnd will <b>not</b> attempt to move and resize windows.\nConsider changing it in General/";
+		warn =
+			"Restoring window geometry is <b>disabled</b>:\npcb-rnd will <b>not</b> attempt to move and resize windows.\nConsider changing it in General/";
 	gtk_label_set_markup(GTK_LABEL(pref_auto_place_lab), _(warn));
 }
 
@@ -438,7 +457,7 @@ static void config_history_spin_button_cb(GtkSpinButton * spin_button, gpointer
 	conf_setf(CFR_DESIGN, "plugins/hid_gtk/history_size", -1, "%d", gtk_spin_button_get_value_as_int(spin_button));
 }
 
-void config_general_save(GtkButton *widget, save_ctx_t *ctx)
+void config_general_save(GtkButton * widget, save_ctx_t * ctx)
 {
 	const char *paths[] = {
 		"plugins/hid_gtk/use_command_window",
@@ -486,7 +505,7 @@ static void config_general_tab_create(GtkWidget * tab_vbox)
 	vbox = ghid_category_vbox(content_vbox, _("Backups"), 4, 2, TRUE, TRUE);
 	ghid_check_button_connected(vbox, NULL, conf_core.editor.save_in_tmp,
 															TRUE, FALSE, FALSE, 2,
-															config_general_toggle_cb, (void *)&conf_core.editor.save_in_tmp,
+															config_general_toggle_cb, (void *) &conf_core.editor.save_in_tmp,
 															_("If layout is modified at exit, save into PCB.%i.save"));
 	ghid_spin_button(vbox, NULL, conf_core.rc.backup_interval, 0.0, 60 * 60, 60.0,
 									 600.0, 0, 0, config_backup_spin_button_cb, NULL, FALSE,
@@ -532,12 +551,12 @@ static void text_spin_button_cb(GtkSpinButton * spin, void *dst)
 	ghid_set_status_line_label();
 }
 
-static void coord_entry_cb(GHidCoordEntry * ce, void *dst)
+static void coord_entry_cb(pcb_gtk_coord_entry_t * ce, void *dst)
 {
-	*(pcb_coord_t *) dst = ghid_coord_entry_get_value(ce);
+	*(pcb_coord_t *) dst = pcb_gtk_coord_entry_get_value(ce);
 }
 
-void config_sizes_save(GtkButton *widget, save_ctx_t *ctx)
+void config_sizes_save(GtkButton * widget, save_ctx_t * ctx)
 {
 	const char *paths[] = {
 		"design/max_width",
@@ -588,7 +607,8 @@ static void config_sizes_tab_create(GtkWidget * tab_vbox)
 	new_board_width = PCB->MaxWidth;
 	new_board_height = PCB->MaxHeight;
 	ghid_table_coord_entry(table, 0, 0, NULL,
-												 PCB->MaxWidth, PCB_MIN_SIZE, PCB_MAX_COORD, CE_LARGE, 0, coord_entry_cb, &new_board_width, FALSE, _("Width"));
+												 PCB->MaxWidth, PCB_MIN_SIZE, PCB_MAX_COORD, CE_LARGE, 0, coord_entry_cb, &new_board_width, FALSE,
+												 _("Width"));
 
 	ghid_table_coord_entry(table, 1, 0, NULL,
 												 PCB->MaxHeight, PCB_MIN_SIZE, PCB_MAX_COORD,
@@ -661,10 +681,16 @@ static void config_window_toggle_cb(GtkToggleButton * button, gpointer data)
 		return;
 
 	if (*ctx == '*') {
-		switch(ctx[1]) {
-			case 'd': path = "plugins/hid_gtk/auto_save_window_geometry/to_design"; break;
-			case 'p': path = "plugins/hid_gtk/auto_save_window_geometry/to_project"; break;
-			case 'u': path = "plugins/hid_gtk/auto_save_window_geometry/to_user"; break;
+		switch (ctx[1]) {
+		case 'd':
+			path = "plugins/hid_gtk/auto_save_window_geometry/to_design";
+			break;
+		case 'p':
+			path = "plugins/hid_gtk/auto_save_window_geometry/to_project";
+			break;
+		case 'u':
+			path = "plugins/hid_gtk/auto_save_window_geometry/to_user";
+			break;
 		}
 		if (path != NULL)
 			conf_set(CFR_USER, path, -1, (active ? "1" : "0"), POL_OVERWRITE);
@@ -672,7 +698,7 @@ static void config_window_toggle_cb(GtkToggleButton * button, gpointer data)
 }
 
 
-static void config_window_row(GtkWidget *parent, const char *desc, int load, const char *wgeo_save_str, CFT_BOOLEAN chk)
+static void config_window_row(GtkWidget * parent, const char *desc, int load, const char *wgeo_save_str, CFT_BOOLEAN chk)
 {
 	GtkWidget *hbox, *lab, *button;
 	hbox = gtk_hbox_new(FALSE, 0);
@@ -686,7 +712,7 @@ static void config_window_row(GtkWidget *parent, const char *desc, int load, con
 
 	button = gtk_button_new_with_label(_("now"));
 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-	g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(wgeo_save_direct), (void *)wgeo_save_str);
+	g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(wgeo_save_direct), (void *) wgeo_save_str);
 
 	if (load) {
 		button = gtk_button_new_with_label(_("Load from file"));
@@ -695,14 +721,14 @@ static void config_window_row(GtkWidget *parent, const char *desc, int load, con
 	else {
 		GtkWidget *btn;
 		ghid_check_button_connected(hbox, &btn, chk,
-															TRUE, FALSE, FALSE, 2,
-															config_window_toggle_cb, (void *)wgeo_save_str, _("every time pcb-rnd exits"));
+																TRUE, FALSE, FALSE, 2,
+																config_window_toggle_cb, (void *) wgeo_save_str, _("every time pcb-rnd exits"));
 		if (wgeo_save_str == NULL)
 			gtk_widget_set_sensitive(btn, FALSE);
 	}
 }
 
-static void config_window_tab_create(GtkWidget *tab_vbox)
+static void config_window_tab_create(GtkWidget * tab_vbox)
 {
 	GtkWidget *lab;
 
@@ -712,14 +738,16 @@ static void config_window_tab_create(GtkWidget *tab_vbox)
 
 	lab = gtk_label_new("");
 	gtk_label_set_use_markup(GTK_LABEL(lab), TRUE);
-	gtk_label_set_markup(GTK_LABEL(lab),
-											 _("<b>Save window geometry...</b>"));
+	gtk_label_set_markup(GTK_LABEL(lab), _("<b>Save window geometry...</b>"));
 	gtk_box_pack_start(GTK_BOX(config_window_vbox), lab, FALSE, FALSE, 4);
 	gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.5);
 
-	config_window_row(config_window_vbox, "... in the design (.pcb) file", 0, "*d", conf_hid_gtk.plugins.hid_gtk.auto_save_window_geometry.to_design);
-	config_window_row(config_window_vbox, "... in the project file", 0, "*p", conf_hid_gtk.plugins.hid_gtk.auto_save_window_geometry.to_project);
-	config_window_row(config_window_vbox, "... in the central user configuration", 0, "*u", conf_hid_gtk.plugins.hid_gtk.auto_save_window_geometry.to_user);
+	config_window_row(config_window_vbox, "... in the design (.pcb) file", 0, "*d",
+										conf_hid_gtk.plugins.hid_gtk.auto_save_window_geometry.to_design);
+	config_window_row(config_window_vbox, "... in the project file", 0, "*p",
+										conf_hid_gtk.plugins.hid_gtk.auto_save_window_geometry.to_project);
+	config_window_row(config_window_vbox, "... in the central user configuration", 0, "*u",
+										conf_hid_gtk.plugins.hid_gtk.auto_save_window_geometry.to_user);
 	config_window_row(config_window_vbox, "... in a custom file", 0, NULL, 0);
 
 
@@ -727,8 +755,7 @@ static void config_window_tab_create(GtkWidget *tab_vbox)
 
 	lab = gtk_label_new("");
 	gtk_label_set_use_markup(GTK_LABEL(lab), TRUE);
-	gtk_label_set_markup(GTK_LABEL(lab),
-											 _("<small>Note: the above checkbox values are saved in the user config</small>"));
+	gtk_label_set_markup(GTK_LABEL(lab), _("<small>Note: the above checkbox values are saved in the user config</small>"));
 	gtk_box_pack_start(GTK_BOX(config_window_vbox), lab, FALSE, FALSE, 4);
 	gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.5);
 
@@ -748,11 +775,11 @@ static void config_window_tab_create(GtkWidget *tab_vbox)
 	/* Increment/decrement values are kept in mil and mm units and not in
 	   |  PCB units.
 	 */
-GtkWidget *config_increments_tbl[4][4]; /* [col][row] */
+GtkWidget *config_increments_tbl[4][4];	/* [col][row] */
 
 static GtkWidget *config_increments_vbox = NULL, *config_increments_tab_vbox = NULL;
 
-static void increment_tbl_update_cell(GtkLabel *lab, pcb_coord_t val, const char *fmt)
+static void increment_tbl_update_cell(GtkLabel * lab, pcb_coord_t val, const char *fmt)
 {
 	char s[128];
 	pcb_snprintf(s, sizeof(s), fmt, val);
@@ -775,16 +802,16 @@ static void increment_tbl_update()
 	increment_tbl_update_row(3, conf_core.editor.increments_mm.clear, conf_core.editor.increments_mil.clear);
 }
 
-static void increment_spin_button_cb(GHidCoordEntry * ce, void *dst)
+static void increment_spin_button_cb(pcb_gtk_coord_entry_t * ce, void *dst)
 {
 	const char *path = dst;
-	conf_setf(CFR_DESIGN, path, -1, "%mr", (pcb_coord_t)ghid_coord_entry_get_value(ce));
+	conf_setf(CFR_DESIGN, path, -1, "%mr", (pcb_coord_t) pcb_gtk_coord_entry_get_value(ce));
 	increment_tbl_update();
 }
 
 static void config_increments_sect_create(GtkWidget * vbox)
 {
-	GtkWidget * hbox, *label;
+	GtkWidget *hbox, *label;
 	const int width = 128;
 	char pathmm[256], *pemm;
 	char pathmil[256], *pemil;
@@ -796,12 +823,12 @@ static void config_increments_sect_create(GtkWidget * vbox)
 	int lmil = strlen(base_pathmil);
 
 	memcpy(pathmm, base_pathmm, lmm);
-	pemm = pathmm+lmm;
+	pemm = pathmm + lmm;
 	*pemm = '/';
 	pemm++;
 
 	memcpy(pathmil, base_pathmil, lmil);
-	pemil = pathmil+lmil;
+	pemil = pathmil + lmil;
 	*pemil = '/';
 	pemil++;
 
@@ -839,19 +866,19 @@ static void config_increments_sect_create(GtkWidget * vbox)
 									 conf_core.editor.increments_mm.size,
 									 conf_core.editor.increments_mm.size_min,
 									 conf_core.editor.increments_mm.size_max,
-									 CE_SMALL, umm, width, increment_spin_button_cb,
-									 pcb_strdup(pathmm), _("Size:"), NULL);
+									 CE_SMALL, umm, width, increment_spin_button_cb, pcb_strdup(pathmm), _("Size:"), NULL);
 
 	ghid_coord_entry(hbox, NULL,
 									 conf_core.editor.increments_mil.size,
 									 conf_core.editor.increments_mil.size_min,
 									 conf_core.editor.increments_mil.size_max,
-									 CE_SMALL, umil, width, increment_spin_button_cb,
-									 pcb_strdup(pathmil), NULL, NULL);
+									 CE_SMALL, umil, width, increment_spin_button_cb, pcb_strdup(pathmil), NULL, NULL);
 
 	label = gtk_label_new("");
 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
-	gtk_label_set_markup(GTK_LABEL(label), _("For <small>'s' and '<shift>s' on lines, pads, text; '<ctrl>s' and '<shift><ctrl>s' on holes.</small>"));
+	gtk_label_set_markup(GTK_LABEL(label),
+											 _
+											 ("For <small>'s' and '<shift>s' on lines, pads, text; '<ctrl>s' and '<shift><ctrl>s' on holes.</small>"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 2);
 
@@ -865,15 +892,13 @@ static void config_increments_sect_create(GtkWidget * vbox)
 									 conf_core.editor.increments_mm.line,
 									 conf_core.editor.increments_mm.line_min,
 									 conf_core.editor.increments_mm.line_max,
-									 CE_SMALL, umm, width, increment_spin_button_cb,
-									 pcb_strdup(pathmm), _("Line:"), NULL);
+									 CE_SMALL, umm, width, increment_spin_button_cb, pcb_strdup(pathmm), _("Line:"), NULL);
 
 	ghid_coord_entry(hbox, NULL,
 									 conf_core.editor.increments_mil.line,
 									 conf_core.editor.increments_mil.line_min,
 									 conf_core.editor.increments_mil.line_max,
-									 CE_SMALL, umil, width, increment_spin_button_cb,
-									 pcb_strdup(pathmil), NULL, NULL);
+									 CE_SMALL, umil, width, increment_spin_button_cb, pcb_strdup(pathmil), NULL, NULL);
 
 	label = gtk_label_new("");
 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
@@ -891,19 +916,18 @@ static void config_increments_sect_create(GtkWidget * vbox)
 									 conf_core.editor.increments_mm.clear,
 									 conf_core.editor.increments_mm.clear_min,
 									 conf_core.editor.increments_mm.clear_max,
-									 CE_SMALL, umm, width, increment_spin_button_cb,
-									 pcb_strdup(pathmm), _("Clear:"), NULL);
+									 CE_SMALL, umm, width, increment_spin_button_cb, pcb_strdup(pathmm), _("Clear:"), NULL);
 
 	ghid_coord_entry(hbox, NULL,
 									 conf_core.editor.increments_mil.clear,
 									 conf_core.editor.increments_mil.clear_min,
 									 conf_core.editor.increments_mil.clear_max,
-									 CE_SMALL, umil, width, increment_spin_button_cb,
-									 pcb_strdup(pathmil), NULL, NULL);
+									 CE_SMALL, umil, width, increment_spin_button_cb, pcb_strdup(pathmil), NULL, NULL);
 
 	label = gtk_label_new("");
 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
-	gtk_label_set_markup(GTK_LABEL(label),_("<small>For 'k' and '<shift>k' line clearance inside polygon size change actions</small>"));
+	gtk_label_set_markup(GTK_LABEL(label),
+											 _("<small>For 'k' and '<shift>k' line clearance inside polygon size change actions</small>"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 2);
 
@@ -911,18 +935,18 @@ static void config_increments_sect_create(GtkWidget * vbox)
 	gtk_widget_show_all(config_increments_vbox);
 }
 
-static GtkWidget *config_increments_table_attach(GtkWidget *table, int x, int y, int colspan, const char *text)
+static GtkWidget *config_increments_table_attach(GtkWidget * table, int x, int y, int colspan, const char *text)
 {
 	GtkWidget *box, *label;
 
 	box = gtk_vbox_new(FALSE, 0);
 	label = gtk_label_new(text);
 	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
-	gtk_table_attach(GTK_TABLE(table), box,  x,x+colspan,y,y+1,   0,0,10,2);
+	gtk_table_attach(GTK_TABLE(table), box, x, x + colspan, y, y + 1, 0, 0, 10, 2);
 	return label;
 }
 
-void config_increments_save(GtkButton *widget, save_ctx_t *ctx)
+void config_increments_save(GtkButton * widget, save_ctx_t * ctx)
 {
 	const char *paths[] = {
 		"editor/increments_mm",
@@ -954,10 +978,10 @@ static void config_increments_tab_create(GtkWidget * tab_vbox)
 	config_increments_tab_vbox = content_vbox;
 
 
-	catvbox = ghid_category_vbox (config_increments_vbox, "Increment Settings", 0, 0, TRUE, TRUE);
+	catvbox = ghid_category_vbox(config_increments_vbox, "Increment Settings", 0, 0, TRUE, TRUE);
 	config_increments_sect_create(catvbox);
 
-	catvbox = ghid_category_vbox (config_increments_vbox, _("Comparison table"), 0, 0, TRUE, TRUE);
+	catvbox = ghid_category_vbox(config_increments_vbox, _("Comparison table"), 0, 0, TRUE, TRUE);
 
 	/* increment summary table */
 	{
@@ -980,9 +1004,9 @@ static void config_increments_tab_create(GtkWidget * tab_vbox)
 		config_increments_table_attach(table, 0, 4, 1, "line");
 		config_increments_table_attach(table, 0, 5, 1, "clear");
 
-		for(y = 0; y < 4; y++)
-			for(x = 0; x < 4; x++)
-				config_increments_tbl[x][y] = config_increments_table_attach(table, x+1, y+2, 1, "n/a");
+		for (y = 0; y < 4; y++)
+			for (x = 0; x < 4; x++)
+				config_increments_tbl[x][y] = config_increments_table_attach(table, x + 1, y + 2, 1, "n/a");
 		increment_tbl_update();
 	}
 
@@ -1000,7 +1024,7 @@ static void config_library_apply(void)
 	pcb_fp_rehash();
 }
 
-static char *get_misc_col_data(int row, int col, lht_node_t *nd)
+static char *get_misc_col_data(int row, int col, lht_node_t * nd)
 {
 	if ((nd != NULL) && (col == 1)) {
 		char *out;
@@ -1014,10 +1038,10 @@ static char *get_misc_col_data(int row, int col, lht_node_t *nd)
 lht_doc_t *config_library_lst_doc;
 lht_node_t *config_library_lst;
 
-static void lht_clean_list(lht_node_t *lst)
+static void lht_clean_list(lht_node_t * lst)
 {
 	lht_node_t *n;
-	while(lst->data.list.first != NULL) {
+	while (lst->data.list.first != NULL) {
 		n = lst->data.list.first;
 		if (n->doc == NULL) {
 			if (lst->data.list.last == n)
@@ -1070,7 +1094,7 @@ static lht_node_t *config_library_list()
 	return config_library_lst;
 }
 
-static void pre_rebuild(gtk_conf_list_t *cl)
+static void pre_rebuild(gtk_conf_list_t * cl)
 {
 	lht_node_t *m;
 	lht_clean_list(config_library_lst);
@@ -1087,7 +1111,7 @@ static void pre_rebuild(gtk_conf_list_t *cl)
 	lht_clean_list(cl->lst);
 }
 
-static void post_rebuild(gtk_conf_list_t *cl)
+static void post_rebuild(gtk_conf_list_t * cl)
 {
 	conf_update("rc/library_search_paths");
 }
@@ -1112,7 +1136,7 @@ static GtkWidget *config_library_append_paths(int post_sep)
 			conf_native_t *nat = e->value;
 			char tmp[256];
 
-			sprintf(tmp, "  $(rc.path.%s)", e->key+8);
+			sprintf(tmp, "  $(rc.path.%s)", e->key + 8);
 			label = gtk_label_new(tmp);
 			gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
 			gtk_box_pack_start(GTK_BOX(vbox_key), label, FALSE, FALSE, 0);
@@ -1130,7 +1154,7 @@ static GtkWidget *config_library_append_paths(int post_sep)
 	return hbox;
 }
 
-void config_library_save(GtkButton *widget, save_ctx_t *ctx)
+void config_library_save(GtkButton * widget, save_ctx_t * ctx)
 {
 	const char *paths[] = {
 		"rc/library_search_paths",
@@ -1143,7 +1167,7 @@ void config_library_save(GtkButton *widget, save_ctx_t *ctx)
 static void config_library_tab_create(GtkWidget * tab_vbox)
 {
 	GtkWidget *vbox, *label, *entry, *content_vbox, *paths_box;
-	const char *cnames[] = {"configured path", "actual path on the filesystem", "config source"};
+	const char *cnames[] = { "configured path", "actual path on the filesystem", "config source" };
 
 	library_cl.num_cols = 3;
 	library_cl.col_names = cnames;
@@ -1165,7 +1189,9 @@ static void config_library_tab_create(GtkWidget * tab_vbox)
 	gtk_container_set_border_width(GTK_CONTAINER(content_vbox), 6);
 	vbox = ghid_category_vbox(content_vbox, _("Element Directories"), 4, 2, TRUE, FALSE);
 
-	label = gtk_label_new(_("Ordered list of footprint library search directories; use drag&drop to reorder.\nThe following $(variables) can be used in the path:\n\n"));
+	label =
+		gtk_label_new(_
+									("Ordered list of footprint library search directories; use drag&drop to reorder.\nThe following $(variables) can be used in the path:\n\n"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
 
@@ -1184,101 +1210,85 @@ static void config_library_tab_create(GtkWidget * tab_vbox)
 static GtkWidget *config_groups_table, *config_groups_vbox, *config_groups_window;
 
 static GtkWidget *layer_entry[PCB_MAX_LAYER];
-static GtkWidget *group_button[PCB_MAX_LAYERGRP + 2][PCB_MAX_LAYER];
-
-static gint config_layer_group[PCB_MAX_LAYERGRP + 2];
 
-static pcb_layer_group_t layer_groups,	/* Working copy */
- *lg_monitor;										/* Keep track if our working copy */
-										/* needs to be changed (new layout) */
-
-static gboolean groups_modified, groups_holdoff, layers_applying;
+static gboolean layers_applying;
 
 static const gchar *layer_info_text[] = {
-	N_("<h>Layer Names\n"),
-	N_("You may enter layer names for the layers drawn on the screen.\n"
-		 "The special 'component side' and 'solder side' are layers which\n"
-		 "will be printed out, so they must have in their group at least one\n"
-		 "of the other layers that are drawn on the screen.\n"),
+	N_("<h>Terminology\n"),
+	N_("A layer group is a physical layer of the board. A layer is a logical\n"
+		 "layer that is always part of exactly one layer group. A layer group may\n"
+		 "host zero or more layers. A logical layer is a canvas on which objects\n"
+		 "are drawn. Physical layer groups are listed on the left - group names\n"
+		 "are printed in the cross-section. Logical layers are listed on the right.\n"),
+	"\n",
+	N_("<h>Moving layers between groups\n(physical layer stack tab)\n"),
+	N_("Drag and drop a framed layer name. Potential target group is marked with\n"
+		 "horizontal line framing. Currently only copper groups can host layers.\n"),
 	"\n",
-	N_("<h>Layer Groups\n"),
-	N_("Each layer on the screen may be in its own group which allows the\n"
-		 "maximum number of board layers.  However, for boards with fewer\n"
-		 "layers, you may group layers together which will then print as a\n"
-		 "single layer on a printout.  This allows a visual color distinction\n"
-		 "to be displayed on the screen for signal groups which will print as\n" "a single layer\n"),
+	N_("<h>Moving layer groups\n(physical layer stack tab)\n"),
+	N_("Drag & drop the group by its name. Currently only copper groups can be moved.\n"
+	"\n"),
 	"\n",
-	N_("For example, for a 4 layer board a useful layer group arrangement\n"
-		 "can be to have 3 screen displayed layers grouped into the same group\n"
-		 "as the 'component side' and 'solder side' printout layers.  Then\n"
-		 "groups such as signals, ground, and supply traces can be color\n"
-		 "coded on the screen while printing as a single layer.  For this\n"
-		 "you would select buttons and enter names on the Setup page to\n" "structure four layer groups similar to this:\n"),
+	N_("<h>Creating a new group\n(physical layer stack tab)\n"),
+	N_("Drag the 'Add copper group' button and drop it in the layer stack.\n"
+	"\n"),
 	"\n",
-	N_("<b>Group 1:"),
-	"\n\t",
-	N_("solder"),
-	"\n\t",
-	N_("GND-solder"),
-	"\n\t",
-	N_("Vcc-solder"),
-	"\n\t",
-	N_("solder side"),
+	N_("<h>Removing a group\n(physical layer stack tab)\n"),
+	N_("Drag the 'Del copper group' button and drop it on the group to be removed.\n"
+		 "Layers in that group are removed too.\n"
+	"\n"),
 	"\n",
-	N_("<b>Group 2:"),
-	"\n\t",
-	N_("component"),
-	"\n\t",
-	N_("GND-component"),
-	"\n\t",
-	N_("Vcc-component"),
-	"\n\t",
-	N_("component side"),
+	N_("<h>Changing the display order of logical layers\n(Logical layers tab)\n"),
+	N_("Select the layer in the main window, press the up/down arrow buttons\n"
+		 "on the Logical layers tab. The display order of layers does not affect\n"
+		 "the physical location of the layer, that is determined by the grouping.\n"
+	"\n"),
 	"\n",
-	N_("<b>Group 3:"),
-	"\n\t",
-	N_("signal1"),
+	N_("<h>Remove a logical layer\n(Logical layers tab)\n"),
+	N_("Select the layer in the main window, press the Delete button\n"
+		 "on the Logical layers tab. The currently selected layer is removed, among\n"
+		 "with all objects hosted by that layer.\n"
+	"\n"),
 	"\n",
-	N_("<b>Group 4:"),
-	"\n\t",
-	N_("signal2"),
-	"\n"
+	N_("<h>Change the name of a logical layer\n(Logical layers tab)\n"),
+	N_("Select the layer in the main window, press the Edit button\n"
+		 "on the Logical layers tab.\n"
+	"\n"),
+	"\n",
+	N_("<h>Create a new logical layer\n(Logical layers tab)\n"),
+	N_("Select a layer in the main window, press the New button\n"
+		 "on the Logical layers tab. The new logical layer is inserted\n"
+		 "before the active layer (display order) and into the first (top)\n"
+		 "copper group in the physical stack.\n"
+	"\n")
 };
 
-static void config_layer_groups_radio_button_cb(GtkToggleButton * button, gpointer data)
-{
-	gint layer = GPOINTER_TO_INT(data) >> 8;
-	gint group = GPOINTER_TO_INT(data) & 0xff;
-
-	if (!gtk_toggle_button_get_active(button) || groups_holdoff)
-		return;
-	config_layer_group[layer] = group;
-	groups_modified = TRUE;
-}
-
 	/* Construct a layer group string.  Follow logic in WritePCBDataHeader(),
 	   |  but use g_string functions.
 	 */
-static gchar *make_layer_group_string(pcb_layer_group_t * lg)
+#warning layer TODO: kill this func, have a centralized C89 implementation and use g_strdup for glib
+static gchar *make_layer_group_string(pcb_layer_stack_t * lg)
 {
 	GString *string;
-	gint group, entry, layer;
+	pcb_layergrp_id_t group;
+	pcb_layer_id_t layer;
+	gint entry;
 
 	string = g_string_new("");
 
 	for (group = 0; group < pcb_max_group; group++) {
-		if (lg->Number[group] == 0)
+		if (lg->grp[group].len == 0)
 			continue;
-		for (entry = 0; entry < lg->Number[group]; entry++) {
-			layer = lg->Entries[group][entry];
-			if (layer == pcb_component_silk_layer)
+		for (entry = 0; entry < lg->grp[group].len; entry++) {
+			layer = lg->grp[group].lid[entry];
+			if ((pcb_layer_flags(layer) & PCB_LYT_TOP) && (pcb_layer_flags(layer) & PCB_LYT_COPPER))
 				string = g_string_append(string, "c");
-			else if (layer == pcb_solder_silk_layer)
+			else if ((pcb_layer_flags(layer) & PCB_LYT_BOTTOM) && (pcb_layer_flags(layer) & PCB_LYT_COPPER))
 				string = g_string_append(string, "s");
 			else
-				g_string_append_printf(string, "%d", layer + 1);
+				g_string_append_printf(string, "%ld", layer + 1);
 
-			if (entry != lg->Number[group] - 1)
+			if (entry != lg->grp[group].len - 1)
 				string = g_string_append(string, ",");
 		}
 		if (group != pcb_max_group - 1)
@@ -1289,175 +1299,9 @@ static gchar *make_layer_group_string(pcb_layer_group_t * lg)
 
 static void config_layers_apply(void)
 {
-	pcb_layer_t *layer;
-	const gchar *s;
-	gint group, i;
-	gint componentgroup = 0, soldergroup = 0;
-	gboolean layers_modified = FALSE;
-
-	/* Get each layer name entry and dup if modified into the PCB layer names
-	   |  and, if to use as default, the Settings layer names.
-	 */
-	for (i = 0; i < pcb_max_copper_layer; ++i) {
-		layer = &PCB->Data->Layer[i];
-		s = ghid_entry_get_text(layer_entry[i]);
-		if (dup_string((char**)&layer->Name, s))
-			layers_modified = TRUE;
-	}
-	/* Layer names can be changed from the menus and that can update the
-	   |  config.  So holdoff the loop.
-	 */
-	layers_applying = TRUE;
-	if (layers_modified)
-		ghid_layer_buttons_update();
-	layers_applying = FALSE;
-
-	if (groups_modified) {				/* If any group radio buttons were toggled. */
-		/* clear all entries and read layer by layer
-		 */
-		for (group = 0; group < pcb_max_group; group++)
-			layer_groups.Number[group] = 0;
-
-		for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-			group = config_layer_group[i] - 1;
-			layer_groups.Entries[group][layer_groups.Number[group]++] = i;
-
-			if (i == pcb_component_silk_layer)
-				componentgroup = group;
-			else if (i == pcb_solder_silk_layer)
-				soldergroup = group;
-		}
-
-		/* do some cross-checking
-		   |  solder-side and component-side must be in different groups
-		   |  solder-side and component-side must not be the only one in the group
-		 */
-		if (layer_groups.Number[soldergroup] <= 1 || layer_groups.Number[componentgroup] <= 1) {
-			pcb_message(PCB_MSG_ERROR, _("Both 'solder side' or 'component side' layers must have at least\n" "\tone other layer in their group.\n"));
-			return;
-		}
-		else if (soldergroup == componentgroup) {
-			pcb_message(PCB_MSG_ERROR, _("The 'solder side' and 'component side' layers are not allowed\n" "\tto be in the same layer group #\n"));
-			return;
-		}
-		PCB->LayerGroups = layer_groups;
-		ghid_invalidate_all();
-		groups_modified = FALSE;
-	}
-}
-
-static void config_layer_group_button_state_update(void)
-{
-	gint g, i;
-
-	/* Set button active corresponding to layer group state.
-	 */
-	groups_holdoff = TRUE;
-	for (g = 0; g < pcb_max_group; g++)
-		for (i = 0; i < layer_groups.Number[g]; i++) {
-/*			printf("layer %d in group %d\n", layer_groups.Entries[g][i], g +1); */
-			config_layer_group[layer_groups.Entries[g][i]] = g + 1;
-			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(group_button[layer_groups.Entries[g][i]][g]), TRUE);
-		}
-	groups_holdoff = FALSE;
-}
-
-static void layer_name_entry_cb(GtkWidget * entry, gpointer data)
-{
-	gint i = GPOINTER_TO_INT(data);
-	pcb_layer_t *layer;
-	const gchar *name;
-
-	layer = &PCB->Data->Layer[i];
-	name = ghid_entry_get_text(entry);
-	if (dup_string((char**)&layer->Name, name))
-		ghid_layer_buttons_update();
-}
-
-void ghid_config_groups_changed(void)
-{
-	GtkWidget *vbox, *table, *button, *label, *scrolled_window;
-	GSList *group;
-	gchar buf[32];
-	const char *name;
-	gint layer, i;
-
-	if (!config_groups_vbox)
-		return;
-	vbox = config_groups_vbox;
-
-	if (config_groups_table)
-		gtk_widget_destroy(config_groups_table);
-	if (config_groups_window)
-		gtk_widget_destroy(config_groups_window);
-
-	config_groups_window = scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-	gtk_widget_set_size_request(scrolled_window, (pcb_max_group + 1)*34, 300);
-	gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), 3);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-	gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
-	gtk_widget_show(scrolled_window);
-
-
-	table = gtk_table_new(pcb_max_copper_layer + 3, pcb_max_group + 1, FALSE);
-	config_groups_table = table;
-	gtk_table_set_row_spacings(GTK_TABLE(table), 3);
-	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), table);
-	gtk_widget_show(table);
-
-	layer_groups = PCB->LayerGroups;	/* working copy */
-	lg_monitor = &PCB->LayerGroups;	/* So can know if PCB changes on us */
-
-	label = gtk_label_new(_("Group #"));
-	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
-	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-
-	for (i = 1; i < pcb_max_group + 1; ++i) {
-		pcb_snprintf(buf, sizeof(buf), "% 3d", i);
-		label = gtk_label_new(buf);
-		gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-		gtk_table_attach_defaults(GTK_TABLE(table), label, i, i + 1, 0, 1);
-	}
-
-	/* Create a row of radio toggle buttons for layer.  So each layer
-	   |  can have an active radio button set for the group it needs to be in.
-	 */
-	for (layer = 0; layer < pcb_max_copper_layer + 2; ++layer) {
-		if (layer == pcb_component_silk_layer)
-			name = _("component side");
-		else if (layer == pcb_solder_silk_layer)
-			name = _("solder side");
-		else
-			name = (gchar *) PCB_UNKNOWN(PCB->Data->Layer[layer].Name);
-
-		if (layer >= pcb_max_copper_layer) {
-			label = gtk_label_new(name);
-			gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-			gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, layer + 1, layer + 2);
-		}
-		else {
-			layer_entry[layer] = gtk_entry_new();
-			gtk_entry_set_text(GTK_ENTRY(layer_entry[layer]), name);
-			gtk_table_attach_defaults(GTK_TABLE(table), layer_entry[layer], 0, 1, layer + 1, layer + 2);
-			g_signal_connect(G_OBJECT(layer_entry[layer]), "activate", G_CALLBACK(layer_name_entry_cb), GINT_TO_POINTER(layer));
-		}
-
-		group = NULL;
-		for (i = 0; i < pcb_max_group; ++i) {
-			button = gtk_radio_button_new(group);
-
-			group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button));
-			gtk_table_attach_defaults(GTK_TABLE(table), button, i + 1, i + 2, layer + 1, layer + 2);
-			g_signal_connect(G_OBJECT(button), "toggled",
-											 G_CALLBACK(config_layer_groups_radio_button_cb), GINT_TO_POINTER((layer << 8) | (i + 1)));
-			group_button[layer][i] = button;
-		}
-	}
-	gtk_widget_show_all(config_groups_vbox);
-	config_layer_group_button_state_update();
+	/* Nothing to do, changes got carried out right away */
 }
 
-
 static void edit_layer_button_cb(GtkWidget * widget, gchar * data)
 {
 	gchar **argv;
@@ -1470,7 +1314,19 @@ static void edit_layer_button_cb(GtkWidget * widget, gchar * data)
 	g_strfreev(argv);
 }
 
-void config_layers_save(GtkButton *widget, save_ctx_t *ctx)
+static void rename_layer_button_cb(GtkWidget * widget, gchar * data)
+{
+	char *name = pcb_gui->prompt_for("Enter the name of the layer:", CURRENT->Name);
+	if (name == NULL)
+		return;
+	if (strcmp(name, CURRENT->Name) == 0)
+		return;
+	free(CURRENT->Name);
+	CURRENT->Name = name;
+	pcb_event(PCB_EVENT_LAYERS_CHANGED, NULL);
+}
+
+void config_layers_save(GtkButton * widget, save_ctx_t * ctx)
 {
 	gchar *s;
 	pcb_cardinal_t n;
@@ -1485,7 +1341,7 @@ void config_layers_save(GtkButton *widget, save_ctx_t *ctx)
 	s = make_layer_group_string(&PCB->LayerGroups);
 
 	/* change default layer names to the current ones in dest */
-	for (n = 0; n < pcb_max_copper_layer; n++) {
+	for (n = 0; n < pcb_max_layer; n++) {
 		pcb_layer_t *layer;
 		char lnp[128];
 		lht_node_t *nd;
@@ -1506,8 +1362,9 @@ void config_layers_save(GtkButton *widget, save_ctx_t *ctx)
 
 static void config_layers_tab_create(GtkWidget * tab_vbox)
 {
-	GtkWidget *tabs, *vbox, *vbox1, *button, *text, *content_vbox;
+	GtkWidget *tabs, *vbox, *vbox1, *button, *text, *content_vbox, *prv;
 	GtkWidget *hbox, *arrow;
+	pcb_layer_id_t lid;
 	gint i;
 
 	content_vbox = gtk_vbox_new(FALSE, 0);
@@ -1517,8 +1374,19 @@ static void config_layers_tab_create(GtkWidget * tab_vbox)
 	tabs = gtk_notebook_new();
 	gtk_box_pack_start(GTK_BOX(content_vbox), tabs, TRUE, TRUE, 0);
 
-/* -- Change tab */
-	vbox = ghid_notebook_page(tabs, _("Change"), 0, 6);
+/* -- Layer stack tab */
+	vbox = ghid_notebook_page(tabs, _("Physical layer stack"), 0, 6);
+	if (pcb_layer_list(PCB_LYT_CSECT, &lid, 1) > 0) {
+		pcb_gtk_preview_t *p;
+		prv = pcb_gtk_preview_layer_new(gport, ghid_init_drawing_widget, ghid_preview_expose, lid);
+		gtk_box_pack_start(GTK_BOX(vbox), prv, TRUE, TRUE, 0);
+		p = (pcb_gtk_preview_t *) prv;
+		p->mouse_cb = pcb_stub_draw_csect_mouse_ev;
+		p->overlay_draw_cb = pcb_stub_draw_csect_overlay;
+	}
+
+/* -- Logical layers tab */
+	vbox = ghid_notebook_page(tabs, _("Logical layers"), 0, 6);
 	vbox1 = ghid_category_vbox(vbox, _("Operations on currently selected layer:"), 4, 2, TRUE, TRUE);
 
 	button = gtk_button_new();
@@ -1543,6 +1411,12 @@ static void config_layers_tab_create(GtkWidget * tab_vbox)
 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
 
+	button = gtk_button_new_from_stock(GTK_STOCK_EDIT);
+	g_signal_connect(G_OBJECT(button), (gchar *) "clicked", G_CALLBACK(rename_layer_button_cb), NULL);
+	hbox = gtk_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+
 	vbox1 = ghid_category_vbox(vbox, _("Add new layer above currently selected layer:"), 4, 2, TRUE, TRUE);
 	button = gtk_button_new_from_stock(GTK_STOCK_ADD);
 	g_signal_connect(G_OBJECT(button), (gchar *) "clicked", G_CALLBACK(edit_layer_button_cb), (gchar *) "-1,c");
@@ -1550,19 +1424,6 @@ static void config_layers_tab_create(GtkWidget * tab_vbox)
 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
 
-/* -- Groups tab */
-	vbox = ghid_notebook_page(tabs, _("Groups"), 0, 6);
-	hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
-
-	config_groups_vbox = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), config_groups_vbox, TRUE, TRUE, 0);
-	ghid_config_groups_changed();
-
-	/* A dummy vbox on the right to take up excess horizontal space so the layer list is not scretched horizontally */
-	vbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
-
 /* -- Info tab */
 	vbox = ghid_notebook_page(tabs, _("Info"), 0, 6);
 
@@ -1581,22 +1442,11 @@ void ghid_config_layer_name_update(gchar * name, gint layer)
 	if (!config_window || layers_applying || !name)
 		return;
 	gtk_entry_set_text(GTK_ENTRY(layer_entry[layer]), name);
-
-	/* If we get a config layer name change because a new PCB is loaded
-	   |  or new layout started, need to change our working layer group copy.
-	 */
-	if (lg_monitor != &PCB->LayerGroups) {
-		layer_groups = PCB->LayerGroups;
-		lg_monitor = &PCB->LayerGroups;
-		config_layer_group_button_state_update();
-		groups_modified = FALSE;
-	}
 }
 
 	/* -------------- The Colors config page ----------------
 	 */
-static GtkWidget *config_colors_vbox,
-	*config_colors_tab_vbox;
+static GtkWidget *config_colors_vbox, *config_colors_tab_vbox;
 
 static void config_colors_tab_create(GtkWidget * tab_vbox);
 
@@ -1607,14 +1457,28 @@ typedef struct {
 	GtkWidget *button;
 } cfg_color_idx_t;
 
-static void config_color_set_cb(GtkWidget * button, cfg_color_idx_t *ci)
+static void config_color_set_cb(GtkWidget * button, cfg_color_idx_t * ci)
 {
 	GdkColor new_color;
-	const char *str;
+	const char *str, *lcpath = "appearance/color/layer", *lspath = "appearance/color/layer_selected";
 
 	gtk_color_button_get_color(GTK_COLOR_BUTTON(button), &new_color);
 	str = ghid_get_color_name(&new_color);
 
+	if ((strcmp(ci->cfg->hash_path, lcpath) == 0) || (strcmp(ci->cfg->hash_path, lspath) == 0)) {
+		/* if the design color list is empty, we should create it and copy
+		   all current colors. If we don't, and conf_set() does it for items
+		   lower than ci->idx, it will create all colors with empty string value,
+		   ruining the color table. */
+		if (conf_lht_get_at(CFR_DESIGN, ci->cfg->hash_path, 0) == NULL) {
+			int n;
+			conf_native_t *nat = conf_get_field(ci->cfg->hash_path);
+			if (nat != NULL)
+				for(n = 0; (n < PCB_MAX_LAYER) && (n < nat->array_size); n++)
+					conf_set(CFR_DESIGN, ci->cfg->hash_path, n,  nat->val.color[n], POL_OVERWRITE);
+		}
+	}
+
 	if (conf_set(CFR_DESIGN, ci->cfg->hash_path, ci->idx, str, POL_OVERWRITE) == 0) {
 		ghid_set_special_colors(ci->cfg);
 		ghid_layer_buttons_color_update();
@@ -1622,7 +1486,7 @@ static void config_color_set_cb(GtkWidget * button, cfg_color_idx_t *ci)
 	}
 }
 
-static void config_color_button_create(GtkWidget * box, conf_native_t *cfg, int idx)
+static void config_color_button_create(GtkWidget * box, conf_native_t * cfg, int idx)
 {
 	GtkWidget *hbox, *label;
 	gchar *title;
@@ -1631,13 +1495,14 @@ static void config_color_button_create(GtkWidget * box, conf_native_t *cfg, int
 	hbox = gtk_hbox_new(FALSE, 6);
 	gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
 
-	if (ci == NULL) {
+	if ((ci == NULL) || (idx > 0)) {
 #warning LEAK: this is never free()d
 		ci = malloc(sizeof(cfg_color_idx_t));
 		ci->cfg = cfg;
 		ci->idx = idx;
 		ci->color = calloc(sizeof(GdkColor), cfg->array_size);
-		conf_hid_set_data(cfg, ghid_conf_id, ci);
+		if (idx == 0)
+			conf_hid_set_data(cfg, ghid_conf_id, ci);
 	}
 
 	ghid_map_color_string(cfg->val.color[idx], &(ci->color[idx]));
@@ -1653,10 +1518,10 @@ static void config_color_button_create(GtkWidget * box, conf_native_t *cfg, int
 	g_signal_connect(G_OBJECT(ci->button), "color-set", G_CALLBACK(config_color_set_cb), ci);
 }
 
-void config_color_button_update(conf_native_t *cfg, int idx)
+void config_color_button_update(conf_native_t * cfg, int idx)
 {
 	if (idx < 0) {
-		for(idx = 0; idx < cfg->array_size; idx++)
+		for (idx = 0; idx < cfg->array_size; idx++)
 			config_color_button_update(cfg, idx);
 	}
 	else {
@@ -1667,7 +1532,7 @@ void config_color_button_update(conf_native_t *cfg, int idx)
 	}
 }
 
-void config_colors_tab_create_scalar(GtkWidget *parent_vbox, const char *path_prefix, int selected)
+void config_colors_tab_create_scalar(GtkWidget * parent_vbox, const char *path_prefix, int selected)
 {
 	htsp_entry_t *e;
 	int pl = strlen(path_prefix);
@@ -1682,18 +1547,18 @@ void config_colors_tab_create_scalar(GtkWidget *parent_vbox, const char *path_pr
 	}
 }
 
-void config_colors_tab_create_array(GtkWidget *parent_vbox, const char *path)
+void config_colors_tab_create_array(GtkWidget * parent_vbox, const char *path)
 {
 	conf_native_t *cfg = conf_get_field(path);
 	int n;
 	if (cfg->type != CFN_COLOR)
 		return;
 
-	for(n = 0; n < cfg->used; n++)
+	for (n = 0; n < cfg->used; n++)
 		config_color_button_create(parent_vbox, cfg, n);
 }
 
-void config_colors_save(GtkButton *widget, save_ctx_t *ctx)
+void config_colors_save(GtkButton * widget, save_ctx_t * ctx)
 {
 	const char *paths[] = {
 		"*appearance/color/",
@@ -1776,9 +1641,9 @@ static GtkWidget *config_page_create(GtkTreeStore * tree, GtkTreeIter * iter, Gt
 void ghid_config_handle_units_changed(void)
 {
 	char *text = pcb_strdup_printf("<b>%s</b>",
-																		conf_core.editor.grid_unit->in_suffix);
-	ghid_set_cursor_position_labels();
-	gtk_label_set_markup(GTK_LABEL(ghidgui->grid_units_label), text);
+																 conf_core.editor.grid_unit->in_suffix);
+	ghid_set_cursor_position_labels(&ghidgui->cps, conf_hid_gtk.plugins.hid_gtk.compact_vertical);
+	gtk_label_set_markup(GTK_LABEL(ghidgui->cps.grid_units_label), text);
 	free(text);
 
 	if (config_sizes_vbox) {
@@ -1834,14 +1699,14 @@ static void config_selection_changed_cb(GtkTreeSelection * selection, gpointer d
 		return;
 	gtk_tree_model_get(model, &iter, CONFIG_PAGE_COLUMN, &page, CONFIG_PAGE_UPDATE_CB, &cb, CONFIG_PAGE_DATA, &page_data, -1);
 	if (cb != NULL) {
-		void (*fnc)(void *data) = pcb_cast_d2f(cb);
+		void (*fnc) (void *data) = pcb_cast_d2f(cb);
 		fnc(page_data);
 	}
 	gtk_notebook_set_current_page(config_notebook, page);
 }
 
 /* Create a root (e.g. Config PoV) top level in the preference tree; iter is output and acts as a parent for further nodes */
-static void config_tree_sect(GtkTreeStore *model, GtkTreeIter *parent, GtkTreeIter *iter, const char *name, const char *desc)
+static void config_tree_sect(GtkTreeStore * model, GtkTreeIter * parent, GtkTreeIter * iter, const char *name, const char *desc)
 {
 	GtkWidget *vbox, *label;
 	gtk_tree_store_append(model, iter, parent);
@@ -1854,7 +1719,8 @@ static void config_tree_sect(GtkTreeStore *model, GtkTreeIter *parent, GtkTreeIt
 }
 
 /* Create a leaf node with a custom tab */
-static GtkWidget *config_tree_leaf_(GtkTreeStore *model, GtkTreeIter *parent, const char *name, void (*tab_create)(GtkWidget *tab_vbox), GtkTreeIter *iter)
+static GtkWidget *config_tree_leaf_(GtkTreeStore * model, GtkTreeIter * parent, const char *name,
+																		void (*tab_create) (GtkWidget * tab_vbox), GtkTreeIter * iter)
 {
 	GtkWidget *vbox = NULL;
 
@@ -1867,7 +1733,8 @@ static GtkWidget *config_tree_leaf_(GtkTreeStore *model, GtkTreeIter *parent, co
 	return vbox;
 }
 
-static GtkWidget *config_tree_leaf(GtkTreeStore *model, GtkTreeIter *parent, const char *name, void (*tab_create)(GtkWidget *tab_vbox))
+static GtkWidget *config_tree_leaf(GtkTreeStore * model, GtkTreeIter * parent, const char *name,
+																	 void (*tab_create) (GtkWidget * tab_vbox))
 {
 	GtkTreeIter iter;
 	return config_tree_leaf_(model, parent, name, tab_create, &iter);
@@ -1892,7 +1759,7 @@ static struct {
 	GtkWidget *edit_list;
 
 	GtkWidget *result;
-	GtkWidget *finalize; /* finalzie hbox */
+	GtkWidget *finalize;					/* finalzie hbox */
 
 	GtkWidget *btn_apply;
 	GtkWidget *btn_reset;
@@ -1912,14 +1779,14 @@ static struct {
 	conf_native_t *nat;
 } auto_tab_widgets;
 
-static void config_auto_src_changed_cb(GtkTreeView *tree, void *data);
-static void config_auto_idx_changed_cb(GtkTreeView *tree, void *data);
-static void config_auto_idx_create_cb(GtkButton *btn, void *data);
-static void config_auto_idx_remove_cb(GtkButton *btn, void *data);
-static void config_auto_apply_cb(GtkButton *btn, void *data);
-static void config_auto_reset_cb(GtkButton *btn, void *data);
-static void config_auto_remove_cb(GtkButton *btn, void *data);
-static void config_auto_create_cb(GtkButton *btn, void *data);
+static void config_auto_src_changed_cb(GtkTreeView * tree, void *data);
+static void config_auto_idx_changed_cb(GtkTreeView * tree, void *data);
+static void config_auto_idx_create_cb(GtkButton * btn, void *data);
+static void config_auto_idx_remove_cb(GtkButton * btn, void *data);
+static void config_auto_apply_cb(GtkButton * btn, void *data);
+static void config_auto_reset_cb(GtkButton * btn, void *data);
+static void config_auto_remove_cb(GtkButton * btn, void *data);
+static void config_auto_create_cb(GtkButton * btn, void *data);
 static void config_page_update_auto(void *data);
 
 /* Evaluates to 1 if the user canedit the config for this role */
@@ -1955,13 +1822,13 @@ static void config_auto_tab_create(GtkWidget * tab_vbox, const char *basename)
 
 	/* upper-left: sources */
 	{
-		static const char *col_names[] = {"role", "prio", "policy", "value"};
-		static GType ty[] = {G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING};
+		static const char *col_names[] = { "role", "prio", "policy", "value" };
+		static GType ty[] = { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING };
 		const char **s;
-		int n, num_cols = sizeof(col_names)/sizeof(col_names[0]);
+		int n, num_cols = sizeof(col_names) / sizeof(col_names[0]);
 		auto_tab_widgets.src_t = gtk_tree_view_new();
 		auto_tab_widgets.src_l = gtk_list_store_newv(num_cols, ty);
-		for(n = 0, s = col_names; n < num_cols; n++,s++) {
+		for (n = 0, s = col_names; n < num_cols; n++, s++) {
 			GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
 			gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(auto_tab_widgets.src_t), -1, *s, renderer, "text", n, NULL);
 		}
@@ -1977,17 +1844,15 @@ static void config_auto_tab_create(GtkWidget * tab_vbox, const char *basename)
 	auto_tab_widgets.src = gtk_label_new("source");
 	gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.src, FALSE, FALSE, 0);
 
-	{ /* array index bar */
+	{															/* array index bar */
 		auto_tab_widgets.edit_idx_box = gtk_hbox_new(FALSE, 4);
 		gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.edit_idx_box, FALSE, FALSE, 4);
 
 		gtk_box_pack_start(GTK_BOX(auto_tab_widgets.edit_idx_box), gtk_label_new("Array index:"), FALSE, FALSE, 4);
 
-		auto_tab_widgets.edit_idx_adj = GTK_ADJUSTMENT(gtk_adjustment_new(10,
-		                                                                  0, /* min */
-		                                                                  4,
-		                                                                  1, 1, /* steps */
-		                                                                  0.0));
+		auto_tab_widgets.edit_idx_adj = GTK_ADJUSTMENT(gtk_adjustment_new(10, 0,	/* min */
+																																			4, 1, 1,	/* steps */
+																																			0.0));
 		g_signal_connect(G_OBJECT(auto_tab_widgets.edit_idx_adj), "value-changed", G_CALLBACK(config_auto_idx_changed_cb), NULL);
 		auto_tab_widgets.edit_idx = gtk_spin_button_new(auto_tab_widgets.edit_idx_adj, 1, 4);
 		gtk_box_pack_start(GTK_BOX(auto_tab_widgets.edit_idx_box), auto_tab_widgets.edit_idx, FALSE, FALSE, 4);
@@ -2007,28 +1872,22 @@ static void config_auto_tab_create(GtkWidget * tab_vbox, const char *basename)
 	auto_tab_widgets.edit_string = gtk_entry_new();
 	gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.edit_string, FALSE, FALSE, 4);
 
-	auto_tab_widgets.edit_coord = ghid_coord_entry_new(10, PCB_MM_TO_COORD(1000), 0, conf_core.editor.grid_unit, CE_TINY);
+	auto_tab_widgets.edit_coord = pcb_gtk_coord_entry_new(10, PCB_MM_TO_COORD(1000), 0, conf_core.editor.grid_unit, CE_TINY);
 	gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.edit_coord, FALSE, FALSE, 4);
 
-	auto_tab_widgets.edit_int_adj = GTK_ADJUSTMENT(gtk_adjustment_new(10,
-	                                                                  0, /* min */
-	                                                                  20000,
-	                                                                  1, 10, /* steps */
-	                                                                  0.0));
+	auto_tab_widgets.edit_int_adj = GTK_ADJUSTMENT(gtk_adjustment_new(10, 0,	/* min */
+																																		20000, 1, 10,	/* steps */
+																																		0.0));
 	auto_tab_widgets.edit_int = gtk_spin_button_new(auto_tab_widgets.edit_int_adj, 1, 4);
 	gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.edit_int, FALSE, FALSE, 4);
 
-	auto_tab_widgets.edit_real_adj = GTK_ADJUSTMENT(gtk_adjustment_new(10,
-	                                                                   0, /* min */
-	                                                                   20000,
-	                                                                   1, 10, /* steps */
-	                                                                   0.0));
+	auto_tab_widgets.edit_real_adj = GTK_ADJUSTMENT(gtk_adjustment_new(10, 0,	/* min */
+																																		 20000, 1, 10,	/* steps */
+																																		 0.0));
 	auto_tab_widgets.edit_real = gtk_spin_button_new(auto_tab_widgets.edit_real_adj, 1, 4);
 	gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.edit_real, FALSE, FALSE, 4);
 
-	ghid_check_button_connected(src_right, &auto_tab_widgets.edit_boolean, 0,
-	                            TRUE, FALSE, FALSE, 2,
-	                            NULL, NULL, NULL);
+	ghid_check_button_connected(src_right, &auto_tab_widgets.edit_boolean, 0, TRUE, FALSE, FALSE, 2, NULL, NULL, NULL);
 
 	auto_tab_widgets.edit_color = gtk_color_button_new();
 	gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.edit_color, FALSE, FALSE, 4);
@@ -2038,8 +1897,8 @@ static void config_auto_tab_create(GtkWidget * tab_vbox, const char *basename)
 	gtk_combo_box_append_text(GTK_COMBO_BOX(auto_tab_widgets.edit_unit), "mil");
 	gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.edit_unit, FALSE, FALSE, 4);
 
-	{ /* list */
-		static const char *col_names[] = {"list items"};
+	{															/* list */
+		static const char *col_names[] = { "list items" };
 		auto_tab_widgets.cl.num_cols = 1;
 		auto_tab_widgets.cl.col_names = col_names;
 		auto_tab_widgets.cl.col_data = 0;
@@ -2072,7 +1931,7 @@ static void config_auto_tab_create(GtkWidget * tab_vbox, const char *basename)
 
 		gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.finalize, FALSE, FALSE, 0);
 	}
-	
+
 	auto_tab_widgets.txt_apply = gtk_label_new("");
 	gtk_box_pack_start(GTK_BOX(src_right), auto_tab_widgets.txt_apply, FALSE, FALSE, 0);
 	gtk_misc_set_alignment(GTK_MISC(auto_tab_widgets.txt_apply), 0., 0.);
@@ -2092,13 +1951,13 @@ static void config_auto_tab_create(GtkWidget * tab_vbox, const char *basename)
 	gtk_misc_set_alignment(GTK_MISC(w), 0., 0.);
 
 	{
-		static const char *col_names[] = {"index", "role & prio", "value"};
-		static GType ty[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING};
+		static const char *col_names[] = { "index", "role & prio", "value" };
+		static GType ty[] = { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING };
 		const char **s;
-		int n, num_cols = sizeof(col_names)/sizeof(col_names[0]);
+		int n, num_cols = sizeof(col_names) / sizeof(col_names[0]);
 		auto_tab_widgets.res_t = gtk_tree_view_new();
 		auto_tab_widgets.res_l = gtk_list_store_newv(num_cols, ty);
-		for(n = 0, s = col_names; n < num_cols; n++,s++) {
+		for (n = 0, s = col_names; n < num_cols; n++, s++) {
 			GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
 			gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(auto_tab_widgets.res_t), -1, *s, renderer, "text", n, NULL);
 		}
@@ -2125,7 +1984,7 @@ static void config_auto_src_hide(void)
 
 /* Return the nth child of a list - only if it's really a list; if idx < 0,
    use the index adjustment value */
-static lht_node_t *config_auto_get_nth(const lht_node_t *list, int idx)
+static lht_node_t *config_auto_get_nth(const lht_node_t * list, int idx)
 {
 	const lht_node_t *nd;
 
@@ -2135,13 +1994,13 @@ static lht_node_t *config_auto_get_nth(const lht_node_t *list, int idx)
 	if (idx < 0)
 		idx = gtk_adjustment_get_value(auto_tab_widgets.edit_idx_adj);
 
-	for(nd = list->data.list.first; (idx > 0) && (nd != NULL); nd = nd->next, idx--) ;
+	for (nd = list->data.list.first; (idx > 0) && (nd != NULL); nd = nd->next, idx--);
 
-	return (lht_node_t *)nd;
+	return (lht_node_t *) nd;
 }
 
 /* set up all source edit widgets for a lihata source node */
-static void config_auto_src_show(lht_node_t *nd)
+static void config_auto_src_show(lht_node_t * nd)
 {
 	conf_native_t *nat = auto_tab_widgets.nat;
 	char *tmp;
@@ -2176,78 +2035,80 @@ static void config_auto_src_show(lht_node_t *nd)
 
 	memset(&citem, 0, sizeof(citem));
 
-	switch(nat->type) {
-		case CFN_STRING:
-			gtk_entry_set_text(GTK_ENTRY(auto_tab_widgets.edit_string), nd->data.text.value);
-			gtk_widget_show(auto_tab_widgets.edit_string);
-			break;
-		case CFN_COORD:
-			{
-				pcb_coord_t coord = 0;
-				citem.coord = &coord;
-				conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
-				ghid_coord_entry_set_value(GHID_COORD_ENTRY(auto_tab_widgets.edit_coord), coord);
-				gtk_widget_show(auto_tab_widgets.edit_coord);
-			}
-			break;
-		case CFN_INTEGER:
-			{
-				long i = 0;
-				citem.integer = &i;
-				conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
-				gtk_adjustment_set_value(GTK_ADJUSTMENT(auto_tab_widgets.edit_int_adj), i);
-				gtk_widget_show(auto_tab_widgets.edit_int);
-			}
-			break;
-		case CFN_REAL:
-			{
-				double d = 0;
-				citem.real = &d;
-				conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
-				gtk_adjustment_set_value(GTK_ADJUSTMENT(auto_tab_widgets.edit_real_adj), d);
-				gtk_widget_show(auto_tab_widgets.edit_real);
-			}
-			break;
-		case CFN_BOOLEAN:
-			{
-				int b = 0;
-				citem.boolean = &b;
-				conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
-				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_tab_widgets.edit_boolean), b);
-				gtk_widget_show(auto_tab_widgets.edit_boolean);
-			}
-			break;
-		case CFN_COLOR:
-			ghid_map_color_string(nd->data.text.value, &auto_tab_widgets.color);
-			gtk_color_button_set_color(GTK_COLOR_BUTTON(auto_tab_widgets.edit_color), &auto_tab_widgets.color);
-			gtk_widget_show(auto_tab_widgets.edit_color);
-			break;
-		case CFN_UNIT:
-			{
-				const pcb_unit_t *u = NULL;
-				citem.unit = &u;
-				conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
-				if (citem.unit[0] == NULL)
-					l = -1;
-				else if (strcmp(citem.unit[0]->suffix, "mm") == 0)
-					l = 0;
-				else if (strcmp(citem.unit[0]->suffix, "mil") == 0)
-					l = 1;
-				else
-					l = -1;
-				gtk_combo_box_set_active(GTK_COMBO_BOX(auto_tab_widgets.edit_unit), l);
-				gtk_widget_show(auto_tab_widgets.edit_unit);
-			}
-			break;
-		case CFN_LIST:
-			gtk_conf_list_set_list(&auto_tab_widgets.cl, nd);
-			gtk_widget_show(auto_tab_widgets.edit_list);
-			break;
+	switch (nat->type) {
+	case CFN_STRING:
+		gtk_entry_set_text(GTK_ENTRY(auto_tab_widgets.edit_string), nd->data.text.value);
+		gtk_widget_show(auto_tab_widgets.edit_string);
+		break;
+	case CFN_COORD:
+		{
+			pcb_coord_t coord = 0;
+			citem.coord = &coord;
+			conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
+			pcb_gtk_coord_entry_set_value(GHID_COORD_ENTRY(auto_tab_widgets.edit_coord), coord);
+			gtk_widget_show(auto_tab_widgets.edit_coord);
+		}
+		break;
+	case CFN_INTEGER:
+		{
+			long i = 0;
+			citem.integer = &i;
+			conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
+			gtk_adjustment_set_value(GTK_ADJUSTMENT(auto_tab_widgets.edit_int_adj), i);
+			gtk_widget_show(auto_tab_widgets.edit_int);
+		}
+		break;
+	case CFN_REAL:
+		{
+			double d = 0;
+			citem.real = &d;
+			conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
+			gtk_adjustment_set_value(GTK_ADJUSTMENT(auto_tab_widgets.edit_real_adj), d);
+			gtk_widget_show(auto_tab_widgets.edit_real);
+		}
+		break;
+	case CFN_BOOLEAN:
+		{
+			int b = 0;
+			citem.boolean = &b;
+			conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
+			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_tab_widgets.edit_boolean), b);
+			gtk_widget_show(auto_tab_widgets.edit_boolean);
+		}
+		break;
+	case CFN_COLOR:
+		ghid_map_color_string(nd->data.text.value, &auto_tab_widgets.color);
+		gtk_color_button_set_color(GTK_COLOR_BUTTON(auto_tab_widgets.edit_color), &auto_tab_widgets.color);
+		gtk_widget_show(auto_tab_widgets.edit_color);
+		break;
+	case CFN_UNIT:
+		{
+			const pcb_unit_t *u = NULL;
+			citem.unit = &u;
+			conf_parse_text(&citem, 0, nat->type, nd->data.text.value, nd);
+			if (citem.unit[0] == NULL)
+				l = -1;
+			else if (strcmp(citem.unit[0]->suffix, "mm") == 0)
+				l = 0;
+			else if (strcmp(citem.unit[0]->suffix, "mil") == 0)
+				l = 1;
+			else
+				l = -1;
+			gtk_combo_box_set_active(GTK_COMBO_BOX(auto_tab_widgets.edit_unit), l);
+			gtk_widget_show(auto_tab_widgets.edit_unit);
+		}
+		break;
+	case CFN_LIST:
+		gtk_conf_list_set_list(&auto_tab_widgets.cl, nd);
+		gtk_widget_show(auto_tab_widgets.edit_list);
+		break;
+	case CFN_INCREMENTS:
+		break;
 	}
 	gtk_widget_show(auto_tab_widgets.finalize);
 }
 
-static void config_auto_res_show_add(const char *s_idx, const confprop_t *prop, const char *val)
+static void config_auto_res_show_add(const char *s_idx, const confprop_t * prop, const char *val)
 {
 	GtkTreeIter iter;
 	char s_pol_prio[256];
@@ -2258,11 +2119,7 @@ static void config_auto_res_show_add(const char *s_idx, const confprop_t *prop,
 		sprintf(s_pol_prio, "%d", prop->prio);
 
 	gtk_list_store_append(auto_tab_widgets.res_l, &iter);
-	gtk_list_store_set(auto_tab_widgets.res_l, &iter,
-		0, s_idx,
-		1, s_pol_prio,
-		2, val,
-		-1);
+	gtk_list_store_set(auto_tab_widgets.res_l, &iter, 0, s_idx, 1, s_pol_prio, 2, val, -1);
 }
 
 /* Fill in the result table on the bottom using the native value */
@@ -2276,24 +2133,24 @@ static void config_auto_res_show(void)
 
 	/* This code addmitedly does not handle array of lists - for now; once the
 	   list-loop below is moved to config_auto_res_show_add, it will work */
-	if(nat->type == CFN_LIST) {
+	if (nat->type == CFN_LIST) {
 		conf_listitem_t *n;
-		for(n = conflist_first(nat->val.list); n != NULL; n = conflist_next(n)) {
+		for (n = conflist_first(nat->val.list); n != NULL; n = conflist_next(n)) {
 			gds_init(&buff);
-			conf_print_native_field((conf_pfn)pcb_append_printf, &buff, 0, &n->val, n->type, &n->prop, 0);
+			conf_print_native_field((conf_pfn) pcb_append_printf, &buff, 0, &n->val, n->type, &n->prop, 0);
 			config_auto_res_show_add("0", &n->prop, buff.array);
 			gds_uninit(&buff);
 		}
 	}
 	else {
 		pcb_cardinal_t n;
-		for(n = 0; n < nat->used; n++) {
+		for (n = 0; n < nat->used; n++) {
 			if (nat->array_size >= 2)
 				sprintf(s_idx, "%d", n);
 			else
 				*s_idx = '\0';
 			gds_init(&buff);
-			conf_print_native_field((conf_pfn)pcb_append_printf, &buff, 0, &nat->val, nat->type, nat->prop, n);
+			conf_print_native_field((conf_pfn) pcb_append_printf, &buff, 0, &nat->val, nat->type, nat->prop, n);
 			config_auto_res_show_add(s_idx, &nat->prop[n], buff.array);
 			gds_uninit(&buff);
 		}
@@ -2317,7 +2174,7 @@ static conf_role_t config_auto_get_edited_role(void)
 	return role;
 }
 
-static conf_auto_set_edited_role(conf_role_t r)
+static void conf_auto_set_edited_role(conf_role_t r)
 {
 	GtkTreePath *p = gtk_tree_path_new_from_indices(r, -1);
 	gtk_tree_view_set_cursor(GTK_TREE_VIEW(auto_tab_widgets.src_t), p, NULL, 0);
@@ -2326,7 +2183,7 @@ static conf_auto_set_edited_role(conf_role_t r)
 
 
 /* Update the conf item edit section; called when a source is clicked */
-static void config_auto_src_changed_cb(GtkTreeView *tree, void *data)
+static void config_auto_src_changed_cb(GtkTreeView * tree, void *data)
 {
 	int role = config_auto_get_edited_role(), idx, len = 0;
 	lht_node_t *nd;
@@ -2342,7 +2199,7 @@ static void config_auto_src_changed_cb(GtkTreeView *tree, void *data)
 			allow_idx = 0;
 			if (nd->type == LHT_LIST) {
 				lht_node_t *n;
-				for(n = nd->data.list.first; n != NULL; n = n->next)
+				for (n = nd->data.list.first; n != NULL; n = n->next)
 					len++;
 			}
 		}
@@ -2371,15 +2228,15 @@ static void config_auto_src_changed_cb(GtkTreeView *tree, void *data)
 	/* adjust array index widget state and max according to our actual array size */
 	idx = gtk_adjustment_get_value(auto_tab_widgets.edit_idx_adj);
 	if (idx >= len)
-		gtk_adjustment_set_value(auto_tab_widgets.edit_idx_adj, len-1);
+		gtk_adjustment_set_value(auto_tab_widgets.edit_idx_adj, len - 1);
 
-	gtk_adjustment_set_upper(auto_tab_widgets.edit_idx_adj, len-1);
+	gtk_adjustment_set_upper(auto_tab_widgets.edit_idx_adj, len - 1);
 
 	if ((allow_idx) && (auto_tab_widgets.nat->array_size > 1))
 		gtk_widget_show(auto_tab_widgets.edit_idx_box);
 }
 
-static void config_auto_idx_changed_cb(GtkTreeView *tree, void *data)
+static void config_auto_idx_changed_cb(GtkTreeView * tree, void *data)
 {
 	int role = config_auto_get_edited_role();
 	if (role != CFR_invalid) {
@@ -2404,12 +2261,12 @@ static void config_auto_idx_deladd_cb(int del)
 	}
 }
 
-static void config_auto_idx_create_cb(GtkButton *btn, void *data)
+static void config_auto_idx_create_cb(GtkButton * btn, void *data)
 {
 	config_auto_idx_deladd_cb(0);
 }
 
-static void config_auto_idx_remove_cb(GtkButton *btn, void *data)
+static void config_auto_idx_remove_cb(GtkButton * btn, void *data)
 {
 	config_auto_idx_deladd_cb(1);
 }
@@ -2438,7 +2295,7 @@ static void config_auto_save(conf_role_t role)
 	conf_save_file(NULL, pcbfn, role, NULL);
 }
 
-static void config_auto_apply_cb(GtkButton *btn, void *data)
+static void config_auto_apply_cb(GtkButton * btn, void *data)
 {
 	conf_native_t *nat = auto_tab_widgets.nat;
 	conf_role_t role = config_auto_get_edited_role();
@@ -2447,63 +2304,63 @@ static void config_auto_apply_cb(GtkButton *btn, void *data)
 	int arr_idx = -1;
 	int update_clr = 0;
 
-	switch(nat->type) {
-		case CFN_STRING:
-			new_val = gtk_entry_get_text(GTK_ENTRY(auto_tab_widgets.edit_string));
-			break;
-		case CFN_COORD:
-			ghid_coord_entry_get_value_str(auto_tab_widgets.edit_coord, buff, sizeof(buff));
-			new_val = buff;
-			break;
-		case CFN_INTEGER:
-			sprintf(buff, "%.0f", gtk_adjustment_get_value(GTK_ADJUSTMENT(auto_tab_widgets.edit_int_adj)));
+	switch (nat->type) {
+	case CFN_STRING:
+		new_val = gtk_entry_get_text(GTK_ENTRY(auto_tab_widgets.edit_string));
+		break;
+	case CFN_COORD:
+		pcb_gtk_coord_entry_get_value_str(GHID_COORD_ENTRY(auto_tab_widgets.edit_coord), buff, sizeof(buff));
+		new_val = buff;
+		break;
+	case CFN_INTEGER:
+		sprintf(buff, "%.0f", gtk_adjustment_get_value(GTK_ADJUSTMENT(auto_tab_widgets.edit_int_adj)));
+		new_val = buff;
+		break;
+	case CFN_REAL:
+		sprintf(buff, "%.16f", gtk_adjustment_get_value(GTK_ADJUSTMENT(auto_tab_widgets.edit_int_adj)));
+		new_val = buff;
+		break;
+	case CFN_BOOLEAN:
+		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_tab_widgets.edit_boolean)))
+			new_val = "1";
+		else
+			new_val = "0";
+		break;
+	case CFN_COLOR:
+		{
+			GdkColor clr;
+			gtk_color_button_get_color(GTK_COLOR_BUTTON(auto_tab_widgets.edit_color), &clr);
+			sprintf(buff, "#%02x%02x%02x", (clr.red >> 8) & 0xFF, (clr.green >> 8) & 0xFF, (clr.blue >> 8) & 0xFF);
 			new_val = buff;
-			break;
-		case CFN_REAL:
-			sprintf(buff, "%.16f", gtk_adjustment_get_value(GTK_ADJUSTMENT(auto_tab_widgets.edit_int_adj)));
+			update_clr = 1;
+		}
+		break;
+	case CFN_UNIT:
+		{
+			char *s = gtk_combo_box_get_active_text(GTK_COMBO_BOX(auto_tab_widgets.edit_unit));
+			strcpy(buff, s);
 			new_val = buff;
-			break;
-		case CFN_BOOLEAN:
-			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_tab_widgets.edit_boolean)))
-				new_val = "1";
-			else
-				new_val = "0";
-			break;
-		case CFN_COLOR:
-			{
-				GdkColor clr;
-				gtk_color_button_get_color(GTK_COLOR_BUTTON(auto_tab_widgets.edit_color), &clr);
-				sprintf(buff, "#%02x%02x%02x", (clr.red >> 8) & 0xFF, (clr.green >> 8) & 0xFF, (clr.blue >> 8) & 0xFF);
-				new_val = buff;
-				update_clr = 1;
-			}
-			break;
-		case CFN_UNIT:
-			{
-				char *s = gtk_combo_box_get_active_text(GTK_COMBO_BOX(auto_tab_widgets.edit_unit));
-				strcpy(buff, s);
-				new_val = buff;
+			g_free(s);
+		}
+		break;
+	case CFN_LIST:
+		{
+			GtkTreeModel *tm = gtk_tree_view_get_model(GTK_TREE_VIEW(auto_tab_widgets.cl.t));
+			GtkTreeIter it;
+			gboolean valid;
+			int n;
+
+			for (valid = gtk_tree_model_get_iter_first(tm, &it), n = 0; valid; valid = gtk_tree_model_iter_next(tm, &it), n++) {
+				gchar *s;
+				gtk_tree_model_get(tm, &it, auto_tab_widgets.cl.col_data, &s, -1);
+				conf_set_dry(role, nat->hash_path, -1, pcb_strdup(s), (n == 0) ? POL_OVERWRITE : POL_APPEND);
 				g_free(s);
 			}
-			break;
-		case CFN_LIST:
-			{
-				GtkTreeModel *tm = gtk_tree_view_get_model(GTK_TREE_VIEW(auto_tab_widgets.cl.t));
-				GtkTreeIter it;
-				gboolean valid;
-				int n;
-
-				for(valid = gtk_tree_model_get_iter_first(tm, &it), n = 0; valid; valid = gtk_tree_model_iter_next(tm, &it), n++) {
-					gchar *s;
-					gtk_tree_model_get(tm, &it, auto_tab_widgets.cl.col_data, &s, -1);
-					conf_set_dry(role, nat->hash_path, -1, pcb_strdup(s), (n == 0) ? POL_OVERWRITE : POL_APPEND);
-					g_free(s);
-				}
-				conf_update(nat->hash_path);
-				config_auto_save(role);
-			}
-			new_val = NULL; /* do not run conf_set, but run the rest of the updates */
-			break;
+			conf_update(nat->hash_path);
+			config_auto_save(role);
+		}
+		new_val = NULL;							/* do not run conf_set, but run the rest of the updates */
+		break;
 	}
 
 	if (nat->array_size > 1)
@@ -2523,12 +2380,12 @@ static void config_auto_apply_cb(GtkButton *btn, void *data)
 	}
 }
 
-static void config_auto_reset_cb(GtkButton *btn, void *data)
+static void config_auto_reset_cb(GtkButton * btn, void *data)
 {
 	config_auto_src_changed_cb(GTK_TREE_VIEW(auto_tab_widgets.src_t), NULL);
 }
 
-static void config_auto_remove_cb(GtkButton *btn, void *data)
+static void config_auto_remove_cb(GtkButton * btn, void *data)
 {
 	conf_native_t *nat = auto_tab_widgets.nat;
 	conf_role_t role = config_auto_get_edited_role();
@@ -2545,7 +2402,7 @@ static void config_auto_remove_cb(GtkButton *btn, void *data)
 	conf_auto_set_edited_role(role);
 }
 
-static void config_auto_create_cb(GtkButton *btn, void *data)
+static void config_auto_create_cb(GtkButton * btn, void *data)
 {
 	gds_t s;
 	char *val;
@@ -2554,13 +2411,14 @@ static void config_auto_create_cb(GtkButton *btn, void *data)
 
 	/* create the config node in the source lht */
 	gds_init(&s);
-	conf_print_native_field((conf_pfn)pcb_append_printf, &s, 0, &nat->val, nat->type, &nat->prop[0], 0);
+	conf_print_native_field((conf_pfn) pcb_append_printf, &s, 0, &nat->val, nat->type, &nat->prop[0], 0);
 	val = s.array;
 
 	/* strip {} from arrays */
 	if (nat->array_size > 1) {
 		int end;
-		while(*val == '{') val++;
+		while (*val == '{')
+			val++;
 		end = gds_len(&s) - (val - s.array);
 		if (end > 0)
 			s.array[end] = '\0';
@@ -2591,7 +2449,7 @@ static void config_page_update_auto(void *data)
 
 	/* split long description strings at whitepsace to make the preferences window narrower */
 	tmp = malloc(strlen(nat->description) * 2);
-	for(si = nat->description, so = tmp, l = 0; *si != '\0'; si++,so++,l++) {
+	for (si = nat->description, so = tmp, l = 0; *si != '\0'; si++, so++, l++) {
 		if (isspace(*si) && (l > 64))
 			*so = '\n';
 		else
@@ -2608,7 +2466,7 @@ static void config_page_update_auto(void *data)
 
 	/* build the source table */
 	gtk_list_store_clear(auto_tab_widgets.src_l);
-	for(n = 0; n < CFR_max_real; n++) {
+	for (n = 0; n < CFR_max_real; n++) {
 		GtkTreeIter iter;
 		long prio = conf_default_prio[n];
 		conf_policy_t pol = POL_OVERWRITE;
@@ -2622,26 +2480,31 @@ static void config_page_update_auto(void *data)
 			char sprio[32];
 			const char *val;
 
-			switch(nd->type) {
-				case LHT_TEXT: val = nd->data.text.value; break;
-				case LHT_LIST: val = "<list>"; break;
-				case LHT_HASH: val = "<hash>"; break;
-				case LHT_TABLE: val = "<table>"; break;
-				case LHT_SYMLINK: val = "<symlink>"; break;
-				case LHT_INVALID_TYPE: val = "<invalid>"; break;
+			switch (nd->type) {
+			case LHT_TEXT:
+				val = nd->data.text.value;
+				break;
+			case LHT_LIST:
+				val = "<list>";
+				break;
+			case LHT_HASH:
+				val = "<hash>";
+				break;
+			case LHT_TABLE:
+				val = "<table>";
+				break;
+			case LHT_SYMLINK:
+				val = "<symlink>";
+				break;
+			case LHT_INVALID_TYPE:
+				val = "<invalid>";
+				break;
 			}
 			sprintf(sprio, "%ld", prio);
-			gtk_list_store_set(auto_tab_widgets.src_l, &iter,
-				0, conf_role_name(n),
-				1, sprio,
-				2, conf_policy_name(pol),
-				3, val,
-				-1);
+			gtk_list_store_set(auto_tab_widgets.src_l, &iter, 0, conf_role_name(n), 1, sprio, 2, conf_policy_name(pol), 3, val, -1);
 		}
 		else {
-			gtk_list_store_set(auto_tab_widgets.src_l, &iter,
-				0, conf_role_name(n),
-				-1);
+			gtk_list_store_set(auto_tab_widgets.src_l, &iter, 0, conf_role_name(n), -1);
 		}
 	}
 	gtk_widget_hide(auto_tab_widgets.edit_idx_box);
@@ -2650,7 +2513,7 @@ static void config_page_update_auto(void *data)
 	config_auto_res_show();
 }
 
-static GtkTreeIter *config_tree_auto_mkdirp(GtkTreeStore *model, GtkTreeIter *main_parent, htsp_t *dirs, char *path)
+static GtkTreeIter *config_tree_auto_mkdirp(GtkTreeStore * model, GtkTreeIter * main_parent, htsp_t * dirs, char *path)
 {
 	char *basename;
 	GtkTreeIter *parent, *cwd;
@@ -2679,13 +2542,13 @@ static GtkTreeIter *config_tree_auto_mkdirp(GtkTreeStore *model, GtkTreeIter *ma
 
 static int config_tree_auto_cmp(const void *v1, const void *v2)
 {
-	const htsp_entry_t **e1 = (const htsp_entry_t **)v1, **e2 = (const htsp_entry_t **)v2;
+	const htsp_entry_t **e1 = (const htsp_entry_t **) v1, **e2 = (const htsp_entry_t **) v2;
 	return strcmp((*e1)->key, (*e2)->key);
 }
 
 
 /* Automatically create a subtree using the central config field hash */
-static void config_tree_auto(GtkTreeStore *model, GtkTreeIter *main_parent)
+static void config_tree_auto(GtkTreeStore * model, GtkTreeIter * main_parent)
 {
 	htsp_t *dirs;
 	htsp_entry_t *e;
@@ -2718,7 +2581,7 @@ static void config_tree_auto(GtkTreeStore *model, GtkTreeIter *main_parent)
 		GtkTreeIter iter;
 		char *basename;
 		e = sorted[n];
-		if (strlen(e->key) > sizeof(path)-1) {
+		if (strlen(e->key) > sizeof(path) - 1) {
 			pcb_message(PCB_MSG_WARNING, "Warning: can't create config item for %s: path too long\n", e->key);
 			continue;
 		}
@@ -2732,7 +2595,8 @@ static void config_tree_auto(GtkTreeStore *model, GtkTreeIter *main_parent)
 		basename++;
 		parent = config_tree_auto_mkdirp(model, main_parent, dirs, path);
 		config_tree_leaf_(model, parent, basename, NULL, &iter);
-		gtk_tree_store_set(model, &iter, CONFIG_PAGE_COLUMN, auto_page, CONFIG_PAGE_UPDATE_CB, config_page_update_auto, CONFIG_PAGE_DATA, e->value, -1);
+		gtk_tree_store_set(model, &iter, CONFIG_PAGE_COLUMN, auto_page, CONFIG_PAGE_UPDATE_CB, config_page_update_auto,
+											 CONFIG_PAGE_DATA, e->value, -1);
 	}
 	htsp_free(dirs);
 	free(sorted);
@@ -2781,8 +2645,12 @@ void ghid_config_window_show(void)
 	/* build the tree */
 	model = gtk_tree_store_new(N_CONFIG_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_POINTER, G_TYPE_POINTER);
 
-	config_tree_sect(model, NULL, &user_pov,   _("User PoV"),   _("\n<b>User PoV</b>\nA subset of configuration settings regrouped,\npresented in the User's Point of View."));
-	config_tree_sect(model, NULL, &config_pov, _("Config PoV"), _("\n<b>Config PoV</b>\nAccess all configuration fields presented in\na tree that matches the configuration\nfile (lht) structure."));
+	config_tree_sect(model, NULL, &user_pov, _("User PoV"),
+									 _
+									 ("\n<b>User PoV</b>\nA subset of configuration settings regrouped,\npresented in the User's Point of View."));
+	config_tree_sect(model, NULL, &config_pov, _("Config PoV"),
+									 _
+									 ("\n<b>Config PoV</b>\nAccess all configuration fields presented in\na tree that matches the configuration\nfile (lht) structure."));
 
 	config_tree_leaf(model, &user_pov, _("General"), config_general_tab_create);
 	config_tree_leaf(model, &user_pov, _("Window"), config_window_tab_create);
diff --git a/src_plugins/hid_gtk/gui-dialog-print.c b/src_plugins/hid_gtk/gui-dialog-print.c
deleted file mode 100644
index 8498358..0000000
--- a/src_plugins/hid_gtk/gui-dialog-print.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 1994,1995,1996 Thomas Nau
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Contact addresses for paper mail and Email:
- *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
- *  Thomas.Nau at rz.uni-ulm.de
- *
- */
-
-/* This file written by Bill Wilson for the PCB Gtk port. */
-
-#include "config.h"
-#include "conf_core.h"
-#include <stdlib.h>
-
-#include "gui.h"
-#include "pcb-printf.h"
-#include "hid_attrib.h"
-#include "hid_init.h"
-#include "misc_util.h"
-#include "compat_misc.h"
-#include "compat_nls.h"
-
-static GtkWidget *export_dialog = NULL;
-
-static void set_flag_cb(GtkToggleButton * button, void *flag)
-{
-	*(gboolean *) flag = gtk_toggle_button_get_active(button);
-}
-
-
-static void intspinner_changed_cb(GtkSpinButton * spin_button, gpointer data)
-{
-	int *ival = (int *) data;
-
-	*ival = gtk_spin_button_get_value(GTK_SPIN_BUTTON((GtkWidget *) spin_button));
-}
-
-static void coordentry_changed_cb(GtkEntry * entry, pcb_coord_t * res)
-{
-	const gchar *s = gtk_entry_get_text(entry);
-	*res = pcb_get_value(s, NULL, NULL, NULL);
-}
-
-static void dblspinner_changed_cb(GtkSpinButton * spin_button, gpointer data)
-{
-	double *dval = (double *) data;
-
-	*dval = gtk_spin_button_get_value(GTK_SPIN_BUTTON((GtkWidget *) spin_button));
-}
-
-
-static void entry_changed_cb(GtkEntry * entry, char **str)
-{
-	const gchar *s;
-
-	s = gtk_entry_get_text(entry);
-
-	if (*str)
-		free(*str);
-	*str = pcb_strdup(s);
-}
-
-static void enum_changed_cb(GtkWidget * combo_box, int *val)
-{
-	gint active;
-
-	active = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
-	*val = active;
-}
-
-
-int ghid_attribute_dialog(pcb_hid_attribute_t * attrs, int n_attrs, pcb_hid_attr_val_t * results, const char *title, const char *descr)
-{
-	GtkWidget *dialog;
-	GtkWidget *content_area;
-	GtkWidget *main_vbox, *vbox, *vbox1, *hbox, *entry;
-	GtkWidget *combo;
-	GtkWidget *widget;
-	GHidPort *out = &ghid_port;
-	int i, j, n;
-	int rc = 0;
-
-	dialog = gtk_dialog_new_with_buttons(_(title),
-																			 GTK_WINDOW(out->top_window),
-																			 (GtkDialogFlags) (GTK_DIALOG_MODAL
-																												 | GTK_DIALOG_DESTROY_WITH_PARENT),
-																			 GTK_STOCK_CANCEL, GTK_RESPONSE_NONE, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-	gtk_window_set_wmclass(GTK_WINDOW(dialog), "PCB_attribute_editor", "PCB");
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-
-	main_vbox = gtk_vbox_new(FALSE, 6);
-	gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 6);
-	gtk_container_add(GTK_CONTAINER(content_area), main_vbox);
-
-	vbox = ghid_category_vbox(main_vbox, descr != NULL ? descr : "", 4, 2, TRUE, TRUE);
-
-	/*
-	 * Iterate over all the export options and build up a dialog box
-	 * that lets us control all of the options.  By doing things this
-	 * way, any changes to the exporter HID's automatically are
-	 * reflected in this dialog box.
-	 */
-	for (j = 0; j < n_attrs; j++) {
-		const pcb_unit_t *unit_list;
-		if (attrs[j].help_text == ATTR_UNDOCUMENTED)
-			continue;
-		switch (attrs[j].type) {
-		case HID_Label:
-			widget = gtk_label_new(attrs[j].name);
-			gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
-			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
-			break;
-
-		case HID_Integer:
-			hbox = gtk_hbox_new(FALSE, 4);
-			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-			/*
-			 * FIXME
-			 * need to pick the "digits" argument based on min/max
-			 * values
-			 */
-			ghid_spin_button(hbox, &widget, attrs[j].default_val.int_value,
-											 attrs[j].min_val, attrs[j].max_val, 1.0, 1.0, 0, 0,
-											 intspinner_changed_cb, &(attrs[j].default_val.int_value), FALSE, NULL);
-			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
-
-			widget = gtk_label_new(attrs[j].name);
-			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
-			break;
-
-		case HID_Coord:
-			hbox = gtk_hbox_new(FALSE, 4);
-			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-			entry = ghid_coord_entry_new(attrs[j].min_val, attrs[j].max_val,
-																	 attrs[j].default_val.coord_value, conf_core.editor.grid_unit, CE_SMALL);
-			gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
-			if (attrs[j].default_val.str_value != NULL)
-				gtk_entry_set_text(GTK_ENTRY(entry), attrs[j].default_val.str_value);
-			gtk_widget_set_tooltip_text(entry, attrs[j].help_text);
-			g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(coordentry_changed_cb), &(attrs[j].default_val.coord_value));
-
-			widget = gtk_label_new(attrs[j].name);
-			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
-			break;
-
-		case HID_Real:
-			hbox = gtk_hbox_new(FALSE, 4);
-			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-			/*
-			 * FIXME
-			 * need to pick the "digits" and step size argument more
-			 * intelligently
-			 */
-			ghid_spin_button(hbox, &widget, attrs[j].default_val.real_value,
-											 attrs[j].min_val, attrs[j].max_val, 0.01, 0.01, 3,
-											 0, dblspinner_changed_cb, &(attrs[j].default_val.real_value), FALSE, NULL);
-
-			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
-
-			widget = gtk_label_new(attrs[j].name);
-			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
-			break;
-
-		case HID_String:
-			hbox = gtk_hbox_new(FALSE, 4);
-			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-			entry = gtk_entry_new();
-			gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
-			if (attrs[j].default_val.str_value != NULL)
-				gtk_entry_set_text(GTK_ENTRY(entry), attrs[j].default_val.str_value);
-			gtk_widget_set_tooltip_text(entry, attrs[j].help_text);
-			g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_changed_cb), &(attrs[j].default_val.str_value));
-
-			widget = gtk_label_new(attrs[j].name);
-			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
-			break;
-
-		case HID_Boolean:
-			/* put this in a check button */
-			ghid_check_button_connected(vbox, &widget,
-																	attrs[j].default_val.int_value,
-																	TRUE, FALSE, FALSE, 0, set_flag_cb, &(attrs[j].default_val.int_value), attrs[j].name);
-			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
-			break;
-
-		case HID_Enum:
-			hbox = gtk_hbox_new(FALSE, 4);
-			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-		do_enum:
-			combo = gtk_combo_box_new_text();
-			gtk_widget_set_tooltip_text(combo, attrs[j].help_text);
-			gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
-			g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(enum_changed_cb), &(attrs[j].default_val.int_value));
-
-
-			/*
-			 * Iterate through each value and add them to the
-			 * combo box
-			 */
-			i = 0;
-			while (attrs[j].enumerations[i]) {
-				gtk_combo_box_append_text(GTK_COMBO_BOX(combo), attrs[j].enumerations[i]);
-				i++;
-			}
-			gtk_combo_box_set_active(GTK_COMBO_BOX(combo), attrs[j].default_val.int_value);
-			widget = gtk_label_new(attrs[j].name);
-			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
-			break;
-
-		case HID_Mixed:
-			hbox = gtk_hbox_new(FALSE, 4);
-			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-			/*
-			 * FIXME
-			 * need to pick the "digits" and step size argument more
-			 * intelligently
-			 */
-			ghid_spin_button(hbox, &widget, attrs[j].default_val.real_value,
-											 attrs[j].min_val, attrs[j].max_val, 0.01, 0.01, 3,
-											 0, dblspinner_changed_cb, &(attrs[j].default_val.real_value), FALSE, NULL);
-			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
-
-			goto do_enum;
-			break;
-
-		case HID_Path:
-			vbox1 = ghid_category_vbox(vbox, attrs[j].name, 4, 2, TRUE, TRUE);
-			entry = gtk_entry_new();
-			gtk_box_pack_start(GTK_BOX(vbox1), entry, FALSE, FALSE, 0);
-			gtk_entry_set_text(GTK_ENTRY(entry), attrs[j].default_val.str_value);
-			g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_changed_cb), &(attrs[j].default_val.str_value));
-
-			gtk_widget_set_tooltip_text(entry, attrs[j].help_text);
-			break;
-
-		case HID_Unit:
-			unit_list = get_unit_list();
-			n = pcb_get_n_units();
-
-			hbox = gtk_hbox_new(FALSE, 4);
-			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-			combo = gtk_combo_box_new_text();
-			gtk_widget_set_tooltip_text(combo, attrs[j].help_text);
-			gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
-			g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(enum_changed_cb), &(attrs[j].default_val.int_value));
-
-			/*
-			 * Iterate through each value and add them to the
-			 * combo box
-			 */
-			for (i = 0; i < n; ++i)
-				gtk_combo_box_append_text(GTK_COMBO_BOX(combo), unit_list[i].in_suffix);
-			gtk_combo_box_set_active(GTK_COMBO_BOX(combo), attrs[j].default_val.int_value);
-			widget = gtk_label_new(attrs[j].name);
-			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
-			break;
-		default:
-			printf("ghid_attribute_dialog: unknown type of HID attribute\n");
-			break;
-		}
-	}
-
-
-	gtk_widget_show_all(dialog);
-
-	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
-		/* copy over the results */
-		for (i = 0; i < n_attrs; i++) {
-			results[i] = attrs[i].default_val;
-			if (results[i].str_value)
-				results[i].str_value = pcb_strdup(results[i].str_value);
-		}
-		rc = 0;
-	}
-	else
-		rc = 1;
-
-	gtk_widget_destroy(dialog);
-
-	return rc;
-}
-
-
-
-static void exporter_clicked_cb(GtkButton * button, pcb_hid_t * exporter)
-{
-	ghid_dialog_print(exporter);
-}
-
-void ghid_dialog_print(pcb_hid_t * hid)
-{
-	pcb_hid_attribute_t *attr;
-	int n = 0;
-	int i;
-	pcb_hid_attr_val_t *results = NULL;
-
-	/* signal the initial export select dialog that it should close */
-	if (export_dialog)
-		gtk_dialog_response(GTK_DIALOG(export_dialog), GTK_RESPONSE_CANCEL);
-
-	pcb_exporter = hid;
-
-	attr = pcb_exporter->get_export_options(&n);
-	if (n > 0) {
-		results = (pcb_hid_attr_val_t *) malloc(n * sizeof(pcb_hid_attr_val_t));
-		if (results == NULL) {
-			fprintf(stderr, "ghid_dialog_print() -- malloc failed\n");
-			exit(1);
-		}
-
-		/* non-zero means cancel was picked */
-		if (ghid_attribute_dialog(attr, n, results, _("PCB Print Layout"), pcb_exporter->description))
-			return;
-
-	}
-
-	pcb_exporter->do_export(results);
-
-	for (i = 0; i < n; i++) {
-		if (results[i].str_value)
-			free((void *) results[i].str_value);
-	}
-
-	if (results)
-		free(results);
-
-	pcb_exporter = NULL;
-}
-
-void ghid_dialog_export(void)
-{
-	GtkWidget *content_area;
-	GtkWidget *vbox, *button;
-	GHidPort *out = &ghid_port;
-	int i;
-	pcb_hid_t **hids;
-	gboolean no_exporter = TRUE;
-
-	export_dialog = gtk_dialog_new_with_buttons(_("PCB Export Layout"),
-																							GTK_WINDOW(out->top_window),
-																							(GtkDialogFlags) (GTK_DIALOG_MODAL
-																																|
-																																GTK_DIALOG_DESTROY_WITH_PARENT),
-																							GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
-	gtk_window_set_wmclass(GTK_WINDOW(export_dialog), "PCB_Export", "PCB");
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(export_dialog));
-
-	vbox = gtk_vbox_new(FALSE, 6);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
-	gtk_container_add(GTK_CONTAINER(content_area), vbox);
-
-	/*
-	 * Iterate over all the export HID's and build up a dialog box that
-	 * lets us choose which one we want to use.
-	 * This way, any additions to the exporter HID's automatically are
-	 * reflected in this dialog box.
-	 */
-
-	hids = pcb_hid_enumerate();
-	for (i = 0; hids[i]; i++) {
-		if (hids[i]->exporter) {
-			no_exporter = FALSE;
-			button = gtk_button_new_with_label(hids[i]->name);
-			gtk_widget_set_tooltip_text(button, hids[i]->description);
-			gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
-			g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(exporter_clicked_cb), hids[i]);
-		}
-	}
-
-	if (no_exporter) {
-		GtkWidget *label;
-		label = gtk_label_new("No exporter found. Check your plugins!");
-			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-	}
-
-	gtk_widget_show_all(export_dialog);
-	gtk_dialog_run(GTK_DIALOG(export_dialog));
-
-	if (export_dialog != NULL)
-		gtk_widget_destroy(export_dialog);
-	export_dialog = NULL;
-}
diff --git a/src_plugins/hid_gtk/gui-dialog.c b/src_plugins/hid_gtk/gui-dialog.c
deleted file mode 100644
index 023b321..0000000
--- a/src_plugins/hid_gtk/gui-dialog.c
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 1994,1995,1996 Thomas Nau
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Contact addresses for paper mail and Email:
- *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
- *  Thomas.Nau at rz.uni-ulm.de
- *
- */
-
-/* This file written by Bill Wilson for the PCB Gtk port.
-*/
-
-#include "config.h"
-#include "compat_misc.h"
-#include "compat_nls.h"
-#include "build_run.h"
-#include "plug_io.h"
-
-#include "data.h"
-#include "gui.h"
-
-/* ---------------------------------------------- */
-gchar *ghid_dialog_input(const char *prompt, const char *initial)
-{
-	GtkWidget *dialog;
-	GtkWidget *content_area;
-	GtkWidget *vbox, *label, *entry;
-	gchar *string;
-	gboolean response;
-	GHidPort *out = &ghid_port;
-
-	dialog = gtk_dialog_new_with_buttons("PCB User Input",
-																			 GTK_WINDOW(out->top_window),
-																			 GTK_DIALOG_MODAL,
-																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
-	vbox = gtk_vbox_new(FALSE, 4);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
-	label = gtk_label_new("");
-	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
-
-	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
-	gtk_label_set_markup(GTK_LABEL(label), prompt ? prompt : "Enter something");
-
-	entry = gtk_entry_new();
-	if (initial)
-		gtk_entry_set_text(GTK_ENTRY(entry), initial);
-
-	gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
-	gtk_box_pack_start(GTK_BOX(vbox), entry, TRUE, TRUE, 0);
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-	gtk_container_add(GTK_CONTAINER(content_area), vbox);
-	gtk_widget_show_all(dialog);
-
-	response = gtk_dialog_run(GTK_DIALOG(dialog));
-	if (response != GTK_RESPONSE_OK)
-		string = g_strdup(initial ? initial : "");
-	else
-		string = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
-
-	gtk_widget_destroy(dialog);
-	return string;
-}
-
-/* ---------------------------------------------- */
-void ghid_dialog_about(void)
-{
-	GtkWidget *dialog;
-	GHidPort *out = &ghid_port;
-	dialog = gtk_message_dialog_new(GTK_WINDOW(out->top_window),
-																	(GtkDialogFlags) (GTK_DIALOG_MODAL
-																										| GTK_DIALOG_DESTROY_WITH_PARENT),
-																	GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", pcb_get_infostr());
-
-	gtk_dialog_run(GTK_DIALOG(dialog));
-	gtk_widget_destroy(dialog);
-}
-
-/* ---------------------------------------------- */
-gint ghid_dialog_confirm_all(gchar * all_message)
-{
-	GtkWidget *dialog;
-	GtkWidget *content_area;
-	GtkWidget *label, *vbox;
-	gint response;
-	GHidPort *out = &ghid_port;
-
-	dialog = gtk_dialog_new_with_buttons("Confirm",
-																			 GTK_WINDOW(out->top_window),
-																			 (GtkDialogFlags) (GTK_DIALOG_MODAL |
-																												 GTK_DIALOG_DESTROY_WITH_PARENT),
-																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-																			 GTK_STOCK_OK, GTK_RESPONSE_OK, "Sequence OK", GUI_DIALOG_RESPONSE_ALL, NULL);
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-	vbox = ghid_framed_vbox(content_area, NULL, 6, FALSE, 4, 6);
-
-	label = gtk_label_new(all_message);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 3);
-	gtk_widget_show_all(dialog);
-
-	response = gtk_dialog_run(GTK_DIALOG(dialog));
-	gtk_widget_destroy(dialog);
-
-	return response;
-}
-
-/* ---------------------------------------------- */
-void ghid_dialog_message(gchar * message)
-{
-	GtkWidget *dialog;
-	GHidPort *out = &ghid_port;
-
-	dialog = gtk_message_dialog_new(GTK_WINDOW(out->top_window),
-																	(GtkDialogFlags) (GTK_DIALOG_MODAL |
-																										GTK_DIALOG_DESTROY_WITH_PARENT),
-																	GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", message);
-
-	gtk_dialog_run(GTK_DIALOG(dialog));
-	gtk_widget_destroy(dialog);
-}
-
-/* ---------------------------------------------- */
-gboolean ghid_dialog_confirm(const gchar * message, const gchar * cancelmsg, const gchar * okmsg)
-{
-	static gint x = -1, y = -1;
-	GtkWidget *dialog;
-	gboolean confirm = FALSE;
-	GHidPort *out = &ghid_port;
-
-	if (cancelmsg == NULL) {
-		cancelmsg = _("_Cancel");
-	}
-	if (okmsg == NULL) {
-		okmsg = _("_OK");
-	}
-
-	dialog = gtk_message_dialog_new(GTK_WINDOW(out->top_window),
-																	(GtkDialogFlags) (GTK_DIALOG_MODAL |
-																										GTK_DIALOG_DESTROY_WITH_PARENT),
-																	GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", message);
-	gtk_dialog_add_buttons(GTK_DIALOG(dialog), cancelmsg, GTK_RESPONSE_CANCEL, okmsg, GTK_RESPONSE_OK, NULL);
-
-	if (x != -1) {
-		gtk_window_move(GTK_WINDOW(dialog), x, y);
-	}
-
-	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
-		confirm = TRUE;
-
-	gtk_window_get_position(GTK_WINDOW(dialog), &x, &y);
-
-	gtk_widget_destroy(dialog);
-	return confirm;
-}
-
-/* ---------------------------------------------- */
-gint ghid_dialog_close_confirm()
-{
-	GtkWidget *dialog;
-	gint rv;
-	GHidPort *out = &ghid_port;
-	gchar *tmp;
-	gchar *str;
-	const char *msg;
-
-	if (PCB->Filename == NULL) {
-		tmp = g_strdup_printf(_("Save the changes to layout before closing?"));
-	}
-	else {
-		tmp = g_strdup_printf(_("Save the changes to layout \"%s\" before closing?"), PCB->Filename);
-	}
-	str = g_strconcat("<big><b>", tmp, "</b></big>", NULL);
-	g_free(tmp);
-	msg = _("If you don't save, all your changes will be permanently lost.");
-	str = g_strconcat(str, "\n\n", msg, NULL);
-
-	dialog = gtk_message_dialog_new(GTK_WINDOW(out->top_window),
-																	(GtkDialogFlags) (GTK_DIALOG_MODAL |
-																										GTK_DIALOG_DESTROY_WITH_PARENT),
-																	GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, NULL);
-	gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), str);
-	gtk_dialog_add_buttons(GTK_DIALOG(dialog),
-												 _("Close _without saving"), GTK_RESPONSE_NO,
-												 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_YES, NULL);
-
-	/* Set the alternative button order (ok, cancel, help) for other systems */
-	gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_YES, GTK_RESPONSE_NO, GTK_RESPONSE_CANCEL, -1);
-
-	switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
-	case GTK_RESPONSE_NO:
-		{
-			rv = GUI_DIALOG_CLOSE_CONFIRM_NOSAVE;
-			break;
-		}
-	case GTK_RESPONSE_YES:
-		{
-			rv = GUI_DIALOG_CLOSE_CONFIRM_SAVE;
-			break;
-		}
-	case GTK_RESPONSE_CANCEL:
-	default:
-		{
-			rv = GUI_DIALOG_CLOSE_CONFIRM_CANCEL;
-			break;
-		}
-	}
-	gtk_widget_destroy(dialog);
-	return rv;
-}
-
-/* ---------------------------------------------- */
-/* Caller must g_free() the returned filename.*/
-gchar *ghid_dialog_file_select_open(const gchar * title, gchar ** path, const gchar * shortcuts)
-{
-	GtkWidget *dialog;
-	gchar *result = NULL, *folder, *seed;
-	GHidPort *out = &ghid_port;
-	GtkFileFilter *no_filter, *any_filter;
-
-	dialog = gtk_file_chooser_dialog_new(title,
-																			 GTK_WINDOW(out->top_window),
-																			 GTK_FILE_CHOOSER_ACTION_OPEN,
-																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
-
-	/* add a default filter for not filtering files */
-	no_filter = gtk_file_filter_new();
-	gtk_file_filter_set_name(no_filter, "all");
-	gtk_file_filter_add_pattern(no_filter, "*.*");
-	gtk_file_filter_add_pattern(no_filter, "*");
-	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), no_filter);
-
-	any_filter = gtk_file_filter_new();
-	gtk_file_filter_set_name(any_filter, "any known format");
-	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), any_filter);
-
-
-	/* in case we have a dialog for loading a footprint file */
-	if (strcmp(title, _("Load element to buffer")) == 0) {
-		/* add a filter for footprint files */
-		GtkFileFilter *fp_filter;
-		fp_filter = gtk_file_filter_new();
-		gtk_file_filter_set_name(fp_filter, "fp");
-		gtk_file_filter_add_mime_type(fp_filter, "application/x-pcb-footprint");
-		gtk_file_filter_add_pattern(fp_filter, "*.fp");
-		gtk_file_filter_add_pattern(fp_filter, "*.FP");
-		gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), fp_filter);
-	}
-
-	/* in case we have a dialog for loading a layout file */
-	if ((strcmp(title, _("Load layout file")) == 0)
-			|| (strcmp(title, _("Load layout file to buffer")) == 0)) {
-		/* add a filter for layout files */
-		pcb_io_formats_t fmts;
-		int n, num_fmts = pcb_io_list(&fmts, PCB_IOT_PCB, 0, 0, PCB_IOL_EXT_BOARD);
-		for(n = 0; n < num_fmts; n++) {
-			int i;
-			char *ext;
-			GtkFileFilter *filter;
-
-			/* register each short name only once - slow O(N^2), but we don't have too many formats anyway */
-			for(i = 0; i < n; i++)
-				if (strcmp(fmts.plug[n]->default_fmt, fmts.plug[i]->default_fmt) == 0)
-					goto next_fmt;
-
-			filter = gtk_file_filter_new();
-			gtk_file_filter_set_name(filter, fmts.plug[n]->default_fmt);
-			if (fmts.plug[n]->mime_type != NULL) {
-				gtk_file_filter_add_mime_type(filter, fmts.plug[n]->mime_type);
-				gtk_file_filter_add_mime_type(any_filter, fmts.plug[n]->mime_type);
-			}
-			if (fmts.plug[n]->default_extension != NULL) {
-				char *s;
-				ext = pcb_concat("*", fmts.plug[n]->default_extension, NULL);
-				gtk_file_filter_add_pattern(filter, ext);
-				gtk_file_filter_add_pattern(any_filter, ext);
-				for(s = ext; *s != '\0'; s++)
-					*s = toupper(*s);
-				gtk_file_filter_add_pattern(filter, ext);
-				gtk_file_filter_add_pattern(any_filter, ext);
-				free(ext);
-			}
-			gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
-			next_fmt:;
-		}
-		pcb_io_list_free(&fmts);
-	}
-
-	/* in case we have a dialog for loading a netlist file */
-	if (strcmp(title, _("Load netlist file")) == 0) {
-		/* add a filter for netlist files */
-		GtkFileFilter *net_filter;
-		net_filter = gtk_file_filter_new();
-		gtk_file_filter_set_name(net_filter, "netlist");
-		gtk_file_filter_add_mime_type(net_filter, "application/x-pcb-netlist");
-		gtk_file_filter_add_pattern(net_filter, "*.net");
-		gtk_file_filter_add_pattern(net_filter, "*.NET");
-		gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), net_filter);
-	}
-
-	if (path && *path)
-		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), *path);
-
-	if (shortcuts && *shortcuts) {
-		folder = g_strdup(shortcuts);
-		seed = folder;
-		while ((folder = strtok(seed, ":")) != NULL) {
-			gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(dialog), folder, NULL);
-			seed = NULL;
-		}
-		g_free(folder);
-	}
-
-	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
-		result = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
-		folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
-		if (folder && path) {
-			dup_string(path, folder);
-			g_free(folder);
-		}
-	}
-	gtk_widget_destroy(dialog);
-
-
-	return result;
-}
-
-
-/* Callback to change the file name in the "save as" dialog according to
-   format selection */
-typedef struct {
-	GtkWidget *dialog;
-	const char **formats, **extensions;
-} ghid_save_ctx_t;
-
-static void fmt_changed_cb(GtkWidget *combo_box, ghid_save_ctx_t *ctx)
-{
-	char *fn, *s, *bn;
-	const char *ext;
-	gint active;
-
-	if (ctx->extensions == NULL)
-		return;
-
-	active = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
-	if (active < 0)
-		return;
-
-	fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ctx->dialog));
-	if (fn == NULL)
-		return;
-
-	/* find and truncate extension */
-	for(s = fn+strlen(fn)-1; *s != '.'; s--) {
-		if ((s <= fn) || (*s == '/') || (*s == '\\')) {
-			g_free(fn);
-			return;
-		}
-	}
-	*s = '\0';
-
-	/* calculate basename in bn */
-	bn = strrchr(fn, '/');
-	if (bn == NULL) {
-		bn = strrchr(fn, '\\');
-		if (bn == NULL)
-			bn = fn;
-		else
-			bn++;
-	}
-	else
-		bn++;
-
-	/* fetch the desired extension */
-	ext = ctx->extensions[active];
-	if (ext == NULL)
-		ext = ".";
-
-	/* build a new file name with the right extension */
-	s = pcb_concat(bn, ext, NULL);
-	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ctx->dialog), s);
-
-	free(s);
-	g_free(fn);
-}
-
-/* ---------------------------------------------- */
-/* Caller must g_free() the returned filename. */
-gchar *ghid_dialog_file_select_save(const gchar * title, gchar ** path, const gchar * file, const gchar * shortcuts, const char **formats, const char **extensions, int *format)
-{
-	GtkWidget *fmt, *tmp, *fmt_combo;
-	gchar *result = NULL, *folder, *seed;
-	GHidPort *out = &ghid_port;
-	ghid_save_ctx_t ctx;
-
-	ctx.formats = formats;
-	ctx.extensions = extensions;
-	ctx.dialog = gtk_file_chooser_dialog_new(title,
-																			 GTK_WINDOW(out->top_window),
-																			 GTK_FILE_CHOOSER_ACTION_SAVE,
-																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(ctx.dialog), TRUE);
-	gtk_dialog_set_default_response(GTK_DIALOG(ctx.dialog), GTK_RESPONSE_OK);
-
-	/* Create and add the file format widget */
-	if (format != NULL) {
-		const char **s;
-		fmt = gtk_hbox_new(FALSE, 0);
-
-		tmp = gtk_vbox_new(FALSE, 0);
-		gtk_box_pack_start(GTK_BOX(fmt), tmp, TRUE, TRUE, 0);
-
-		tmp = gtk_label_new("File format: ");
-		gtk_box_pack_start(GTK_BOX(fmt), tmp, FALSE, FALSE, 0);
-
-		fmt_combo = gtk_combo_box_new_text();
-		gtk_box_pack_start(GTK_BOX(fmt), fmt_combo, FALSE, FALSE, 0);
-
-		for(s = formats; *s != NULL; s++)
-			gtk_combo_box_append_text(GTK_COMBO_BOX(fmt_combo), *s);
-
-		gtk_combo_box_set_active(GTK_COMBO_BOX(fmt_combo), *format);
-		g_signal_connect(G_OBJECT(fmt_combo), "changed", G_CALLBACK(fmt_changed_cb), &ctx);
-
-		gtk_widget_show_all(fmt);
-		gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(ctx.dialog), fmt);
-	}
-
-	if (path && *path && **path)
-		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ctx.dialog), *path);
-
-	if (file && *file) {
-		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ctx.dialog), g_path_get_basename(file));
-		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ctx.dialog), g_path_get_dirname(file));
-	}
-
-	if (shortcuts && *shortcuts) {
-		folder = g_strdup(shortcuts);
-		seed = folder;
-		while ((folder = strtok(seed, ":")) != NULL) {
-			gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(ctx.dialog), folder, NULL);
-			seed = NULL;
-		}
-		g_free(folder);
-	}
-	if (gtk_dialog_run(GTK_DIALOG(ctx.dialog)) == GTK_RESPONSE_OK) {
-		result = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ctx.dialog));
-		folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(ctx.dialog));
-		if (folder && path) {
-			dup_string(path, folder);
-			g_free(folder);
-		}
-	}
-
-	if (format != NULL)
-		*format = gtk_combo_box_get_active(GTK_COMBO_BOX(fmt_combo));
-
-	gtk_widget_destroy(ctx.dialog);
-
-	return result;
-}
-
-
-/* ---------------------------------------------- */
-/* how many files and directories to keep for the shortcuts */
-#define NHIST 8
-typedef struct ghid_file_history_struct {
-	/*
-	 * an identifier as to which recent files pool this is.  For example
-	 * "boards", "eco", "netlists", etc.
-	 */
-	char *id;
-
-	/*
-	 * the array of files or directories
-	 */
-	char *history[NHIST];
-} ghid_file_history;
-
-static int n_recent_dirs = 0;
-static ghid_file_history *recent_dirs = NULL;
-
-/* ---------------------------------------------- */
-/* Caller must g_free() the returned filename. */
-gchar *ghid_fileselect(const char *title, const char *descr,
-											 const char *default_file, const char *default_ext, const char *history_tag, int flags)
-{
-	GtkWidget *dialog;
-	gchar *result = NULL;
-	GHidPort *out = &ghid_port;
-	gchar *path = NULL, *base = NULL;
-	int history_pool = -1;
-	int i;
-
-	if (history_tag && *history_tag) {
-		/*
-		 * I used a simple linear search here because the number of
-		 * entries in the array is likely to be quite small (5, maybe 10 at
-		 * the absolute most) and this function is used when pulling up
-		 * a file dialog box instead of something called over and over
-		 * again as part of moving elements or autorouting.  So, keep it
-		 * simple....
-		 */
-		history_pool = 0;
-		while (history_pool < n_recent_dirs && strcmp(recent_dirs[history_pool].id, history_tag) != 0) {
-			history_pool++;
-		}
-
-		/*
-		 * If we counted all the way to n_recent_dirs, that means we
-		 * didn't find our entry
-		 */
-		if (history_pool >= n_recent_dirs) {
-			n_recent_dirs++;
-
-			recent_dirs = (ghid_file_history *) realloc(recent_dirs, n_recent_dirs * sizeof(ghid_file_history));
-
-			if (recent_dirs == NULL) {
-				fprintf(stderr, "ghid_fileselect():  realloc failed\n");
-				exit(1);
-			}
-
-			recent_dirs[history_pool].id = pcb_strdup(history_tag);
-
-			/* Initialize the entries in our history list to all be NULL */
-			for (i = 0; i < NHIST; i++) {
-				recent_dirs[history_pool].history[i] = NULL;
-			}
-		}
-	}
-
-	if (default_file && *default_file) {
-		path = g_path_get_dirname(default_file);
-		base = g_path_get_basename(default_file);
-	}
-
-	dialog = gtk_file_chooser_dialog_new(title,
-																			 GTK_WINDOW(out->top_window),
-																			 (flags & HID_FILESELECT_READ) ?
-																			 GTK_FILE_CHOOSER_ACTION_OPEN :
-																			 GTK_FILE_CHOOSER_ACTION_SAVE,
-																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
-
-	if (path && *path) {
-		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
-		g_free(path);
-	}
-
-	if (base && *base) {
-		/* default file is only supposed to be for writing, not reading */
-		if (!(flags & HID_FILESELECT_READ)) {
-			gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), base);
-		}
-		g_free(base);
-	}
-
-	for (i = 0; i < NHIST && recent_dirs[history_pool].history[i] != NULL; i++) {
-		gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(dialog), recent_dirs[history_pool].history[i], NULL);
-	}
-
-	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
-		result = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
-		if (result != NULL)
-			path = g_path_get_dirname(result);
-		else
-			path = NULL;
-
-		/* update the history list */
-		if (path != NULL) {
-			char *tmps, *tmps2;
-			int k = 0;
-
-			/*
-			 * Put this at the top of the list and bump everything else
-			 * down but skip any old entry of this directory
-			 *
-			 */
-			while (k < NHIST &&
-						 recent_dirs[history_pool].history[k] != NULL && strcmp(recent_dirs[history_pool].history[k], path) == 0) {
-				k++;
-			}
-			tmps = recent_dirs[history_pool].history[k];
-			recent_dirs[history_pool].history[0] = path;
-			for (i = 1; i < NHIST; i++) {
-				/* store our current entry, but skip duplicates */
-				while (i + k < NHIST &&
-							 recent_dirs[history_pool].history[i + k] != NULL &&
-							 strcmp(recent_dirs[history_pool].history[i + k], path) == 0) {
-					k++;
-				}
-
-				if (i + k < NHIST)
-					tmps2 = recent_dirs[history_pool].history[i + k];
-				else
-					tmps2 = NULL;
-
-				/* move down the one we stored last time */
-				recent_dirs[history_pool].history[i] = tmps;
-
-				/* and remember the displace entry */
-				tmps = tmps2;
-			}
-
-			/*
-			 * the last one has fallen off the end of the history list
-			 * so we need to free() it.
-			 */
-			if (tmps) {
-				free(tmps);
-			}
-		}
-
-#ifdef DEBUG
-		printf("\n\n-----\n\n");
-		for (i = 0; i < NHIST; i++) {
-			printf("After update recent_dirs[%d].history[%d] = \"%s\"\n",
-						 history_pool, i, recent_dirs[history_pool].history[i] != NULL ? recent_dirs[history_pool].history[i] : "NULL");
-		}
-#endif
-
-	}
-	gtk_widget_destroy(dialog);
-
-
-	return result;
-}
diff --git a/src_plugins/hid_gtk/gui-drc-window.c b/src_plugins/hid_gtk/gui-drc-window.c
index a055eeb..e67830a 100644
--- a/src_plugins/hid_gtk/gui-drc-window.c
+++ b/src_plugins/hid_gtk/gui-drc-window.c
@@ -34,7 +34,6 @@
 #include "pcb-printf.h"
 #include "undo.h"
 #include "gui.h"
-#include "win_place.h"
 #include "gui-drc-window.h"
 #include "hid_actions.h"
 #include "compat_nls.h"
@@ -47,6 +46,8 @@
 #include "obj_poly_draw.h"
 #include "layer_vis.h"
 
+#include "../src_plugins/lib_gtk_common/util_str.h"
+#include "../src_plugins/lib_gtk_common/win_place.h"
 
 #define VIOLATION_PIXMAP_PIXEL_SIZE   100
 #define VIOLATION_PIXMAP_PIXEL_BORDER 5
diff --git a/src_plugins/hid_gtk/gui-icons-misc.data b/src_plugins/hid_gtk/gui-icons-misc.data
index e1f879a..fef854b 100644
--- a/src_plugins/hid_gtk/gui-icons-misc.data
+++ b/src_plugins/hid_gtk/gui-icons-misc.data
@@ -29,46 +29,51 @@
 /* XPM */
 static const char *icon_bits[] = {
 /* columns rows colors chars-per-pixel */
-"32 32 6 1",
-"  c black",
-". c #53E336",
-"X c #E34736",
-"o c #BED7E3",
-"O c #E7E3E7",
-"+ c None",
+"32 32 11 1",
+" 	c None",
+".	c #030703",
+"+	c #2C3133",
+"@	c #254E29",
+"#	c #395C3D",
+"$	c #4B734E",
+"%	c #626B6B",
+"&	c #6C9174",
+"*	c #8C959C",
+"=	c #A0B0A8",
+"-	c #DDDEDC",
 /* pixels */
-"++++++++++++++++++++++++++++++++",
-"++++++++++++++++++++++++++++++++",
-"++++++++++++++++++++++++++++++++",
-"++++++++++++++++++++++++++++++++",
-"+                              +",
-"+ o   oo   o   oo   o   oo   o +",
-"+ o + oo + o + oo + o + oo + o +",
-"+ o   oo   o   oo   o   oo   o +",
-"+ oooooooooooooooooooooooooooo +",
-"+   oooooooooooooooooooooooooo +",
-"+   oooooooooooooooooooooooooo +",
-"+   oooooooooooooooooooooooooo +",
-"+   oooooooooooooooooooooooooo +",
-"+ oooooooooooooooooooooooooooo +",
-"+ o   oo   o   oo   o   oo   o +",
-"+ o + oo + o + oo + o + oo + o +",
-"+ o   oo . o   oo   o   oo X o +",
-"+        .                 X   +",
-"+++++++++.+++++++++++++++++X++++",
-"+++++++++.+++++++++++++++++X++++",
-"+++++++++.+++++++++++++++++X++++",
-"+++++++++.+++++++++++++++++X++++",
-"++++++++.++++++++++++++++++X++++",
-"+++++++.++++ +++ ++++++++++X++++",
-"+++++++.++++ ++  +++++++++XX++++",
-"++++++ . +++ + o ++++   +XX+++++",
-"++++++ .      oo      XXXX++++++",
-"++++++   +++ + o ++++   ++++++++",
-"++++++++++++ ++  +++++++++++++++",
-"++++++++++++ +++ +++++++++++++++",
-"++++++++++++++++++++++++++++++++",
-"++++++++++++++++++++++++++++++++"
+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
+"&&&&&&&&&&&&$#@@@@#$&&&&&&&&&&&&",
+"&&&&&&&&&&&@@@@@@@@@@&&&&&&&&&&&",
+"&&&&&&&&&&$@@@@@@@@@@$&&&&&&&&&&",
+"&&&&&&&&&&&@@@#%%#@@@&&&&&&&&&&&",
+"&&&&&&&&&&&&%******%&&&&&&&&&&&&",
+"&&&&&&&&&&&**********&&&&&&&&&&&",
+"&&&&&&@@#&************&#@@&&&&&&",
+"&&&&&$@@@**************@@@$&&&&&",
+"&&&&&#@@#*****%++%*****#@@@&&&&&",
+"&&&&&@@@%****%....%****%@@@&&&&&",
+"&&&&&@@@%****......****%@@@$&&&&",
+"&&&&&@@@%****......****%@@@$&&&&",
+"&&&&&@@@%****+....+****%@@@&&&&&",
+"&&&&&@@@%*****+...*****%@@@&&&&&",
+"&&&&&#@@@**************#@@@&&&&&",
+"&&&&&$@@@**************@@@$&&&&&",
+"&&&&&&$$$&************=&$$&&&&&&",
+"&&&&&&&&&&&**********&==&&&&&&&&",
+"&&&&&&&&&&&##%%**%%##&==&&&&&&&&",
+"&&&&&&&&&&&$#@##%@@@#&-=&&&&&&&&",
+"&&&&&&&&---=&$---=@&-=-=&&&&&&&&",
+"&&&&&&&&&-&#@@==@- at -$&==&&&&&&&&",
+"&&&&&&&&&-&&&$=&$-$-&&==&&&&&&&&",
+"&&&&&&&&&-&&&&==&-&=---=&&&&&&&&",
+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"
 };
 
 #define rotateIcon_width 16
diff --git a/src_plugins/hid_gtk/gui-keyref-window.c b/src_plugins/hid_gtk/gui-keyref-window.c
deleted file mode 100644
index 616f38f..0000000
--- a/src_plugins/hid_gtk/gui-keyref-window.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 1994,1995,1996 Thomas Nau
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Contact addresses for paper mail and Email:
- *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
- *  Thomas.Nau at rz.uni-ulm.de
- *
- */
-
-/* This file written by Bill Wilson for the PCB Gtk port */
-
-#include "config.h"
-
-#include "gui.h"
-#include "win_place.h"
-#include "compat_nls.h"
-
-static GtkWidget *keyref_window;
-
-static const gchar *key_ref_text[] = {
-	"<h>",
-	N_("Keyboard\n"),
-	N_("Keyboard shortcuts and actions available in PCB.\n"),
-	N_("In below key actions, <s> is <shift>, <c> is <ctrl>\n"),
-	N_("and <a> is <alt> or <mod>\n"),
-	"\n",
-
-	"<b>\ta\t",
-	N_("Set layer and size from line or arc\n"),
-	"\n",
-
-	"<b><s><a>a ",
-	N_("Unselect all objects\n"),
-	"\n",
-
-	"<b>\tb\t",
-	N_("Flip element to opposite side of the board\n"),
-	"<b><c>\tb\t",
-	N_("Flip selected objects to opposite side of the board\n"),
-	"\n",
-
-	"<b><c>\tc\t",
-	N_("Copy selected to buffer and unselect\n"),
-	"\n",
-
-	"<b>\td\t",
-	N_("Display pin/pad names (numbers with View->Enable pinout shows number)\n"),
-	"<b><s>\td\t",
-	N_("Open pinout window for element under cursor\n"),
-	"\n",
-
-	"<b>\te\t",
-	N_("Delete all rats\n"),
-	"<b><s>\te\t",
-	N_("Delete selected rats\n"),
-	"\n",
-
-	"<b>\tf\t",
-	N_("Highlight connections to object\n"),
-	"<b><s>\tf\t",
-	N_("Reset highlighted connections\n"),
-	"<b><c>\tf\t",
-	N_("Cumulative highlight connections to object\n"),
-	"\n",
-
-	"<b>\tg\t",
-	N_("Increment grid by configured grid increment\n"),
-
-	"<b><s>\tg\t",
-	N_("Decrement grid by configured grid increment\n"),
-	"\n",
-
-	"<b>\th\t",
-	N_("Toggle visibility of element name under cursor\n"),
-
-	"<b><s>\th\t",
-	N_("Toggle visibility of selected element names\n"),
-
-	"<b><c>\th\t",
-	N_("Toggle the hole flag of object under cursor\n"),
-	"\n",
-
-	"<b>\tj\t",
-	N_("Toggle line/arc should clear polygons flag of object under cursor\n"),
-
-	"<b><s>\tj\t",
-	N_("Toggle line/arc should clear polygons flag of selected\n"),
-	"\n",
-
-	"<b>\tk\t",
-	N_("Increase clearance of object by configured clearance\n"),
-
-	"<b><s>\tk\t",
-	N_("Decrease clearance of object by configured clearance\n"),
-
-	"<b><c>\tk\t",
-	N_("Increase clearance of selected objects by configured clearance\n"),
-
-	"<b><s><c>k ",
-	N_("Decrease clearance of selected objects by configured clearance\n"),
-	"\n",
-
-	"<b>\tl\t",
-	N_("Increment current route style line size by configured line increment\n"),
-
-	"<b><s>\tl\t",
-	N_("Decrement current route style line size by configured line increment\n"),
-	"\n",
-
-	"<b>\tm\t",
-	N_("Move object to current layer\n"),
-
-	"<b><s>\tm\t",
-	N_("Move selected objects to current layer\n"),
-
-	"<b><c>\tm\t",
-	N_("Mark at cursor location for showing relative offsets\n"),
-	"\n",
-
-	"<b><s>\tn\t",
-	N_("Select the shortest unselected rat on the board\n"),
-	"\n",
-
-	"<b>\to\t",
-	N_("Optimize and draw all rats\n"),
-
-	"<b><s>\to\t",
-	N_("Optimize and draw selected rats\n"),
-	"\n",
-
-	"<b><c>\to\t",
-	N_("Change octagon flag of object\n"),
-	"\n",
-
-	"<b>\tp\t",
-	N_("Backup polygon drawing to previous point\n"),
-
-	"<b><s>\tp\t",
-	N_("Close polygon\n"),
-	"\n",
-
-	"<b>\tq\t",
-	N_("Toggle the square flag of an object\n"),
-	"\n",
-
-	"<b><s>\tr\t",
-	N_("Redo last undone operation\n"),
-	"\n",
-
-	"<b>\ts\t",
-	N_("Increment size of an object by configured size increment\n"),
-	"<b><s>\ts\t",
-	N_("Decrement size of an object by configured size increment\n"),
-	"<b><a>\ts\t",
-	N_("Increment drill size of a pin or via\n"),
-	"<b><s><a>s ",
-	N_("Decrement drill size of a pin or via\n"),
-	"\n",
-
-	"<b>\tt\t",
-	N_("Adjust text scale so new text increases by the configured size increment\n"),
-	"<b><s>\tt\t",
-	N_("Adjust text scale so new text decreases by the configured size increment\n"),
-	"\n",
-
-	"<b>\tu\t",
-	N_("Undo last operation\n"),
-	"\n",
-
-	"<b>\tv\t",
-	N_("Zoom to board extents\n"),
-	"<b><c>\tv\t",
-	N_("Increment current route style via size\n"),
-	"<b><s><c>v ",
-	N_("Decrement current route style via size\n"),
-	"<b><a>\tv\t",
-	N_("Increment current route style via hole size\n"),
-	"<b><s><a>v ",
-	N_("Decrement current route style via hole size\n"),
-	"\n",
-
-	"<b><c>\tx\t",
-	N_("Copy selection to buffer and enter pastebuffer mode\n"),
-	"<b><s><c>x ",
-	N_("Cut selection to buffer and enter pastebuffer mode\n"),
-	"\n",
-
-	"<b>\tz\t",
-	N_("Zoom in\n"),
-	"<b><z>\tz\t",
-	N_("Zoom out\n"),
-	"\n",
-
-	"<b>\t|\t",
-	N_("Toggle thin draw mode\n"),
-	"\n",
-
-	"<b>\t/\t",
-	N_("Cycle multiline mode (Using <s> overrides)\n"),
-	"\n",
-
-	"<b>\t.\t",
-	N_("Toggle all direction lines mode\n"),
-	"\n",
-
-	"<b>\tEsc\t",
-	N_("If drawing an object, return to a neutral state.\n"),
-	"\n",
-
-	"<b>\tTab\t",
-	N_("Switch view to other side\n"),
-	"\n",
-
-	"<b>  Space\t",
-	N_("Switch to select mode\n"),
-	"\n",
-
-	"<b>\t:\t",
-	N_("Enter user command or pop up command window\n"),
-	"\n",
-
-	"<b>\tDEL\t",
-	N_("Delete object\n"),
-	"\n",
-
-	"<b>\t1-9\t",
-	N_("Select drawing layers\n"),
-	"\n",
-
-	"<b><c>\t1-5\t",
-	N_("Select current buffer\n"),
-	"\n",
-	"\n",
-	"<h>",
-	N_("Mouse\n"),
-	N_("Modifier key use can be combined with mouse button presses\n" "to modify mouse button actions.\n"),
-	"\n",
-	N_("<b>Left button\n"),
-	N_("\tPerform or initiate action determined by current mode.\n"),
-	"\n",
-	"\t",
-	N_("<b><shift>"),
-	N_(" - change rotation direction for rotation tool actions.\n"),
-	"\n",
-	N_("\tAfter a draw operation has been left mouse button initiated,\n" "\tmodifier key effects:\n"),
-	"\t",
-	N_("<b><shift>"),
-	N_(" - change line 45 degree direction and arc angle direction,\n"),
-	"\n",
-	N_("<b>Middle button\n"),
-	N_("\tIf a line, arc, rectangle, or polygon draw operation has been\n"
-		 "\tinitiated, a click restarts the draw operation at the cursor position.\n"),
-	"\n",
-	N_("\tIf such a draw has not been initiated, a click selects objects and\n" "\ta press and drag moves objects.\n"),
-	"\n",
-	N_("<b>Right button\n"),
-	N_("\tPress and drag to pan.\n" "\tWhile drawing or moving, a click without a drag toggles auto pan mode.\n"),
-	"\n\t",
-	N_("<b><shift>"),
-	N_(" - Popup a menu.\n"),
-	"\n",
-	N_("<b>Scroll wheel\n"),
-	N_("\tZoom in/out.\n"),
-	"\n\t",
-	N_("<b><shift>"),
-	N_(" - pan vertically.\n"),
-	"\t",
-	N_("<b><ctrl>"),
-	N_(" - pan horizontally.\n"),
-	"\n",
-	N_("<b>Usage:\n"),
-	N_("\tMouse actions can typically be combined.  For example: while moving\n"
-		 "\tan object (with left or middle press and drag), the right button may\n"
-		 "\tbe simultaneously clicked to toggle auto pan or pressed and dragged\n"
-		 "\tto manually pan.  Mouse moving or drawing may also be combined with\n" "\tkey actions.\n"),
-};
-
-
-
-
-	/* Remember user window resizes.
-	 */
-static gint keyref_window_configure_event_cb(GtkWidget * widget, GdkEventConfigure * ev, gpointer data)
-{
-	wplc_config_event(widget, &hid_gtk_wgeo.keyref_x, &hid_gtk_wgeo.keyref_y, &hid_gtk_wgeo.keyref_width, &hid_gtk_wgeo.keyref_height);
-	return FALSE;
-}
-
-static void keyref_close_cb(gpointer data)
-{
-	gtk_widget_destroy(keyref_window);
-	keyref_window = NULL;
-}
-
-static void keyref_destroy_cb(GtkWidget * widget, gpointer data)
-{
-	keyref_window = NULL;
-}
-
-void ghid_keyref_window_show(gboolean raise)
-{
-	GtkWidget *vbox, *hbox, *button, *text;
-	gint i;
-
-	if (keyref_window) {
-		if (raise)
-			gtk_window_present(GTK_WINDOW(keyref_window));
-		return;
-	}
-	keyref_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	g_signal_connect(G_OBJECT(keyref_window), "destroy", G_CALLBACK(keyref_destroy_cb), NULL);
-	g_signal_connect(G_OBJECT(keyref_window), "configure_event", G_CALLBACK(keyref_window_configure_event_cb), NULL);
-	gtk_window_set_title(GTK_WINDOW(keyref_window), _("pcb-rnd Key Reference"));
-	gtk_window_set_wmclass(GTK_WINDOW(keyref_window), "PCB_Keyref", "PCB");
-	gtk_window_set_default_size(GTK_WINDOW(keyref_window), hid_gtk_wgeo.keyref_width, hid_gtk_wgeo.keyref_height);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
-	gtk_container_add(GTK_CONTAINER(keyref_window), vbox);
-
-	text = ghid_scrolled_text_view(vbox, NULL, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	for (i = 0; i < sizeof(key_ref_text) / sizeof(gchar *); ++i)
-		ghid_text_view_append(text, _(key_ref_text[i]));
-
-	/* The keyref window close button.
-	 */
-	hbox = gtk_hbutton_box_new();
-	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
-	button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(keyref_close_cb), NULL);
-	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
-
-	gtk_widget_show_all(keyref_window);
-
-}
diff --git a/src_plugins/hid_gtk/gui-library-window.c b/src_plugins/hid_gtk/gui-library-window.c
index bce0851..e6d6e30 100644
--- a/src_plugins/hid_gtk/gui-library-window.c
+++ b/src_plugins/hid_gtk/gui-library-window.c
@@ -55,7 +55,6 @@
 #include "conf_core.h"
 
 #include "gui.h"
-#include "win_place.h"
 #include "buffer.h"
 #include "data.h"
 #include "plug_footprint.h"
@@ -65,7 +64,9 @@
 
 static GtkWidget *library_window;
 
-#include "gui-pinout-preview.h"
+#include "../src_plugins/lib_gtk_common/bu_box.h"
+#include "../src_plugins/lib_gtk_common/wt_preview.h"
+#include "../src_plugins/lib_gtk_common/win_place.h"
 #include "gui-library-window.h"
 
 /*! \def LIBRARY_FILTER_INTERVAL
@@ -782,9 +783,15 @@ static GObject *library_window_constructor(GType type, guint n_construct_propert
 																			"right-padding", 5,
 																			"top-padding", 5,
 																			"bottom-padding", 5, "xscale", 1.0, "yscale", 1.0, "xalign", 0.5, "yalign", 0.5, NULL));
+
+#warning gl TODO: this wont work with gl: use pcb_gtk_preview_pinout_new() instead and set *-request separately, because _new() has side effects
 	preview = (GtkWidget *) g_object_new(GHID_TYPE_PINOUT_PREVIEW,
 																			 /* GhidPinoutPreview */
 																			 "element-data", NULL,
+																			 "gport", gport,
+																			 "init-widget", ghid_init_drawing_widget,
+																			 "expose", ghid_preview_expose,
+																			 "kind", PCB_GTK_PREVIEW_PINOUT,
 																			 /* GtkWidget */
 																			 "width-request", 150, "height-request", 150, NULL);
 
diff --git a/src_plugins/hid_gtk/gui-log-window.c b/src_plugins/hid_gtk/gui-log-window.c
index 6596c74..9f9af31 100644
--- a/src_plugins/hid_gtk/gui-log-window.c
+++ b/src_plugins/hid_gtk/gui-log-window.c
@@ -33,10 +33,13 @@
 #include "conf_hid.h"
 
 #include "gui.h"
-#include "win_place.h"
 #include "pcb-printf.h"
 #include "hid_actions.h"
 #include "compat_nls.h"
+#include "gtkhid-main.h"
+
+#include "../src_plugins/lib_gtk_common/win_place.h"
+#include "../src_plugins/lib_gtk_common/bu_text_view.h"
 
 static GtkWidget *log_window, *log_text;
 static gboolean log_show_on_append = FALSE;
diff --git a/src_plugins/hid_gtk/gui-misc.c b/src_plugins/hid_gtk/gui-misc.c
deleted file mode 100644
index 2bb6c52..0000000
--- a/src_plugins/hid_gtk/gui-misc.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 1994,1995,1996 Thomas Nau
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/* This file was originally written by Bill Wilson for the PCB Gtk port */
-
-#include "config.h"
-#include "conf_core.h"
-
-#include "math_helper.h"
-#include "crosshair.h"
-#include "data.h"
-#include "action_helper.h"
-#include "pcb-printf.h"
-#include "misc_util.h"
-#include "compat_nls.h"
-
-#include "gui.h"
-#include <gdk/gdkkeysyms.h>
-
-const char *ghid_cookie = "gtk hid";
-const char *ghid_menu_cookie = "gtk hid menu";
-
-#define CUSTOM_CURSOR_CLOCKWISE		(GDK_LAST_CURSOR + 10)
-#define CUSTOM_CURSOR_DRAG			(GDK_LAST_CURSOR + 11)
-#define CUSTOM_CURSOR_LOCK			(GDK_LAST_CURSOR + 12)
-
-#define ICON_X_HOT 8
-#define ICON_Y_HOT 8
-
-
-GdkPixmap *XC_clock_source, *XC_clock_mask, *XC_hand_source, *XC_hand_mask, *XC_lock_source, *XC_lock_mask;
-
-
-static GdkCursorType oldCursor;
-
-void ghid_status_line_set_text(const gchar * text)
-{
-	if (ghidgui->command_entry_status_line_active)
-		return;
-
-	ghid_label_set_markup(ghidgui->status_line_label, text);
-}
-
-void ghid_cursor_position_label_set_text(gchar * text)
-{
-	ghid_label_set_markup(ghidgui->cursor_position_absolute_label, text);
-}
-
-void ghid_cursor_position_relative_label_set_text(gchar * text)
-{
-	ghid_label_set_markup(ghidgui->cursor_position_relative_label, text);
-}
-
-static GdkCursorType gport_set_cursor(GdkCursorType shape)
-{
-	GdkWindow *window;
-	GdkCursorType old_shape = gport->X_cursor_shape;
-	GdkColor fg = { 0, 65535, 65535, 65535 };	/* white */
-	GdkColor bg = { 0, 0, 0, 0 };	/* black */
-
-	if (gport->drawing_area == NULL)
-		return GDK_X_CURSOR;
-
-	window = gtk_widget_get_window(gport->drawing_area);
-
-	if (gport->X_cursor_shape == shape)
-		return shape;
-
-	/* check if window exists to prevent from fatal errors */
-	if (window == NULL)
-		return GDK_X_CURSOR;
-
-	gport->X_cursor_shape = shape;
-	if (shape > GDK_LAST_CURSOR) {
-		if (shape == CUSTOM_CURSOR_CLOCKWISE)
-			gport->X_cursor = gdk_cursor_new_from_pixmap(XC_clock_source, XC_clock_mask, &fg, &bg, ICON_X_HOT, ICON_Y_HOT);
-		else if (shape == CUSTOM_CURSOR_DRAG)
-			gport->X_cursor = gdk_cursor_new_from_pixmap(XC_hand_source, XC_hand_mask, &fg, &bg, ICON_X_HOT, ICON_Y_HOT);
-		else if (shape == CUSTOM_CURSOR_LOCK)
-			gport->X_cursor = gdk_cursor_new_from_pixmap(XC_lock_source, XC_lock_mask, &fg, &bg, ICON_X_HOT, ICON_Y_HOT);
-	}
-	else
-		gport->X_cursor = gdk_cursor_new(shape);
-
-	gdk_window_set_cursor(window, gport->X_cursor);
-	gdk_cursor_unref(gport->X_cursor);
-
-	return old_shape;
-}
-
-void ghid_point_cursor(void)
-{
-	oldCursor = gport_set_cursor(GDK_DRAPED_BOX);
-}
-
-void ghid_hand_cursor(void)
-{
-	oldCursor = gport_set_cursor(GDK_HAND2);
-}
-
-void ghid_watch_cursor(void)
-{
-	GdkCursorType tmp;
-
-	tmp = gport_set_cursor(GDK_WATCH);
-	if (tmp != GDK_WATCH)
-		oldCursor = tmp;
-}
-
-void ghid_mode_cursor(int Mode)
-{
-	switch (Mode) {
-	case PCB_MODE_NO:
-		gport_set_cursor((GdkCursorType) CUSTOM_CURSOR_DRAG);
-		break;
-
-	case PCB_MODE_VIA:
-		gport_set_cursor(GDK_ARROW);
-		break;
-
-	case PCB_MODE_LINE:
-		gport_set_cursor(GDK_PENCIL);
-		break;
-
-	case PCB_MODE_ARC:
-		gport_set_cursor(GDK_QUESTION_ARROW);
-		break;
-
-	case PCB_MODE_ARROW:
-		gport_set_cursor(GDK_LEFT_PTR);
-		break;
-
-	case PCB_MODE_POLYGON:
-	case PCB_MODE_POLYGON_HOLE:
-		gport_set_cursor(GDK_SB_UP_ARROW);
-		break;
-
-	case PCB_MODE_PASTE_BUFFER:
-		gport_set_cursor(GDK_HAND1);
-		break;
-
-	case PCB_MODE_TEXT:
-		gport_set_cursor(GDK_XTERM);
-		break;
-
-	case PCB_MODE_RECTANGLE:
-		gport_set_cursor(GDK_UL_ANGLE);
-		break;
-
-	case PCB_MODE_THERMAL:
-		gport_set_cursor(GDK_IRON_CROSS);
-		break;
-
-	case PCB_MODE_REMOVE:
-		gport_set_cursor(GDK_PIRATE);
-		break;
-
-	case PCB_MODE_ROTATE:
-		if (ghid_shift_is_pressed())
-			gport_set_cursor((GdkCursorType) CUSTOM_CURSOR_CLOCKWISE);
-		else
-			gport_set_cursor(GDK_EXCHANGE);
-		break;
-
-	case PCB_MODE_COPY:
-	case PCB_MODE_MOVE:
-		gport_set_cursor(GDK_CROSSHAIR);
-		break;
-
-	case PCB_MODE_INSERT_POINT:
-		gport_set_cursor(GDK_DOTBOX);
-		break;
-
-	case PCB_MODE_LOCK:
-		gport_set_cursor((GdkCursorType) CUSTOM_CURSOR_LOCK);
-	}
-}
-
-void ghid_corner_cursor(void)
-{
-	GdkCursorType shape;
-
-	if (pcb_crosshair.Y <= pcb_crosshair.AttachedBox.Point1.Y)
-		shape = (pcb_crosshair.X >= pcb_crosshair.AttachedBox.Point1.X) ? GDK_UR_ANGLE : GDK_UL_ANGLE;
-	else
-		shape = (pcb_crosshair.X >= pcb_crosshair.AttachedBox.Point1.X) ? GDK_LR_ANGLE : GDK_LL_ANGLE;
-	if (gport->X_cursor_shape != shape)
-		gport_set_cursor(shape);
-}
-
-void ghid_restore_cursor(void)
-{
-	gport_set_cursor(oldCursor);
-}
-
-
-
-	/* =============================================================== */
-static gboolean got_location;
-
-	/* If user hits a key instead of the mouse button, we'll abort unless
-	   |  it's the enter key (which accepts the current crosshair location).
-	 */
-static gboolean loop_key_press_cb(GtkWidget * drawing_area, GdkEventKey * kev, GMainLoop ** loop)
-{
-	gint ksym = kev->keyval;
-
-	if (ghid_is_modifier_key_sym(ksym))
-		return TRUE;
-
-	switch (ksym) {
-	case GDK_Return:							/* Accept cursor location */
-		if (g_main_loop_is_running(*loop))
-			g_main_loop_quit(*loop);
-		break;
-
-	default:											/* Abort */
-		got_location = FALSE;
-		if (g_main_loop_is_running(*loop))
-			g_main_loop_quit(*loop);
-		break;
-	}
-	return TRUE;
-}
-
-	/* User hit a mouse button in the Output drawing area, so quit the loop
-	   |  and the cursor values when the button was pressed will be used.
-	 */
-static gboolean loop_button_press_cb(GtkWidget * drawing_area, GdkEventButton * ev, GMainLoop ** loop)
-{
-	if (g_main_loop_is_running(*loop))
-		g_main_loop_quit(*loop);
-	ghid_note_event_location(ev);
-	return TRUE;
-}
-
-int ghid_wheel_zoom = 0;
-	/* Run a glib GMainLoop which intercepts key and mouse button events from
-	   |  the top level loop.  When a mouse or key is hit in the Output drawing
-	   |  area, quit the loop so the top level loop can continue and use the
-	   |  the mouse pointer coordinates at the time of the mouse button event.
-	 */
-static gboolean run_get_location_loop(const gchar * message)
-{
-	static int getting_loc = 0;
-	GMainLoop *loop;
-	gulong button_handler, key_handler;
-	gint oldObjState, oldLineState, oldBoxState;
-
-	/* Do not enter the loop recursively (ask for coord only once); also don't
-	   ask for coord if the scrollwheel triggered the event, it may cause strange
-	   GUI lockups when done outside of the drawing area */
-	if ((getting_loc) || (ghid_wheel_zoom))
-		return pcb_false;
-
-	getting_loc = 1;
-	ghid_status_line_set_text(message);
-
-	oldObjState = pcb_crosshair.AttachedObject.State;
-	oldLineState = pcb_crosshair.AttachedLine.State;
-	oldBoxState = pcb_crosshair.AttachedBox.State;
-	pcb_notify_crosshair_change(pcb_false);
-	pcb_crosshair.AttachedObject.State = PCB_CH_STATE_FIRST;
-	pcb_crosshair.AttachedLine.State = PCB_CH_STATE_FIRST;
-	pcb_crosshair.AttachedBox.State = PCB_CH_STATE_FIRST;
-	ghid_hand_cursor();
-	pcb_notify_crosshair_change(pcb_true);
-
-	/* Stop the top level GMainLoop from getting user input from keyboard
-	   |  and mouse so we can install our own handlers here.  Also set the
-	   |  control interface insensitive so all the user can do is hit a key
-	   |  or mouse button in the Output drawing area.
-	 */
-	ghid_interface_input_signals_disconnect();
-	ghid_interface_set_sensitive(FALSE);
-
-	got_location = TRUE;					/* Will be unset by hitting most keys */
-	button_handler =
-		g_signal_connect(G_OBJECT(gport->drawing_area), "button_press_event", G_CALLBACK(loop_button_press_cb), &loop);
-	key_handler = g_signal_connect(G_OBJECT(gport->top_window), "key_press_event", G_CALLBACK(loop_key_press_cb), &loop);
-
-	loop = g_main_loop_new(NULL, FALSE);
-	g_main_loop_run(loop);
-
-	g_main_loop_unref(loop);
-
-	g_signal_handler_disconnect(gport->drawing_area, button_handler);
-	g_signal_handler_disconnect(gport->top_window, key_handler);
-
-	ghid_interface_input_signals_connect();	/* return to normal */
-	ghid_interface_set_sensitive(TRUE);
-
-	pcb_notify_crosshair_change(pcb_false);
-	pcb_crosshair.AttachedObject.State = oldObjState;
-	pcb_crosshair.AttachedLine.State = oldLineState;
-	pcb_crosshair.AttachedBox.State = oldBoxState;
-	pcb_notify_crosshair_change(pcb_true);
-	ghid_restore_cursor();
-
-	ghid_set_status_line_label();
-
-	getting_loc = 0;
-	return got_location;
-}
-
-
-
-/* ---------------------------------------------------------------------------*/
-void ghid_get_user_xy(const char *msg)
-{
-	run_get_location_loop(msg);
-}
-
-	/* XXX The abort dialog isn't implemented yet in the Gtk port
-	 */
-void ghid_create_abort_dialog(char *msg)
-{
-}
-
-gboolean ghid_check_abort(void)
-{
-	return FALSE;									/* Abort isn't implemented, so never abort */
-}
-
-void ghid_end_abort(void)
-{
-}
-
-void ghid_get_pointer(int *x, int *y)
-{
-	gint xp, yp;
-
-	gdk_window_get_pointer(gtk_widget_get_window(gport->drawing_area), &xp, &yp, NULL);
-	if (x)
-		*x = xp;
-	if (y)
-		*y = yp;
-}
-
-/* ---------------------------------------------------------------------------
- * output of status line
- */
-void ghid_set_status_line_label(void)
-{
-	const gchar *flag = conf_core.editor.all_direction_lines
-	    ? "*" : (conf_core.editor.line_refraction == 0 ? "X" : (conf_core.editor.line_refraction == 1 ? "_/" : "\\_"));
-	    char *text = pcb_strdup_printf(_("%m+<b>view</b>=%s  "
-	        "<b>grid</b>=%$mS  "
-	        "%s%s  "
-	        "<b>line</b>=%mS  "
-	        "<b>via</b>=%mS (%mS)  %s"
-	        "<b>clearance</b>=%mS  "
-	        "<b>text</b>=%i%%  "
-	        "<b>buffer</b>=#%i"),
-	conf_core.editor.grid_unit->allow,
-	conf_core.editor.show_solder_side ? _("solder") : _("component"),
-	PCB->Grid,
-	flag, conf_core.editor.rubber_band_mode ? ",R  " : "  ",
-	conf_core.design.line_thickness,
-	conf_core.design.via_thickness,
-	conf_core.design.via_drilling_hole,
-	conf_hid_gtk.plugins.hid_gtk.compact_horizontal ? "\n" : "",
-	conf_core.design.clearance,
-	conf_core.design.text_scale, conf_core.editor.buffer_number + 1);
-
-	ghid_status_line_set_text(text);
-	free(text);
-}
-
-/* ---------------------------------------------------------------------------
- * output of cursor position
- */
-void ghid_set_cursor_position_labels(void)
-{
-	char *text, sep = ' ';
-	if (conf_hid_gtk.plugins.hid_gtk.compact_vertical)
-		sep = '\n';
-
-	if (pcb_marked.status) {
-		pcb_coord_t dx = pcb_crosshair.X - pcb_marked.X;
-		pcb_coord_t dy = pcb_crosshair.Y - pcb_marked.Y;
-		pcb_coord_t r = pcb_distance(pcb_crosshair.X, pcb_crosshair.Y, pcb_marked.X, pcb_marked.Y);
-		double a = atan2(dy, dx) * PCB_RAD_TO_DEG;
-
-
-		text = pcb_strdup_printf(_("%m+r %-mS;%cphi %-.1f;%c%-mS %-mS"), conf_core.editor.grid_unit->allow, r, sep, a, sep, dx, dy);
-		ghid_cursor_position_relative_label_set_text(text);
-		free(text);
-	}
-	else {
-		char text[64];
-		sprintf(text, _("r __.__;%cphi __._;%c__.__ __.__"), sep, sep);
-		ghid_cursor_position_relative_label_set_text(text);
-	}
-
-
-	text = pcb_strdup_printf("%m+%-mS%c%-mS", conf_core.editor.grid_unit->allow, pcb_crosshair.X, sep, pcb_crosshair.Y);
-	ghid_cursor_position_label_set_text(text);
-	free(text);
-}
diff --git a/src_plugins/hid_gtk/gui-netlist-window.c b/src_plugins/hid_gtk/gui-netlist-window.c
index c253d33..a0a1103 100644
--- a/src_plugins/hid_gtk/gui-netlist-window.c
+++ b/src_plugins/hid_gtk/gui-netlist-window.c
@@ -35,7 +35,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "win_place.h"
 
 #include "data.h"
 #include "draw.h"
@@ -51,7 +50,11 @@
 #include "obj_all.h"
 
 #include "gui.h"
-
+#include "../src_plugins/lib_gtk_common/util_str.h"
+#include "../src_plugins/lib_gtk_common/win_place.h"
+#include "../src_plugins/lib_gtk_common/bu_text_view.h"
+#include "../src_plugins/lib_gtk_common/bu_box.h"
+#include "../src_plugins/lib_gtk_common/bu_check_button.h"
 
 #define NET_HIERARCHY_SEPARATOR "/"
 
@@ -253,7 +256,7 @@ static void node_selection_changed_cb(GtkTreeSelection * selection, gpointer dat
 	 */
 	gtk_tree_model_get(model, &iter, NODE_LIBRARY_COLUMN, &node, -1);
 
-	dup_string(&node_name, node->ListEntry);
+	pcb_gtk_g_strdup(&node_name, node->ListEntry);
 	node_selected_net = selected_net;
 
 	/* Now just toggle a select of the node on the layout
@@ -919,6 +922,9 @@ void ghid_netlist_window_update(gboolean init_nodes)
 
 void GhidNetlistChanged(void *user_data, int argc, pcb_event_arg_t argv[])
 {
+	extern int gtkhid_active;
+	if (!gtkhid_active)
+		return;
 	loading_new_netlist = TRUE;
 	ghid_netlist_window_update(TRUE);
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(disable_all_button), FALSE);
diff --git a/src_plugins/hid_gtk/gui-output-events.c b/src_plugins/hid_gtk/gui-output-events.c
index 426b9f3..25464d2 100644
--- a/src_plugins/hid_gtk/gui-output-events.c
+++ b/src_plugins/hid_gtk/gui-output-events.c
@@ -30,7 +30,6 @@
 #include "conf_core.h"
 
 #include "gui.h"
-#include "gtkhid.h"
 #include "hid_cfg.h"
 
 #include <gdk/gdkkeysyms.h>
@@ -43,9 +42,12 @@
 #include "find.h"
 #include "search.h"
 #include "rats.h"
+#include "gtkhid-main.h"
 
-
-#define TOOLTIP_UPDATE_DELAY 200
+#include "../src_plugins/lib_gtk_common/bu_dwg_tooltip.h"
+#include "../src_plugins/lib_gtk_common/bu_status_line.h"
+#include "../src_plugins/lib_gtk_common/in_mouse.h"
+#include "../src_plugins/lib_gtk_common/in_keyboard.h"
 
 void ghid_port_ranges_changed(void)
 {
@@ -71,8 +73,7 @@ void ghid_port_ranges_scale(void)
 	   |  drawing area size in pixels to PCB units and that will be
 	   |  the page size for the Gtk adjustment.
 	 */
-	gport->view.width = gport->width * gport->view.coord_per_px;
-	gport->view.height = gport->height * gport->view.coord_per_px;
+	pcb_gtk_zoom_post(&gport->view);
 
 	adj = gtk_range_get_adjustment(GTK_RANGE(ghidgui->h_range));
 	page_size = MIN(gport->view.width, PCB->MaxWidth);
@@ -93,21 +94,6 @@ void ghid_port_ranges_scale(void)
 													 page_size);	/* page_size      */
 }
 
-
-/* ----------------------------------------------------------------------
- * handles all events from PCB drawing area
- */
-
-void ghid_get_coords(const char *msg, pcb_coord_t * x, pcb_coord_t * y)
-{
-	if (!ghid_port.has_entered && msg)
-		ghid_get_user_xy(msg);
-	if (ghid_port.has_entered) {
-		*x = gport->pcb_x;
-		*y = gport->pcb_y;
-	}
-}
-
 void ghid_note_event_location(GdkEventButton * ev)
 {
 	gint event_x, event_y;
@@ -120,17 +106,18 @@ void ghid_note_event_location(GdkEventButton * ev)
 		event_y = ev->y;
 	}
 
-	ghid_event_to_pcb_coords(event_x, event_y, &gport->pcb_x, &gport->pcb_y);
+	pcb_gtk_coords_event2pcb(&gport->view, event_x, event_y, &gport->view.pcb_x, &gport->view.pcb_y);
 
-	pcb_event_move_crosshair(gport->pcb_x, gport->pcb_y);
-	ghid_set_cursor_position_labels();
+	pcb_event_move_crosshair(gport->view.pcb_x, gport->view.pcb_y);
+	ghid_set_cursor_position_labels(&ghidgui->cps, conf_hid_gtk.plugins.hid_gtk.compact_vertical);
 }
 
-static gboolean ghid_idle_cb(gpointer data)
+#warning TODO: move this to common
+gboolean ghid_idle_cb(gpointer data)
 {
 	if (conf_core.editor.mode == PCB_MODE_NO)
 		pcb_crosshair_set_mode(PCB_MODE_ARROW);
-	ghid_mode_cursor(conf_core.editor.mode);
+	ghid_mode_cursor(&gport->mouse, conf_core.editor.mode);
 	if (ghidgui->settings_mode != conf_core.editor.mode) {
 		ghid_mode_buttons_update();
 	}
@@ -151,118 +138,17 @@ gboolean ghid_port_key_release_cb(GtkWidget * drawing_area, GdkEventKey * kev, g
 	return FALSE;
 }
 
-/* Handle user keys in the output drawing area. */
-gboolean ghid_port_key_press_cb(GtkWidget * drawing_area, GdkEventKey * kev, gpointer data)
-{
-	if (ghid_is_modifier_key_sym(kev->keyval))
-		return FALSE;
-
-	if (kev->keyval <= 0xffff) {
-		GdkModifierType state = (GdkModifierType) (kev->state);
-		int slen, mods = 0;
-		static pcb_hid_cfg_keyseq_t *seq[32];
-		static int seq_len = 0;
-		unsigned short int kv = kev->keyval;
-
-		ghid_note_event_location(NULL);
-
-		extern GdkModifierType ghid_glob_mask;
-		ghid_glob_mask = state;
-
-		if (state & GDK_MOD1_MASK)    mods |= PCB_M_Alt;
-		if (state & GDK_CONTROL_MASK) mods |= PCB_M_Ctrl;
-		if (state & GDK_SHIFT_MASK) {
-/* TODO#3: this works only on US keyboard */
-			static const char *ignore_shift = "~!@#$%^&*()_+{}|:\"<>?";
-			if ((kv < 32) || (kv > 126) || (strchr(ignore_shift, kv) == NULL)) {
-				mods |= PCB_M_Shift;
-				if ((kv >= 'A') && (kv <= 'Z'))
-					kv = tolower(kv);
-			}
-		}
-
-		if (kv == GDK_KEY_ISO_Left_Tab) kv = GDK_KEY_Tab;
-		slen = pcb_hid_cfg_keys_input(&ghid_keymap, mods, kv, seq, &seq_len);
-		if (slen > 0) {
-			ghid_port.has_entered  = 1;
-			pcb_hid_cfg_keys_action(seq, slen);
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
-static pcb_hid_cfg_mod_t ghid_mouse_button(int ev_button)
-{
-	/* GDK numbers buttons from 1..5, there seem to be no symbolic names */
-	return (PCB_MB_LEFT << (ev_button-1));
-}
-
-gboolean ghid_port_button_press_cb(GtkWidget * drawing_area, GdkEventButton * ev, gpointer data)
-{
-	ModifierKeysState mk;
-	GdkModifierType state;
-
-GHidPort *out = &ghid_port;
-GdkModifierType mask;
-
-	/* Reject double and triple click events */
-	if (ev->type != GDK_BUTTON_PRESS)
-		return TRUE;
-
-	ghid_note_event_location(ev);
-	state = (GdkModifierType) (ev->state);
-	mk = ghid_modifier_keys_state(&state);
-
-	extern GdkModifierType ghid_glob_mask;
-	ghid_glob_mask = state;
-
-	gdk_window_get_pointer(gtk_widget_get_window(out->drawing_area), NULL, NULL, &mask);
-
-	hid_cfg_mouse_action(&ghid_mouse, ghid_mouse_button(ev->button) | mk);
-
-	ghid_invalidate_all();
-	ghid_window_set_name_label(PCB->Name);
-	ghid_set_status_line_label();
-	if (!gport->panning)
-		g_idle_add(ghid_idle_cb, NULL);
-	return TRUE;
-}
-
-
-gboolean ghid_port_button_release_cb(GtkWidget * drawing_area, GdkEventButton * ev, gpointer data)
-{
-	ModifierKeysState mk;
-	GdkModifierType state;
-
-	ghid_note_event_location(ev);
-	state = (GdkModifierType) (ev->state);
-	mk = ghid_modifier_keys_state(&state);
-
-	hid_cfg_mouse_action(&ghid_mouse, ghid_mouse_button(ev->button) | mk | PCB_M_Release);
-
-	pcb_adjust_attached_objects();
-	ghid_invalidate_all();
-
-	ghid_window_set_name_label(PCB->Name);
-	ghid_set_status_line_label();
-	g_idle_add(ghid_idle_cb, NULL);
-	return TRUE;
-}
-
-
 gboolean ghid_port_drawing_area_configure_event_cb(GtkWidget * widget, GdkEventConfigure * ev, GHidPort * out)
 {
 	static gboolean first_time_done;
 
-	gport->width = ev->width;
-	gport->height = ev->height;
+	gport->view.canvas_width = ev->width;
+	gport->view.canvas_height = ev->height;
 
 	if (gport->pixmap)
 		gdk_pixmap_unref(gport->pixmap);
 
-	gport->pixmap = gdk_pixmap_new(gtk_widget_get_window(widget), gport->width, gport->height, -1);
+	gport->pixmap = gdk_pixmap_new(gtk_widget_get_window(widget), gport->view.canvas_width, gport->view.canvas_height, -1);
 	gport->drawable = gport->pixmap;
 
 	if (!first_time_done) {
@@ -289,111 +175,9 @@ gboolean ghid_port_drawing_area_configure_event_cb(GtkWidget * widget, GdkEventC
 	return 0;
 }
 
-
-static char *describe_location(pcb_coord_t X, pcb_coord_t Y)
-{
-	void *ptr1, *ptr2, *ptr3;
-	int type;
-	int Range = 0;
-	const char *elename = "";
-	char *pinname;
-	char *netname = NULL;
-	char *description;
-
-	/* check if there are any pins or pads at that position */
-
-	type = pcb_search_obj_by_location(PCB_TYPE_PIN | PCB_TYPE_PAD, &ptr1, &ptr2, &ptr3, X, Y, Range);
-	if (type == PCB_TYPE_NONE)
-		return NULL;
-
-	/* don't mess with silk objects! */
-	if (type & PCB_SILK_TYPE && pcb_layer_id(PCB->Data, (pcb_layer_t *) ptr1) >= pcb_max_copper_layer)
-		return NULL;
-
-	if (type == PCB_TYPE_PIN || type == PCB_TYPE_PAD)
-		elename = (char *) PCB_UNKNOWN(PCB_ELEM_NAME_REFDES((pcb_element_t *) ptr1));
-
-	pinname = pcb_connection_name(type, ptr1, ptr2);
-
-	if (pinname == NULL)
-		return NULL;
-
-	/* Find netlist entry */
-	PCB_MENU_LOOP(&PCB->NetlistLib[PCB_NETLIST_EDITED]);
-	{
-		if (!menu->Name)
-			continue;
-
-		PCB_ENTRY_LOOP(menu);
-		{
-			if (!entry->ListEntry)
-				continue;
-
-			if (strcmp(entry->ListEntry, pinname) == 0) {
-				netname = g_strdup(menu->Name);
-				/* For some reason, the netname has spaces in front of it, strip them */
-				g_strstrip(netname);
-				break;
-			}
-		}
-		PCB_END_LOOP;
-
-		if (netname != NULL)
-			break;
-	}
-	PCB_END_LOOP;
-
-	description = g_strdup_printf("Element name: %s\n"
-																"Pinname : %s\n"
-																"Netname : %s",
-																elename, (pinname != NULL) ? pinname : "--", (netname != NULL) ? netname : "--");
-
-	g_free(netname);
-
-	return description;
-}
-
-static int tooltip_update_timeout_id = 0;
-static gboolean check_object_tooltips(GHidPort * out)
-{
-	char *description;
-
-	/* Make sure the timer is not removed - we are called by the timer and it is
-	   automatically removed because we are returning false */
-	tooltip_update_timeout_id = 0;
-
-	/* check if there are any pins or pads at that position */
-	description = describe_location(out->crosshair_x, out->crosshair_y);
-
-	if (description == NULL)
-		return FALSE;
-
-	gtk_widget_set_tooltip_text(out->drawing_area, description);
-	g_free(description);
-
-	return FALSE;
-}
-
-static void cancel_tooltip_update()
-{
-	if (tooltip_update_timeout_id)
-		g_source_remove(tooltip_update_timeout_id);
-	tooltip_update_timeout_id = 0;
-}
-
-/* FIXME: If the GHidPort is ever destroyed, we must call
- * cancel_tooltip_update (), otherwise the timeout might
- * fire after the data it utilises has been free'd.
- */
-static void queue_tooltip_update(GHidPort * out)
+static gboolean check_object_tooltips(GHidPort *out)
 {
-	/* Zap the old tool-tip text and force it to be removed from the screen */
-	gtk_widget_set_tooltip_text(out->drawing_area, NULL);
-	gtk_widget_trigger_tooltip_query(out->drawing_area);
-
-	cancel_tooltip_update();
-
-	tooltip_update_timeout_id = g_timeout_add(TOOLTIP_UPDATE_DELAY, (GSourceFunc) check_object_tooltips, out);
+	return pcb_gtk_dwg_tooltip_check_object(out->drawing_area, out->view.crosshair_x, out->view.crosshair_y);
 }
 
 gint ghid_port_window_motion_cb(GtkWidget * widget, GdkEventMotion * ev, GHidPort * out)
@@ -403,11 +187,11 @@ gint ghid_port_window_motion_cb(GtkWidget * widget, GdkEventMotion * ev, GHidPor
 
 	gdk_event_request_motions(ev);
 
-	if (out->panning) {
+	if (out->view.panning) {
 		dx = gport->view.coord_per_px * (x_prev - ev->x);
 		dy = gport->view.coord_per_px * (y_prev - ev->y);
 		if (x_prev > 0)
-			ghid_pan_view_rel(dx, dy);
+			pcb_gtk_pan_view_rel(&gport->view, dx, dy);
 		x_prev = ev->x;
 		y_prev = ev->y;
 		return FALSE;
@@ -415,7 +199,7 @@ gint ghid_port_window_motion_cb(GtkWidget * widget, GdkEventMotion * ev, GHidPor
 	x_prev = y_prev = -1;
 	ghid_note_event_location((GdkEventButton *) ev);
 
-	queue_tooltip_update(out);
+	pcb_gtk_dwg_tooltip_queue(out->drawing_area, (GSourceFunc)check_object_tooltips, out);
 
 	return FALSE;
 }
@@ -431,7 +215,7 @@ gint ghid_port_window_enter_cb(GtkWidget * widget, GdkEventCrossing * ev, GHidPo
 	}
 
 	if (!ghidgui->command_entry_status_line_active) {
-		out->has_entered = TRUE;
+		out->view.has_entered = TRUE;
 		/* Make sure drawing area has keyboard focus when we are in it.
 		 */
 		gtk_widget_grab_focus(out->drawing_area);
@@ -463,7 +247,7 @@ gint ghid_port_window_leave_cb(GtkWidget * widget, GdkEventCrossing * ev, GHidPo
 		return FALSE;
 	}
 
-	out->has_entered = FALSE;
+	out->view.has_entered = FALSE;
 
 	ghid_screen_update();
 
@@ -471,37 +255,6 @@ gint ghid_port_window_leave_cb(GtkWidget * widget, GdkEventCrossing * ev, GHidPo
 }
 
 
-	/* Mouse scroll wheel events
-	 */
-gint ghid_port_window_mouse_scroll_cb(GtkWidget * widget, GdkEventScroll * ev, GHidPort * out)
-{
-	ModifierKeysState mk;
-	GdkModifierType state;
-	int button;
-
-	state = (GdkModifierType) (ev->state);
-	mk = ghid_modifier_keys_state(&state);
-
-	/* X11 gtk hard codes buttons 4, 5, 6, 7 as below in
-	 * gtk+/gdk/x11/gdkevents-x11.c:1121, but quartz and windows have
-	 * special mouse scroll events, so this may conflict with a mouse
-	 * who has buttons 4 - 7 that aren't the scroll wheel?
-	 */
-	switch (ev->direction) {
-		case GDK_SCROLL_UP:    button = PCB_MB_SCROLL_UP; break;
-		case GDK_SCROLL_DOWN:  button = PCB_MB_SCROLL_DOWN; break;
-		case GDK_SCROLL_LEFT:  button = PCB_MB_SCROLL_LEFT; break;
-		case GDK_SCROLL_RIGHT: button = PCB_MB_SCROLL_RIGHT; break;
-		default: return FALSE;
-	}
-
-	ghid_wheel_zoom = 1;
-	hid_cfg_mouse_action(&ghid_mouse, button | mk);
-	ghid_wheel_zoom = 0;
-
-	return TRUE;
-}
-
 void ghid_confchg_line_refraction(conf_native_t *cfg)
 {
 	/* test if PCB struct doesn't exist at startup */
diff --git a/src_plugins/hid_gtk/gui-pinout-preview.c b/src_plugins/hid_gtk/gui-pinout-preview.c
deleted file mode 100644
index 2773a19..0000000
--- a/src_plugins/hid_gtk/gui-pinout-preview.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 1994,1995,1996 Thomas Nau
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Contact addresses for paper mail and Email:
- *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
- *  Thomas.Nau at rz.uni-ulm.de
- *
- */
-
-/* This file copied and modified by Peter Clifton, starting from
- * gui-pinout-window.c, written by Bill Wilson for the PCB Gtk port */
-
-#include "config.h"
-#include "conf_core.h"
-
-#include "gui.h"
-
-#include "copy.h"
-#include "data.h"
-#include "draw.h"
-#include "move.h"
-#include "rotate.h"
-#include "obj_all.h"
-#include "gui-pinout-preview.h"
-
-/* Just define a sensible scale, lets say (for example), 100 pixel per 150 mil */
-#define SENSIBLE_VIEW_SCALE  (100. / PCB_MIL_TO_COORD (150.))
-static void pinout_set_view(GhidPinoutPreview * pinout)
-{
-	float scale = SENSIBLE_VIEW_SCALE;
-
-	pinout->x_max = pinout->element.BoundingBox.X2 + conf_core.appearance.pinout.offset_x;
-	pinout->y_max = pinout->element.BoundingBox.Y2 + conf_core.appearance.pinout.offset_y;
-	pinout->w_pixels = scale * (pinout->element.BoundingBox.X2 - pinout->element.BoundingBox.X1);
-	pinout->h_pixels = scale * (pinout->element.BoundingBox.Y2 - pinout->element.BoundingBox.Y1);
-}
-
-
-static void pinout_set_data(GhidPinoutPreview * pinout, pcb_element_t * element)
-{
-	if (element == NULL) {
-		pcb_element_destroy(&pinout->element);
-		pinout->w_pixels = 0;
-		pinout->h_pixels = 0;
-		return;
-	}
-
-	/* 
-	 * copy element data 
-	 * enable output of pin and padnames
-	 * move element to a 5% offset from zero position
-	 * set all package lines/arcs to zero width
-	 */
-	pcb_element_copy(NULL, &pinout->element, element, FALSE, 0, 0);
-	PCB_PIN_LOOP(&pinout->element);
-	{
-		PCB_FLAG_SET(PCB_FLAG_DISPLAYNAME, pin);
-	}
-	PCB_END_LOOP;
-
-	PCB_PAD_LOOP(&pinout->element);
-	{
-		PCB_FLAG_SET(PCB_FLAG_DISPLAYNAME, pad);
-	}
-	PCB_END_LOOP;
-
-
-	pcb_element_move(NULL, &pinout->element,
-											conf_core.appearance.pinout.offset_x -
-											pinout->element.BoundingBox.X1, conf_core.appearance.pinout.offset_y - pinout->element.BoundingBox.Y1);
-
-	pinout_set_view(pinout);
-
-	PCB_ELEMENT_PCB_LINE_LOOP(&pinout->element);
-	{
-		line->Thickness = 0;
-	}
-	PCB_END_LOOP;
-
-	PCB_ARC_LOOP(&pinout->element);
-	{
-		/* 
-		 * for whatever reason setting a thickness of 0 causes the arcs to
-		 * not display so pick 1 which does display but is still quite
-		 * thin.
-		 */
-		arc->Thickness = 1;
-	}
-	PCB_END_LOOP;
-}
-
-
-enum {
-	PROP_ELEMENT_DATA = 1,
-};
-
-
-static GObjectClass *ghid_pinout_preview_parent_class = NULL;
-
-
-/*! \brief GObject constructed
- *
- *  \par Function Description
- *  Initialise the pinout preview object once it is constructed.
- *  Chain up in case the parent class wants to do anything too.
- *
- *  \param [in] object  The pinout preview object
- */
-static void ghid_pinout_preview_constructed(GObject * object)
-{
-	/* chain up to the parent class */
-	if (G_OBJECT_CLASS(ghid_pinout_preview_parent_class)->constructed != NULL)
-		G_OBJECT_CLASS(ghid_pinout_preview_parent_class)->constructed(object);
-
-	ghid_init_drawing_widget(GTK_WIDGET(object), gport);
-}
-
-
-
-/*! \brief GObject finalise handler
- *
- *  \par Function Description
- *  Just before the GhidPinoutPreview GObject is finalized, free our
- *  allocated data, and then chain up to the parent's finalize handler.
- *
- *  \param [in] widget  The GObject being finalized.
- */
-static void ghid_pinout_preview_finalize(GObject * object)
-{
-	GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW(object);
-
-	/* Passing NULL for element data will free the old memory */
-	pinout_set_data(pinout, NULL);
-
-	G_OBJECT_CLASS(ghid_pinout_preview_parent_class)->finalize(object);
-}
-
-
-/*! \brief GObject property setter function
- *
- *  \par Function Description
- *  Setter function for GhidPinoutPreview's GObject properties,
- *  "settings-name" and "toplevel".
- *
- *  \param [in]  object       The GObject whose properties we are setting
- *  \param [in]  property_id  The numeric id. under which the property was
- *                            registered with g_object_class_install_property()
- *  \param [in]  value        The GValue the property is being set from
- *  \param [in]  pspec        A GParamSpec describing the property being set
- */
-static void ghid_pinout_preview_set_property(GObject * object, guint property_id, const GValue * value, GParamSpec * pspec)
-{
-	GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW(object);
-	GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(pinout));
-
-	switch (property_id) {
-	case PROP_ELEMENT_DATA:
-		pinout_set_data(pinout, (pcb_element_t *) g_value_get_pointer(value));
-		if (window != NULL)
-			gdk_window_invalidate_rect(window, NULL, FALSE);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
-	}
-
-}
-
-
-/*! \brief GObject property getter function
- *
- *  \par Function Description
- *  Getter function for GhidPinoutPreview's GObject properties,
- *  "settings-name" and "toplevel".
- *
- *  \param [in]  object       The GObject whose properties we are getting
- *  \param [in]  property_id  The numeric id. under which the property was
- *                            registered with g_object_class_install_property()
- *  \param [out] value        The GValue in which to return the value of the property
- *  \param [in]  pspec        A GParamSpec describing the property being got
- */
-static void ghid_pinout_preview_get_property(GObject * object, guint property_id, GValue * value, GParamSpec * pspec)
-{
-	switch (property_id) {
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
-	}
-
-}
-
-
-/*! \brief GType class initialiser for GhidPinoutPreview
- *
- *  \par Function Description
- *  GType class initialiser for GhidPinoutPreview. We override our parent
- *  virtual class methods as needed and register our GObject properties.
- *
- *  \param [in]  klass       The GhidPinoutPreviewClass we are initialising
- */
-static void ghid_pinout_preview_class_init(GhidPinoutPreviewClass * klass)
-{
-	GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
-	GtkWidgetClass *gtk_widget_class = GTK_WIDGET_CLASS(klass);
-
-	gobject_class->finalize = ghid_pinout_preview_finalize;
-	gobject_class->set_property = ghid_pinout_preview_set_property;
-	gobject_class->get_property = ghid_pinout_preview_get_property;
-	gobject_class->constructed = ghid_pinout_preview_constructed;
-
-	gtk_widget_class->expose_event = ghid_pinout_preview_expose;
-
-	ghid_pinout_preview_parent_class = (GObjectClass *) g_type_class_peek_parent(klass);
-
-	g_object_class_install_property(gobject_class, PROP_ELEMENT_DATA,
-																	g_param_spec_pointer("element-data", "", "", G_PARAM_WRITABLE));
-}
-
-
-/*! \brief Function to retrieve GhidPinoutPreview's GType identifier.
- *
- *  \par Function Description
- *  Function to retrieve GhidPinoutPreview's GType identifier.
- *  Upon first call, this registers the GhidPinoutPreview in the GType system.
- *  Subsequently it returns the saved value from its first execution.
- *
- *  \return the GType identifier associated with GhidPinoutPreview.
- */
-GType ghid_pinout_preview_get_type()
-{
-	static GType ghid_pinout_preview_type = 0;
-
-	if (!ghid_pinout_preview_type) {
-		static const GTypeInfo ghid_pinout_preview_info = {
-			sizeof(GhidPinoutPreviewClass),
-			NULL,											/* base_init */
-			NULL,											/* base_finalize */
-			(GClassInitFunc) ghid_pinout_preview_class_init,
-			NULL,											/* class_finalize */
-			NULL,											/* class_data */
-			sizeof(GhidPinoutPreview),
-			0,												/* n_preallocs */
-			NULL,											/* instance_init */
-		};
-
-		ghid_pinout_preview_type =
-			g_type_register_static(GTK_TYPE_DRAWING_AREA, "GhidPinoutPreview", &ghid_pinout_preview_info, (GTypeFlags) 0);
-	}
-
-	return ghid_pinout_preview_type;
-}
-
-
-/*! \brief Convenience function to create a new pinout preview
- *
- *  \par Function Description
- *  Convenience function which creates a GhidPinoutPreview.
- *
- *  \return  The GhidPinoutPreview created.
- */
-GtkWidget *ghid_pinout_preview_new(pcb_element_t * element)
-{
-	GhidPinoutPreview *pinout_preview;
-
-	pinout_preview = (GhidPinoutPreview *) g_object_new(GHID_TYPE_PINOUT_PREVIEW, "element-data", element, NULL);
-
-	return GTK_WIDGET(pinout_preview);
-}
-
-
-/*! \brief Query the natural size of a pinout preview
- *
- *  \par Function Description
- *  Convenience function to query the natural size of a pinout preview
- */
-void ghid_pinout_preview_get_natural_size(GhidPinoutPreview * pinout, int *width, int *height)
-{
-	*width = pinout->w_pixels;
-	*height = pinout->h_pixels;
-}
diff --git a/src_plugins/hid_gtk/gui-pinout-preview.h b/src_plugins/hid_gtk/gui-pinout-preview.h
deleted file mode 100644
index 78afd1f..0000000
--- a/src_plugins/hid_gtk/gui-pinout-preview.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 1994,1995,1996 Thomas Nau
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Contact addresses for paper mail and Email:
- *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
- *  Thomas.Nau at rz.uni-ulm.de
- *
- */
-
-/* This file written by Peter Clifton */
-
-#ifndef PCB_HID_GTK_GUI_PINOUT_PREVIEW_H
-#define PCB_HID_GTK_GUI_PINOUT_PREVIEW_H
-
-
-#define GHID_TYPE_PINOUT_PREVIEW           (ghid_pinout_preview_get_type())
-#define GHID_PINOUT_PREVIEW(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_TYPE_PINOUT_PREVIEW, GhidPinoutPreview))
-#define GHID_PINOUT_PREVIEW_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass),  GHID_TYPE_PINOUT_PREVIEW, GhidPinoutPreviewClass))
-#define GHID_IS_PINOUT_PREVIEW(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_TYPE_PINOUT_PREVIEW))
-#define GHID_PINOUT_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),  GHID_TYPE_PINOUT_PREVIEW, GhidPinoutPreviewClass))
-
-typedef struct _GhidPinoutPreviewClass GhidPinoutPreviewClass;
-typedef struct _GhidPinoutPreview GhidPinoutPreview;
-
-
-struct _GhidPinoutPreviewClass {
-	GtkDrawingAreaClass parent_class;
-};
-
-struct _GhidPinoutPreview {
-	GtkDrawingArea parent_instance;
-
-	pcb_element_t element;					/* element data to display */
-	gint x_max, y_max;
-	gint w_pixels, h_pixels;			/* natural size of element preview */
-};
-
-
-GType ghid_pinout_preview_get_type(void);
-
-GtkWidget *ghid_pinout_preview_new(pcb_element_t * element);
-void ghid_pinout_preview_get_natural_size(GhidPinoutPreview * pinout, int *width, int *height);
-
-#endif /* PCB_HID_GTK_GUI_PINOUT_PREVIEW_H */
diff --git a/src_plugins/hid_gtk/gui-pinout-window.c b/src_plugins/hid_gtk/gui-pinout-window.c
deleted file mode 100644
index 2507ae2..0000000
--- a/src_plugins/hid_gtk/gui-pinout-window.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 1994,1995,1996 Thomas Nau
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Contact addresses for paper mail and Email:
- *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
- *  Thomas.Nau at rz.uni-ulm.de
- *
- */
-
-/* This file written by Bill Wilson for the PCB Gtk port */
-
-#include "config.h"
-#include "conf_core.h"
-
-#include "gui.h"
-#include "win_place.h"
-
-#include "copy.h"
-#include "data.h"
-#include "draw.h"
-#include "move.h"
-#include "rotate.h"
-
-#include "gui-pinout-preview.h"
-
-static void pinout_close_cb(GtkWidget * widget, GtkWidget * top_window)
-{
-	gtk_widget_destroy(top_window);
-}
-
-
-void ghid_pinout_window_show(GHidPort * out, pcb_element_t * element)
-{
-	GtkWidget *button, *vbox, *hbox, *preview, *top_window;
-	gchar *title;
-	int width, height;
-
-	if (!element)
-		return;
-	title = g_strdup_printf("%s [%s,%s]",
-													PCB_UNKNOWN(PCB_ELEM_NAME_DESCRIPTION(element)), PCB_UNKNOWN(PCB_ELEM_NAME_REFDES(element)), PCB_UNKNOWN(PCB_ELEM_NAME_VALUE(element)));
-
-	top_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	gtk_window_set_title(GTK_WINDOW(top_window), title);
-	g_free(title);
-	gtk_window_set_wmclass(GTK_WINDOW(top_window), "PCB_Pinout", "PCB");
-	gtk_container_set_border_width(GTK_CONTAINER(top_window), 4);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(top_window), vbox);
-
-
-	preview = ghid_pinout_preview_new(element);
-	gtk_box_pack_start(GTK_BOX(vbox), preview, TRUE, TRUE, 0);
-
-	ghid_pinout_preview_get_natural_size(GHID_PINOUT_PREVIEW(preview), &width, &height);
-
-	gtk_window_set_default_size(GTK_WINDOW(top_window), width + 50, height + 50);
-
-	hbox = gtk_hbutton_box_new();
-	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-	button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pinout_close_cb), top_window);
-	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
-
-	gtk_widget_realize(top_window);
-	wplc_place(WPLC_PINOUT, top_window);
-	gtk_widget_show_all(top_window);
-}
diff --git a/src_plugins/hid_gtk/gui-top-window.c b/src_plugins/hid_gtk/gui-top-window.c
index 2db5136..dcda1ab 100644
--- a/src_plugins/hid_gtk/gui-top-window.c
+++ b/src_plugins/hid_gtk/gui-top-window.c
@@ -50,13 +50,10 @@ I NEED TO DO THE STATUS LINE THING.for example shift - alt - v to change the
 |  we have our own shortcut table and capture the keys and send the events
 |  there in ghid_port_key_press_cb().
 */
+#define _POSIX_SOURCE
 #include "config.h"
 #include "conf_core.h"
-
 #include <locale.h>
-#include "ghid-layer-selector.h"
-#include "ghid-route-style-selector.h"
-#include "gtkhid.h"
 #include "gui.h"
 #include "hid.h"
 #include "hid_cfg.h"
@@ -86,7 +83,6 @@ I NEED TO DO THE STATUS LINE THING.for example shift - alt - v to change the
 #include "paths.h"
 #include "gui-icons-mode-buttons.data"
 #include "gui-icons-misc.data"
-#include "win_place.h"
 #include "hid_attrib.h"
 #include "hid_actions.h"
 #include "hid_flags.h"
@@ -95,6 +91,16 @@ I NEED TO DO THE STATUS LINE THING.for example shift - alt - v to change the
 #include "compat_misc.h"
 #include "obj_line.h"
 #include "layer_vis.h"
+#include "gtkhid-main.h"
+
+#include "../src_plugins/lib_gtk_common/bu_box.h"
+#include "../src_plugins/lib_gtk_common/bu_status_line.h"
+#include "../src_plugins/lib_gtk_common/dlg_route_style.h"
+#include "../src_plugins/lib_gtk_common/util_str.h"
+#include "../src_plugins/lib_gtk_common/in_mouse.h"
+#include "../src_plugins/lib_gtk_common/in_keyboard.h"
+#include "../src_plugins/lib_gtk_common/wt_layer_selector.h"
+#include "../src_plugins/lib_gtk_common/win_place.h"
 
 static pcb_bool ignore_layer_update;
 
@@ -105,7 +111,6 @@ GhidGui _ghidgui, *ghidgui = &_ghidgui;
 GHidPort ghid_port, *gport;
 
 pcb_hid_cfg_t *ghid_cfg = NULL;
-pcb_hid_cfg_mouse_t ghid_mouse;
 pcb_hid_cfg_keys_t ghid_keymap;
 
 /*! \brief callback for ghid_main_menu_update_toggle_state () */
@@ -322,7 +327,7 @@ void ghid_sync_with_new_layout(void)
 {
 	if (vtroutestyle_len(&PCB->RouteStyle) > 0) {
 		pcb_use_route_style(&PCB->RouteStyle.array[0]);
-		ghid_route_style_selector_select_style(GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector), &PCB->RouteStyle.array[0]);
+		pcb_gtk_route_style_select_style(GHID_ROUTE_STYLE(ghidgui->route_style_selector), &PCB->RouteStyle.array[0]);
 	}
 
 	ghid_config_handle_units_changed();
@@ -430,8 +435,8 @@ static void layer_process(const gchar ** color_string, const char **text, int *s
 	}
 }
 
-/*! \brief Callback for GHidLayerSelector layer selection */
-static void layer_selector_select_callback(GHidLayerSelector * ls, int layer, gpointer d)
+/*! \brief Callback for pcb_gtk_layer_selector_t layer selection */
+static void layer_selector_select_callback(pcb_gtk_layer_selector_t * ls, int layer, gpointer d)
 {
 	ignore_layer_update = pcb_true;
 	/* Select Layer */
@@ -445,7 +450,7 @@ static void layer_selector_select_callback(GHidLayerSelector * ls, int layer, gp
 		PCB->RatOn = pcb_true;
 		ghid_LayersChanged(0, 0, 0);
 	}
-	else if (layer < pcb_max_copper_layer)
+	else
 		pcb_layervis_change_group_vis(layer, TRUE, pcb_true);
 
 	ignore_layer_update = pcb_false;
@@ -453,8 +458,8 @@ static void layer_selector_select_callback(GHidLayerSelector * ls, int layer, gp
 	ghid_invalidate_all();
 }
 
-/*! \brief Callback for GHidLayerSelector layer toggling */
-static void layer_selector_toggle_callback(GHidLayerSelector * ls, int layer, gpointer d)
+/*! \brief Callback for pcb_gtk_layer_selector_t layer toggling */
+static void layer_selector_toggle_callback(pcb_gtk_layer_selector_t * ls, int layer, gpointer d)
 {
 	gboolean redraw = FALSE;
 	gboolean active;
@@ -511,7 +516,7 @@ static void layer_selector_toggle_callback(GHidLayerSelector * ls, int layer, gp
 	 * will never have an invisible layer selected.
 	 */
 	if (!active)
-		ghid_layer_selector_select_next_visible(ls);
+		pcb_gtk_layer_selector_select_next_visible(ls);
 
 	ignore_layer_update = pcb_false;
 
@@ -523,18 +528,18 @@ static void layer_selector_toggle_callback(GHidLayerSelector * ls, int layer, gp
 void ghid_install_accel_groups(GtkWindow * window, GhidGui * gui)
 {
 	gtk_window_add_accel_group(window, ghid_main_menu_get_accel_group(GHID_MAIN_MENU(gui->menu_bar)));
-	gtk_window_add_accel_group(window, ghid_layer_selector_get_accel_group(GHID_LAYER_SELECTOR(gui->layer_selector)));
+	gtk_window_add_accel_group(window, pcb_gtk_layer_selector_get_accel_group(GHID_LAYER_SELECTOR(gui->layer_selector)));
 	gtk_window_add_accel_group
-		(window, ghid_route_style_selector_get_accel_group(GHID_ROUTE_STYLE_SELECTOR(gui->route_style_selector)));
+		(window, pcb_gtk_route_style_get_accel_group(GHID_ROUTE_STYLE(gui->route_style_selector)));
 }
 
 /*! \brief Remove menu bar and accelerator groups */
 void ghid_remove_accel_groups(GtkWindow * window, GhidGui * gui)
 {
 	gtk_window_remove_accel_group(window, ghid_main_menu_get_accel_group(GHID_MAIN_MENU(gui->menu_bar)));
-	gtk_window_remove_accel_group(window, ghid_layer_selector_get_accel_group(GHID_LAYER_SELECTOR(gui->layer_selector)));
+	gtk_window_remove_accel_group(window, pcb_gtk_layer_selector_get_accel_group(GHID_LAYER_SELECTOR(gui->layer_selector)));
 	gtk_window_remove_accel_group
-		(window, ghid_route_style_selector_get_accel_group(GHID_ROUTE_STYLE_SELECTOR(gui->route_style_selector)));
+		(window, pcb_gtk_route_style_get_accel_group(GHID_ROUTE_STYLE(gui->route_style_selector)));
 }
 
 /* Refreshes the window title bar and sets the PCB name to the
@@ -550,7 +555,7 @@ void ghid_window_set_name_label(gchar * name)
 	if (ghidgui == NULL)
 		return;
 
-	dup_string(&(ghidgui->name_label_string), name);
+	pcb_gtk_g_strdup(&(ghidgui->name_label_string), name);
 	if (!ghidgui->name_label_string || !*ghidgui->name_label_string)
 		ghidgui->name_label_string = g_strdup(_("Unnamed"));
 
@@ -565,111 +570,36 @@ void ghid_window_set_name_label(gchar * name)
 	g_free(filename);
 }
 
-static void grid_units_button_cb(GtkWidget * widget, gpointer data)
-{
-	/* Button only toggles between mm and mil */
-	if (conf_core.editor.grid_unit == get_unit_struct("mm"))
-		pcb_hid_actionl("SetUnits", "mil", NULL);
-	else
-		pcb_hid_actionl("SetUnits", "mm", NULL);
-}
-
-/*
- * The two following callbacks are used to keep the absolute
- * and relative cursor labels from growing and shrinking as you
- * move the cursor around.
- */
-static void absolute_label_size_req_cb(GtkWidget * widget, GtkRequisition * req, gpointer data)
-{
-
-	static gint w = 0;
-	if (req->width > w)
-		w = req->width;
-	else
-		req->width = w;
-}
-
-static void relative_label_size_req_cb(GtkWidget * widget, GtkRequisition * req, gpointer data)
-{
-
-	static gint w = 0;
-	if (req->width > w)
-		w = req->width;
-	else
-		req->width = w;
-}
-
-static void make_cursor_position_labels(GtkWidget * hbox, GHidPort * port)
-{
-	GtkWidget *frame, *label;
-
-	/* The grid units button next to the cursor position labels.
-	 */
-	ghidgui->grid_units_button = gtk_button_new();
-	label = gtk_label_new("");
-	gtk_label_set_markup(GTK_LABEL(label), conf_core.editor.grid_unit->in_suffix);
-	ghidgui->grid_units_label = label;
-	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
-	gtk_container_add(GTK_CONTAINER(ghidgui->grid_units_button), label);
-	gtk_box_pack_end(GTK_BOX(hbox), ghidgui->grid_units_button, FALSE, TRUE, 0);
-	g_signal_connect(ghidgui->grid_units_button, "clicked", G_CALLBACK(grid_units_button_cb), NULL);
-
-	/* The absolute cursor position label
-	 */
-	frame = gtk_frame_new(NULL);
-	gtk_box_pack_end(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
-	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
-
-	label = gtk_label_new("");
-	gtk_container_add(GTK_CONTAINER(frame), label);
-	ghidgui->cursor_position_absolute_label = label;
-	g_signal_connect(G_OBJECT(label), "size-request", G_CALLBACK(absolute_label_size_req_cb), NULL);
-
-
-	/* The relative cursor position label
-	 */
-	frame = gtk_frame_new(NULL);
-	gtk_box_pack_end(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
-	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
-	label = gtk_label_new(" __.__  __.__ ");
-	gtk_container_add(GTK_CONTAINER(frame), label);
-	ghidgui->cursor_position_relative_label = label;
-	g_signal_connect(G_OBJECT(label), "size-request", G_CALLBACK(relative_label_size_req_cb), NULL);
-
-}
-
 /* \brief Add "virtual layers" to a layer selector */
 static void make_virtual_layer_buttons(GtkWidget * layer_selector)
 {
-	GHidLayerSelector *layersel = GHID_LAYER_SELECTOR(layer_selector);
+	pcb_gtk_layer_selector_t *layersel = GHID_LAYER_SELECTOR(layer_selector);
 	const gchar *text;
 	const gchar *color_string;
 	gboolean active;
 	pcb_layer_id_t ui[16], numui, n;
 
 	layer_process(&color_string, &text, &active, LAYER_BUTTON_SILK);
-	ghid_layer_selector_add_layer(layersel, LAYER_BUTTON_SILK, text, color_string, active, TRUE);
+	pcb_gtk_layer_selector_add_layer(layersel, LAYER_BUTTON_SILK, text, color_string, active, TRUE);
 	layer_process(&color_string, &text, &active, LAYER_BUTTON_RATS);
-	ghid_layer_selector_add_layer(layersel, LAYER_BUTTON_RATS, text, color_string, active, TRUE);
+	pcb_gtk_layer_selector_add_layer(layersel, LAYER_BUTTON_RATS, text, color_string, active, TRUE);
 	layer_process(&color_string, &text, &active, LAYER_BUTTON_PINS);
-	ghid_layer_selector_add_layer(layersel, LAYER_BUTTON_PINS, text, color_string, active, FALSE);
+	pcb_gtk_layer_selector_add_layer(layersel, LAYER_BUTTON_PINS, text, color_string, active, FALSE);
 	layer_process(&color_string, &text, &active, LAYER_BUTTON_VIAS);
-	ghid_layer_selector_add_layer(layersel, LAYER_BUTTON_VIAS, text, color_string, active, FALSE);
+	pcb_gtk_layer_selector_add_layer(layersel, LAYER_BUTTON_VIAS, text, color_string, active, FALSE);
 	layer_process(&color_string, &text, &active, LAYER_BUTTON_FARSIDE);
-	ghid_layer_selector_add_layer(layersel, LAYER_BUTTON_FARSIDE, text, color_string, active, FALSE);
+	pcb_gtk_layer_selector_add_layer(layersel, LAYER_BUTTON_FARSIDE, text, color_string, active, FALSE);
 	layer_process(&color_string, &text, &active, LAYER_BUTTON_MASK);
-	ghid_layer_selector_add_layer(layersel, LAYER_BUTTON_MASK, text, color_string, active, FALSE);
+	pcb_gtk_layer_selector_add_layer(layersel, LAYER_BUTTON_MASK, text, color_string, active, FALSE);
 
-	numui = pcb_layer_list(PCB_LYT_UI, ui, sizeof(ui)/sizeof(ui[0]));
-	for(n = 0; n < numui; n++) {
+	numui = pcb_layer_list(PCB_LYT_UI, ui, sizeof(ui) / sizeof(ui[0]));
+	for (n = 0; n < numui; n++) {
 		pcb_layer_t *l = pcb_get_layer(ui[n]);
-		ghid_layer_selector_add_layer(layersel, LAYER_BUTTON_UI, l->Name, l->Color, 1, FALSE);
+		pcb_gtk_layer_selector_add_layer(layersel, LAYER_BUTTON_UI, l->Name, l->Color, 1, FALSE);
 	}
 }
 
-/*! \brief callback for ghid_layer_selector_update_colors */
+/*! \brief callback for pcb_gtk_layer_selector_update_colors */
 const gchar *get_layer_color(gint layer)
 {
 	const gchar *rv;
@@ -680,7 +610,7 @@ const gchar *get_layer_color(gint layer)
 /*! \brief Update a layer selector's color scheme */
 void ghid_layer_buttons_color_update(void)
 {
-	ghid_layer_selector_update_colors(GHID_LAYER_SELECTOR(ghidgui->layer_selector), get_layer_color);
+	pcb_gtk_layer_selector_update_colors(GHID_LAYER_SELECTOR(ghidgui->layer_selector), get_layer_color);
 	pcb_colors_from_settings(PCB);
 }
 
@@ -692,17 +622,21 @@ static void make_layer_buttons(GtkWidget * layersel)
 	const gchar *color_string;
 	gboolean active = TRUE;
 
-	for (i = 0; i < pcb_max_copper_layer; ++i) {
+	for (i = 0; i < pcb_max_layer; ++i) {
+		if (pcb_layer_flags(i) & PCB_LYT_SILK)
+			continue;									/* silks have a special, common button */
 		layer_process(&color_string, &text, &active, i);
-		ghid_layer_selector_add_layer(GHID_LAYER_SELECTOR(layersel), i, text, color_string, active, TRUE);
+		pcb_gtk_layer_selector_add_layer(GHID_LAYER_SELECTOR(layersel), i, text, color_string, active, TRUE);
 	}
 }
 
 
-/*! \brief callback for ghid_layer_selector_delete_layers */
+/*! \brief callback for pcb_gtk_layer_selector_delete_layers */
 gboolean get_layer_delete(gint layer)
 {
-	return layer >= pcb_max_copper_layer;
+	if (pcb_layer_flags(layer) & PCB_LYT_SILK)
+		return 1;
+	return layer >= pcb_max_layer;
 }
 
 /*! \brief Synchronize layer selector widget with current PCB state
@@ -717,7 +651,7 @@ void ghid_layer_buttons_update(void)
 	if (ignore_layer_update)
 		return;
 
-	ghid_layer_selector_delete_layers(GHID_LAYER_SELECTOR(ghidgui->layer_selector), get_layer_delete);
+	pcb_gtk_layer_selector_delete_layers(GHID_LAYER_SELECTOR(ghidgui->layer_selector), get_layer_delete);
 	make_layer_buttons(ghidgui->layer_selector);
 	make_virtual_layer_buttons(ghidgui->layer_selector);
 	ghid_main_menu_install_layer_selector(GHID_MAIN_MENU(ghidgui->menu_bar), GHID_LAYER_SELECTOR(ghidgui->layer_selector));
@@ -730,38 +664,17 @@ void ghid_layer_buttons_update(void)
 	else
 		layer = pcb_layer_stack[0];
 
-	ghid_layer_selector_select_layer(GHID_LAYER_SELECTOR(ghidgui->layer_selector), layer);
+	pcb_gtk_layer_selector_select_layer(GHID_LAYER_SELECTOR(ghidgui->layer_selector), layer);
 }
 
 /*! \brief Called when user clicks OK on route style dialog */
-static void route_styles_edited_cb(GHidRouteStyleSelector * rss, gboolean save, gpointer data)
+void route_styles_edited_cb(pcb_gtk_route_style_t * rss, gboolean save, gpointer data)
 {
 	conf_setf(CFR_DESIGN, "design/routes", -1, "%s", pcb_route_string_make(&PCB->RouteStyle));
 	if (save)
 		conf_setf(CFR_USER, "design/routes", -1, "%s", pcb_route_string_make(&PCB->RouteStyle));
 	ghid_main_menu_install_route_style_selector
-		(GHID_MAIN_MENU(ghidgui->menu_bar), GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector));
-}
-
-/*! \brief Called when a route style is selected */
-static void route_style_changed_cb(GHidRouteStyleSelector * rss, pcb_route_style_t * rst, gpointer data)
-{
-	pcb_use_route_style(rst);
-	ghid_set_status_line_label();
-}
-
-/*! \brief Configure the route style selector */
-void make_route_style_buttons(GHidRouteStyleSelector * rss)
-{
-	int i;
-
-	/* Make sure the <custom> item is added */
-	ghid_route_style_selector_add_route_style(rss, NULL);
-
-	for (i = 0; i < vtroutestyle_len(&PCB->RouteStyle); ++i)
-		ghid_route_style_selector_add_route_style(rss, &PCB->RouteStyle.array[i]);
-	g_signal_connect(G_OBJECT(rss), "select_style", G_CALLBACK(route_style_changed_cb), NULL);
-	g_signal_connect(G_OBJECT(rss), "style_edited", G_CALLBACK(route_styles_edited_cb), NULL);
+		(GHID_MAIN_MENU(ghidgui->menu_bar), GHID_ROUTE_STYLE(ghidgui->route_style_selector));
 }
 
 /*
@@ -801,7 +714,7 @@ static gint n_mode_buttons = G_N_ELEMENTS(mode_buttons);
 static void do_set_mode(int mode)
 {
 	pcb_crosshair_set_mode(mode);
-	ghid_mode_cursor(mode);
+	ghid_mode_cursor(&gport->mouse, mode);
 	ghidgui->settings_mode = mode;
 }
 
@@ -1017,20 +930,20 @@ static void do_fix_topbar_theming(void)
 	 * need to grab the GtkStyle associated with an actual menu item to
 	 * get a text color to render with.
 	 */
-	gtk_widget_set_style(ghidgui->cursor_position_relative_label, menu_bar_style);
-	gtk_widget_set_style(ghidgui->cursor_position_absolute_label, menu_bar_style);
+	gtk_widget_set_style(ghidgui->cps.cursor_position_relative_label, menu_bar_style);
+	gtk_widget_set_style(ghidgui->cps.cursor_position_absolute_label, menu_bar_style);
 
 	/* Style the units button as if it were a toolbar button - hopefully
 	 * this isn't too ugly sitting on a background themed as a menu bar.
 	 * It is unlikely any theme defines colours for a GtkButton sitting on
 	 * a menu bar.
 	 */
-	rel_pos_frame = gtk_widget_get_parent(ghidgui->cursor_position_relative_label);
-	abs_pos_frame = gtk_widget_get_parent(ghidgui->cursor_position_absolute_label);
+	rel_pos_frame = gtk_widget_get_parent(ghidgui->cps.cursor_position_relative_label);
+	abs_pos_frame = gtk_widget_get_parent(ghidgui->cps.cursor_position_absolute_label);
 	gtk_widget_set_style(rel_pos_frame, menu_bar_style);
 	gtk_widget_set_style(abs_pos_frame, menu_bar_style);
-	gtk_widget_set_style(ghidgui->grid_units_button, tool_button_style);
-	gtk_widget_set_style(ghidgui->grid_units_label, tool_button_label_style);
+	gtk_widget_set_style(ghidgui->cps.grid_units_button, tool_button_style);
+	gtk_widget_set_style(ghidgui->cps.grid_units_label, tool_button_label_style);
 }
 
 /* Attempt to produce a conststent style for our extra menu-bar items by
@@ -1049,7 +962,7 @@ static void fix_topbar_theming(void)
 	g_signal_connect(settings, "notify::gtk-font-name", G_CALLBACK(do_fix_topbar_theming), NULL);
 }
 
-static void fullscreen_cb(GtkButton *btn, void *data)
+static void fullscreen_cb(GtkButton * btn, void *data)
 {
 	conf_setf(CFR_DESIGN, "editor/fullscreen", -1, "%d", !conf_core.editor.fullscreen, POL_OVERWRITE);
 }
@@ -1090,7 +1003,7 @@ static void ghid_build_pcb_top_window(void)
 	gtk_box_pack_start(GTK_BOX(ghidgui->menu_hbox), ghidgui->menubar_toolbar_vbox, FALSE, FALSE, 0);
 
 	/* Build layer menus */
-	ghidgui->layer_selector = ghid_layer_selector_new();
+	ghidgui->layer_selector = pcb_gtk_layer_selector_new();
 	make_layer_buttons(ghidgui->layer_selector);
 	make_virtual_layer_buttons(ghidgui->layer_selector);
 	g_signal_connect(G_OBJECT(ghidgui->layer_selector), "select_layer", G_CALLBACK(layer_selector_select_callback), NULL);
@@ -1105,7 +1018,7 @@ static void ghid_build_pcb_top_window(void)
 	ghidgui->position_hbox = gtk_hbox_new(FALSE, 0);
 	gtk_box_pack_end(GTK_BOX(ghidgui->top_hbox), ghidgui->position_hbox, FALSE, FALSE, 0);
 
-	make_cursor_position_labels(ghidgui->position_hbox, port);
+	make_cursor_position_labels(ghidgui->position_hbox, &ghidgui->cps);
 
 	hbox_middle = gtk_hbox_new(FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(vbox_main), hbox_middle, TRUE, TRUE, 0);
@@ -1134,8 +1047,8 @@ static void ghid_build_pcb_top_window(void)
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
 	hbox = gtk_hbox_new(FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 1);
-	ghidgui->route_style_selector = ghid_route_style_selector_new();
-	make_route_style_buttons(GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector));
+	ghidgui->route_style_selector = pcb_gtk_route_style_new();
+	make_route_style_buttons(GHID_ROUTE_STYLE(ghidgui->route_style_selector));
 	gtk_box_pack_start(GTK_BOX(hbox), ghidgui->route_style_selector, FALSE, FALSE, 0);
 
 	ghidgui->vbox_middle = gtk_vbox_new(FALSE, 0);
@@ -1149,6 +1062,9 @@ static void ghid_build_pcb_top_window(void)
 	gport->drawing_area = gtk_drawing_area_new();
 	ghid_init_drawing_widget(gport->drawing_area, gport);
 
+	gport->mouse.drawing_area = gport->drawing_area;
+	gport->mouse.top_window = gport->top_window;
+
 	gtk_widget_add_events(gport->drawing_area, GDK_EXPOSURE_MASK
 												| GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
 												| GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK
@@ -1190,10 +1106,10 @@ static void ghid_build_pcb_top_window(void)
 	ghidgui->status_line_hbox = gtk_hbox_new(FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(ghidgui->vbox_middle), ghidgui->status_line_hbox, FALSE, FALSE, 0);
 
-	label = gtk_label_new("");
-	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
-	gtk_box_pack_start(GTK_BOX(ghidgui->status_line_hbox), label, FALSE, FALSE, 0);
+	label = pcb_gtk_build_status_line_label();
+
 	ghidgui->status_line_label = label;
+	gtk_box_pack_start(GTK_BOX(ghidgui->status_line_hbox), label, FALSE, FALSE, 0);
 
 	/* Depending on user setting, the command_combo_box may get packed into
 	   |  the status_line_hbox, but it will happen on demand the first time
@@ -1246,14 +1162,11 @@ static gulong button_press_handler, button_release_handler, key_press_handler, k
 
 void ghid_interface_input_signals_connect(void)
 {
-	button_press_handler =
-		g_signal_connect(G_OBJECT(gport->drawing_area), "button_press_event", G_CALLBACK(ghid_port_button_press_cb), NULL);
-
-	button_release_handler =
-		g_signal_connect(G_OBJECT(gport->drawing_area), "button_release_event", G_CALLBACK(ghid_port_button_release_cb), NULL);
+	button_press_handler = g_signal_connect(G_OBJECT(gport->drawing_area), "button_press_event", G_CALLBACK(ghid_port_button_press_cb), &gport->mouse);
+	button_release_handler = g_signal_connect(G_OBJECT(gport->drawing_area), "button_release_event", G_CALLBACK(ghid_port_button_release_cb), &gport->mouse);
 
 	key_press_handler =
-		g_signal_connect(G_OBJECT(gport->drawing_area), "key_press_event", G_CALLBACK(ghid_port_key_press_cb), NULL);
+		g_signal_connect(G_OBJECT(gport->drawing_area), "key_press_event", G_CALLBACK(ghid_port_key_press_cb), &ghid_port.view);
 
 	key_release_handler =
 		g_signal_connect(G_OBJECT(gport->drawing_area), "key_release_event", G_CALLBACK(ghid_port_key_release_cb), NULL);
@@ -1480,7 +1393,8 @@ static unsigned short int ghid_translate_key(const char *desc, int len)
 {
 	guint key;
 
-	if (pcb_strcasecmp(desc, "enter") == 0) desc = "Return";
+	if (pcb_strcasecmp(desc, "enter") == 0)
+		desc = "Return";
 
 	key = gdk_keyval_from_name(desc);
 	if (key > 0xffff) {
@@ -1496,7 +1410,7 @@ int ghid_key_name(unsigned short int key_char, char *out, int out_len)
 	if (name == NULL)
 		return -1;
 	strncpy(out, name, out_len);
-	out[out_len-1] = '\0';
+	out[out_len - 1] = '\0';
 	return 0;
 }
 
@@ -1517,7 +1431,7 @@ void ghid_do_export(pcb_hid_attr_val_t * options)
 	 */
 	ghid_layer_buttons_update();
 	ghid_main_menu_install_route_style_selector
-		(GHID_MAIN_MENU(ghidgui->menu_bar), GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector));
+		(GHID_MAIN_MENU(ghidgui->menu_bar), GHID_ROUTE_STYLE(ghidgui->route_style_selector));
 
 	if (conf_hid_gtk.plugins.hid_gtk.listen)
 		ghid_create_listener();
@@ -1531,7 +1445,7 @@ void ghid_do_export(pcb_hid_attr_val_t * options)
 	gtkhid_end();
 }
 
-void ghid_do_exit(pcb_hid_t *hid)
+void ghid_do_exit(pcb_hid_t * hid)
 {
 	gtk_main_quit();
 }
@@ -1563,9 +1477,8 @@ void ghid_LayersChanged(void *user_data, int argc, pcb_event_arg_t argv[])
 	if (!ghidgui || !ghidgui->menu_bar || PCB == NULL)
 		return;
 
-	ghid_config_groups_changed();
 	ghid_layer_buttons_update();
-	ghid_layer_selector_show_layers(GHID_LAYER_SELECTOR(ghidgui->layer_selector), get_layer_visible_cb);
+	pcb_gtk_layer_selector_show_layers(GHID_LAYER_SELECTOR(ghidgui->layer_selector), get_layer_visible_cb);
 
 	/* FIXME - if a layer is moved it should retain its color.  But layers
 	   |  currently can't do that because color info is not saved in the
@@ -1623,7 +1536,7 @@ static int ToggleView(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 		l = LAYER_BUTTON_FARSIDE;
 	else {
 		l = -1;
-		for (i = 0; i < pcb_max_copper_layer + 2; i++) {
+		for (i = 0; i < pcb_max_layer; i++) {
 			if (strcmp(argv[0], PCB->Data->Layer[i].Name) == 0) {
 				l = i;
 				break;
@@ -1637,7 +1550,7 @@ static int ToggleView(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 	/* Now that we've figured out which toggle button ought to control
 	 * this layer, simply hit the button and let the pre-existing code deal
 	 */
-	ghid_layer_selector_toggle_layer(GHID_LAYER_SELECTOR(ghidgui->layer_selector), l);
+	pcb_gtk_layer_selector_toggle_layer(GHID_LAYER_SELECTOR(ghidgui->layer_selector), l);
 	return 0;
 }
 
@@ -1672,7 +1585,7 @@ static int SelectLayer(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y
 	/* Now that we've figured out which radio button ought to select
 	 * this layer, simply hit the button and let the pre-existing code deal
 	 */
-	ghid_layer_selector_select_layer(GHID_LAYER_SELECTOR(ghidgui->layer_selector), newl);
+	pcb_gtk_layer_selector_select_layer(GHID_LAYER_SELECTOR(ghidgui->layer_selector), newl);
 
 	return 0;
 }
@@ -1688,7 +1601,7 @@ pcb_hid_action_t gtk_topwindow_action_list[] = {
 
 PCB_REGISTER_ACTIONS(gtk_topwindow_action_list, ghid_cookie)
 
-static GtkWidget *ghid_load_menus(void)
+		 static GtkWidget *ghid_load_menus(void)
 {
 	const lht_node_t *mr;
 	GtkWidget *menu_bar = NULL;
@@ -1710,7 +1623,7 @@ static GtkWidget *ghid_load_menus(void)
 	if (mr != NULL) {
 		if (mr->type == LHT_LIST) {
 			lht_node_t *n;
-			for(n = mr->data.list.first; n != NULL; n = n->next)
+			for (n = mr->data.list.first; n != NULL; n = n->next)
 				ghid_main_menu_add_popup_node(GHID_MAIN_MENU(menu_bar), n);
 		}
 		else
@@ -1745,7 +1658,7 @@ static int AdjustStyle(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y
 	if (argc > 1)
 		PCB_AFAIL(adjuststyle);
 
-	ghid_route_style_selector_edit_dialog(GHID_ROUTE_STYLE_SELECTOR(ghidgui->route_style_selector));
+  pcb_gtk_route_style_edit_dialog(GHID_ROUTE_STYLE(ghidgui->route_style_selector));
 	return 0;
 }
 
@@ -1769,6 +1682,8 @@ static int EditLayerGroups(int argc, const char **argv, pcb_coord_t x, pcb_coord
 	if (argc != 0)
 		PCB_AFAIL(editlayergroups);
 
+#warning TODO: extend the DoWindows action so it opens the right preferences tab
+
 	pcb_hid_actionl("DoWindows", "Preferences", NULL);
 
 	return 0;
diff --git a/src_plugins/hid_gtk/gui-utils.c b/src_plugins/hid_gtk/gui-utils.c
deleted file mode 100644
index 70c1c1a..0000000
--- a/src_plugins/hid_gtk/gui-utils.c
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 1994,1995,1996 Thomas Nau
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* This module, gui-utils.c, was written by Bill Wilson and the functions
- * here are Copyright (C) 2004 by Bill Wilson.  These functions are utility
- * functions which are taken from my other GPL'd projects gkrellm and
- * gstocks and are copied here for the Gtk PCB port.
- */
-
-#include "config.h"
-#include "conf_core.h"
-
-#include "gui.h"
-#include <gdk/gdkkeysyms.h>
-
-/* Not a gui function, but no better place to put it...
- */
-gboolean dup_string(gchar ** dst, const gchar * src)
-{
-	if ((dst == NULL) || ((*dst == NULL) && (src == NULL)))
-		return FALSE;
-	if (*dst) {
-		if (src && !strcmp(*dst, src))
-			return FALSE;
-		g_free(*dst);
-	}
-	*dst = g_strdup(src);
-	return TRUE;
-}
-
-void free_glist_and_data(GList ** list_head)
-{
-	GList *list;
-
-	if (*list_head == NULL)
-		return;
-	for (list = *list_head; list; list = list->next)
-		if (list->data)
-			g_free(list->data);
-	g_list_free(*list_head);
-	*list_head = NULL;
-}
-
-
-gboolean ghid_is_modifier_key_sym(gint ksym)
-{
-	if (ksym == GDK_Shift_R || ksym == GDK_Shift_L || ksym == GDK_Control_R || ksym == GDK_Control_L)
-		return TRUE;
-	return FALSE;
-}
-
-
-ModifierKeysState ghid_modifier_keys_state(GdkModifierType * state)
-{
-	GdkModifierType mask;
-	ModifierKeysState mk;
-	gboolean shift, control, mod1;
-	GHidPort *out = &ghid_port;
-
-	if (!state)
-		gdk_window_get_pointer(gtk_widget_get_window(out->drawing_area), NULL, NULL, &mask);
-	else
-		mask = *state;
-
-	shift = (mask & GDK_SHIFT_MASK);
-	control = (mask & GDK_CONTROL_MASK);
-	mod1 = (mask & GDK_MOD1_MASK);
-
-	if (shift && !control && !mod1)
-		mk = SHIFT_PRESSED;
-	else if (!shift && control && !mod1)
-		mk = CONTROL_PRESSED;
-	else if (!shift && !control && mod1)
-		mk = MOD1_PRESSED;
-	else if (shift && control && !mod1)
-		mk = SHIFT_CONTROL_PRESSED;
-	else if (shift && !control && mod1)
-		mk = SHIFT_MOD1_PRESSED;
-	else if (!shift && control && mod1)
-		mk = CONTROL_MOD1_PRESSED;
-	else if (shift && control && mod1)
-		mk = SHIFT_CONTROL_MOD1_PRESSED;
-	else
-		mk = NONE_PRESSED;
-
-	return mk;
-}
-
-ButtonState ghid_button_state(GdkModifierType * state)
-{
-	GdkModifierType mask;
-	ButtonState bs;
-	gboolean button1, button2, button3;
-	GHidPort *out = &ghid_port;
-
-	if (!state) {
-		gdk_window_get_pointer(gtk_widget_get_window(out->drawing_area), NULL, NULL, &mask);
-	}
-	else
-		mask = *state;
-
-	extern GdkModifierType ghid_glob_mask;
-	ghid_glob_mask = mask;
-
-	button1 = (mask & GDK_BUTTON1_MASK);
-	button2 = (mask & GDK_BUTTON2_MASK);
-	button3 = (mask & GDK_BUTTON3_MASK);
-
-	if (button1)
-		bs = BUTTON1_PRESSED;
-	else if (button2)
-		bs = BUTTON2_PRESSED;
-	else if (button3)
-		bs = BUTTON3_PRESSED;
-	else
-		bs = NO_BUTTON_PRESSED;
-
-	return bs;
-}
-
-void ghid_draw_area_update(GHidPort * port, GdkRectangle * rect)
-{
-	gdk_window_invalidate_rect(gtk_widget_get_window(port->drawing_area), rect, FALSE);
-}
-
-
-const gchar *ghid_get_color_name(GdkColor * color)
-{
-	static char tmp[16];
-
-	if (!color)
-		return "#000000";
-
-	sprintf(tmp, "#%2.2x%2.2x%2.2x", (color->red >> 8) & 0xff, (color->green >> 8) & 0xff, (color->blue >> 8) & 0xff);
-	return tmp;
-}
-
-void ghid_map_color_string(const char *color_string, GdkColor * color)
-{
-	static GdkColormap *colormap = NULL;
-	GHidPort *out = &ghid_port;
-
-	if (!color || !out->top_window)
-		return;
-	if (colormap == NULL)
-		colormap = gtk_widget_get_colormap(out->top_window);
-	if (color->red || color->green || color->blue)
-		gdk_colormap_free_colors(colormap, color, 1);
-	gdk_color_parse(color_string, color);
-	gdk_color_alloc(colormap, color);
-}
-
-
-const gchar *ghid_entry_get_text(GtkWidget * entry)
-{
-	const gchar *s = "";
-
-	if (entry)
-		s = gtk_entry_get_text(GTK_ENTRY(entry));
-	while (*s == ' ' || *s == '\t')
-		++s;
-	return s;
-}
-
-
-
-void
-ghid_check_button_connected(GtkWidget * box,
-														GtkWidget ** button,
-														gboolean active,
-														gboolean pack_start,
-														gboolean expand,
-														gboolean fill,
-														gint pad, void (*cb_func) (GtkToggleButton *, gpointer), gpointer data, const gchar * string)
-{
-	GtkWidget *b;
-
-	if (string != NULL)
-		b = gtk_check_button_new_with_label(string);
-	else
-		b = gtk_check_button_new();
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b), active);
-	if (box && pack_start)
-		gtk_box_pack_start(GTK_BOX(box), b, expand, fill, pad);
-	else if (box && !pack_start)
-		gtk_box_pack_end(GTK_BOX(box), b, expand, fill, pad);
-
-	if (cb_func)
-		g_signal_connect(b, "clicked", G_CALLBACK(cb_func), data);
-	if (button)
-		*button = b;
-}
-
-void
-ghid_coord_entry(GtkWidget * box, GtkWidget ** coord_entry, pcb_coord_t value,
-								 pcb_coord_t low, pcb_coord_t high, enum ce_step_size step_size, const pcb_unit_t *u,
-								 gint width, void (*cb_func) (GHidCoordEntry *, gpointer), gpointer data, const gchar * string_pre, const gchar * string_post)
-{
-	GtkWidget *hbox = NULL, *label, *entry_widget;
-	GHidCoordEntry *entry;
-
-	if (u == NULL)
-		u = conf_core.editor.grid_unit;
-
-	if ((string_pre || string_post) && box) {
-		hbox = gtk_hbox_new(FALSE, 0);
-		gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 2);
-		box = hbox;
-	}
-
-	entry_widget = ghid_coord_entry_new(low, high, value, u, step_size);
-	if (coord_entry)
-		*coord_entry = entry_widget;
-	if (width > 0)
-		gtk_widget_set_size_request(entry_widget, width, -1);
-	entry = GHID_COORD_ENTRY(entry_widget);
-	if (data == NULL)
-		data = (gpointer) entry;
-	if (cb_func)
-		g_signal_connect(G_OBJECT(entry_widget), "value_changed", G_CALLBACK(cb_func), data);
-	if (box) {
-		if (string_pre) {
-			label = gtk_label_new(string_pre);
-			gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 2);
-		}
-		gtk_box_pack_start(GTK_BOX(box), entry_widget, FALSE, FALSE, 2);
-		if (string_post) {
-			label = gtk_label_new(string_post);
-			gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-			gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 2);
-		}
-	}
-}
-
-void
-ghid_spin_button(GtkWidget * box, GtkWidget ** spin_button, gfloat value,
-								 gfloat low, gfloat high, gfloat step0, gfloat step1,
-								 gint digits, gint width,
-								 void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, const gchar * string)
-{
-	GtkWidget *hbox = NULL, *label, *spin_but;
-	GtkSpinButton *spin;
-	GtkAdjustment *adj;
-
-	if (string && box) {
-		hbox = gtk_hbox_new(FALSE, 0);
-		gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 2);
-		box = hbox;
-	}
-	adj = (GtkAdjustment *) gtk_adjustment_new(value, low, high, step0, step1, 0.0);
-	spin_but = gtk_spin_button_new(adj, 0.5, digits);
-	if (spin_button)
-		*spin_button = spin_but;
-	if (width > 0)
-		gtk_widget_set_size_request(spin_but, width, -1);
-	spin = GTK_SPIN_BUTTON(spin_but);
-	gtk_spin_button_set_numeric(spin, TRUE);
-	if (data == NULL)
-		data = (gpointer) spin;
-	if (cb_func)
-		g_signal_connect(G_OBJECT(spin_but), "value_changed", G_CALLBACK(cb_func), data);
-	if (box) {
-		if (right_align && string) {
-			label = gtk_label_new(string);
-			gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-			gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 2);
-		}
-		gtk_box_pack_start(GTK_BOX(box), spin_but, FALSE, FALSE, 2);
-		if (!right_align && string) {
-			label = gtk_label_new(string);
-			gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-			gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 2);
-		}
-	}
-}
-
-void
-ghid_table_coord_entry(GtkWidget * table, gint row, gint column,
-											 GtkWidget ** coord_entry, pcb_coord_t value,
-											 pcb_coord_t low, pcb_coord_t high, enum ce_step_size step_size,
-											 gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
-											 gpointer data, gboolean right_align, const gchar * string)
-{
-	GtkWidget *label, *entry_widget;
-	GHidCoordEntry *entry;
-
-	if (!table)
-		return;
-
-	entry_widget = ghid_coord_entry_new(low, high, value, conf_core.editor.grid_unit, step_size);
-	if (coord_entry)
-		*coord_entry = entry_widget;
-	if (width > 0)
-		gtk_widget_set_size_request(entry_widget, width, -1);
-	entry = GHID_COORD_ENTRY(entry_widget);
-	if (data == NULL)
-		data = (gpointer) entry;
-	if (cb_func)
-		g_signal_connect(G_OBJECT(entry), "value_changed", G_CALLBACK(cb_func), data);
-
-	if (right_align) {
-		gtk_table_attach_defaults(GTK_TABLE(table), entry_widget, column + 1, column + 2, row, row + 1);
-		if (string) {
-			label = gtk_label_new(string);
-			gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-			gtk_table_attach_defaults(GTK_TABLE(table), label, column, column + 1, row, row + 1);
-		}
-	}
-	else {
-		gtk_table_attach_defaults(GTK_TABLE(table), entry_widget, column, column + 1, row, row + 1);
-		if (string) {
-			label = gtk_label_new(string);
-			gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-			gtk_table_attach_defaults(GTK_TABLE(table), label, column + 1, column + 2, row, row + 1);
-		}
-	}
-}
-
-
-void
-ghid_table_spin_button(GtkWidget * table, gint row, gint column,
-											 GtkWidget ** spin_button, gfloat value,
-											 gfloat low, gfloat high, gfloat step0, gfloat step1,
-											 gint digits, gint width,
-											 void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, const gchar * string)
-{
-	GtkWidget *label, *spin_but;
-	GtkSpinButton *spin;
-	GtkAdjustment *adj;
-
-	if (!table)
-		return;
-
-	adj = (GtkAdjustment *) gtk_adjustment_new(value, low, high, step0, step1, 0.0);
-	spin_but = gtk_spin_button_new(adj, 0.5, digits);
-
-	if (spin_button)
-		*spin_button = spin_but;
-	if (width > 0)
-		gtk_widget_set_size_request(spin_but, width, -1);
-	spin = GTK_SPIN_BUTTON(spin_but);
-	gtk_spin_button_set_numeric(spin, TRUE);
-	if (data == NULL)
-		data = (gpointer) spin;
-	if (cb_func)
-		g_signal_connect(G_OBJECT(spin_but), "value_changed", G_CALLBACK(cb_func), data);
-
-	if (right_align) {
-		gtk_table_attach_defaults(GTK_TABLE(table), spin_but, column + 1, column + 2, row, row + 1);
-		if (string) {
-			label = gtk_label_new(string);
-			gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-			gtk_table_attach_defaults(GTK_TABLE(table), label, column, column + 1, row, row + 1);
-		}
-	}
-	else {
-		gtk_table_attach_defaults(GTK_TABLE(table), spin_but, column, column + 1, row, row + 1);
-		if (string) {
-			label = gtk_label_new(string);
-			gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-			gtk_table_attach_defaults(GTK_TABLE(table), label, column + 1, column + 2, row, row + 1);
-		}
-	}
-}
-
-void
-ghid_range_control(GtkWidget * box, GtkWidget ** scale_res,
-									 gboolean horizontal, GtkPositionType pos,
-									 gboolean set_draw_value, gint digits, gboolean pack_start,
-									 gboolean expand, gboolean fill, guint pad, gfloat value,
-									 gfloat low, gfloat high, gfloat step0, gfloat step1, void (*cb_func) (), gpointer data)
-{
-	GtkWidget *scale;
-	GtkAdjustment *adj;
-
-	adj = (GtkAdjustment *) gtk_adjustment_new(value, low, high, step0, step1, 0.0);
-
-	if (horizontal)
-		scale = gtk_hscale_new(GTK_ADJUSTMENT(adj));
-	else
-		scale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
-	gtk_scale_set_value_pos(GTK_SCALE(scale), pos);
-	gtk_scale_set_draw_value(GTK_SCALE(scale), set_draw_value);
-	gtk_scale_set_digits(GTK_SCALE(scale), digits);
-
-	/* pcb_increments_t don't make sense, use -1,1 because that does closest to
-	   |  what I want: scroll down decrements slider value.
-	 */
-	gtk_range_set_increments(GTK_RANGE(scale), -1, 1);
-
-	if (pack_start)
-		gtk_box_pack_start(GTK_BOX(box), scale, expand, fill, pad);
-	else
-		gtk_box_pack_end(GTK_BOX(box), scale, expand, fill, pad);
-
-	if (data == NULL)
-		data = (gpointer) adj;
-	if (cb_func)
-		g_signal_connect(G_OBJECT(adj), "value_changed", G_CALLBACK(cb_func), data);
-	if (scale_res)
-		*scale_res = scale;
-}
-
-GtkWidget *ghid_scrolled_vbox(GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy)
-{
-	GtkWidget *scrolled, *vbox;
-
-	scrolled = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), h_policy, v_policy);
-	gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0);
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), vbox);
-	if (scr)
-		*scr = scrolled;
-	return vbox;
-}
-
-/* frame_border_width - border around outside of frame.
-   |  vbox_pad - pad between widgets to be packed in returned vbox.
-   |  vbox_border_width - border between returned vbox and frame.
-*/
-GtkWidget *ghid_framed_vbox(GtkWidget * box, gchar * label, gint frame_border_width,
-														gboolean frame_expand, gint vbox_pad, gint vbox_border_width)
-{
-	GtkWidget *frame;
-	GtkWidget *vbox;
-
-	frame = gtk_frame_new(label);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), frame_border_width);
-	gtk_box_pack_start(GTK_BOX(box), frame, frame_expand, frame_expand, 0);
-	vbox = gtk_vbox_new(FALSE, vbox_pad);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), vbox_border_width);
-	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	return vbox;
-}
-
-GtkWidget *ghid_framed_vbox_end(GtkWidget * box, gchar * label, gint frame_border_width,
-																gboolean frame_expand, gint vbox_pad, gint vbox_border_width)
-{
-	GtkWidget *frame;
-	GtkWidget *vbox;
-
-	frame = gtk_frame_new(label);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), frame_border_width);
-	gtk_box_pack_end(GTK_BOX(box), frame, frame_expand, frame_expand, 0);
-	vbox = gtk_vbox_new(FALSE, vbox_pad);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), vbox_border_width);
-	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	return vbox;
-}
-
-GtkWidget *ghid_category_vbox(GtkWidget * box, const gchar * category_header,
-															gint header_pad, gint box_pad, gboolean pack_start, gboolean bottom_pad)
-{
-	GtkWidget *vbox, *vbox1, *hbox, *label;
-	gchar *s;
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	if (pack_start)
-		gtk_box_pack_start(GTK_BOX(box), vbox, FALSE, FALSE, 0);
-	else
-		gtk_box_pack_end(GTK_BOX(box), vbox, FALSE, FALSE, 0);
-
-	if (category_header) {
-		label = gtk_label_new(NULL);
-		s = g_strconcat("<span weight=\"bold\">", category_header, "</span>", NULL);
-		gtk_label_set_markup(GTK_LABEL(label), s);
-		gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, header_pad);
-		g_free(s);
-	}
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-	label = gtk_label_new("     ");
-	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-	vbox1 = gtk_vbox_new(FALSE, box_pad);
-	gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0);
-
-	if (bottom_pad) {
-		label = gtk_label_new("");
-		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-	}
-	return vbox1;
-}
-
-GtkTreeSelection *ghid_scrolled_selection(GtkTreeView * treeview, GtkWidget * box,
-																					GtkSelectionMode s_mode,
-																					GtkPolicyType h_policy, GtkPolicyType v_policy,
-																					void (*func_cb) (GtkTreeSelection *, gpointer), gpointer data)
-{
-	GtkTreeSelection *selection;
-	GtkWidget *scrolled;
-
-	if (!box || !treeview)
-		return NULL;
-
-	scrolled = gtk_scrolled_window_new(NULL, NULL);
-	gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0);
-	gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(treeview));
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), h_policy, v_policy);
-	selection = gtk_tree_view_get_selection(treeview);
-	gtk_tree_selection_set_mode(selection, s_mode);
-	if (func_cb)
-		g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(func_cb), data);
-	return selection;
-}
-
-GtkWidget *ghid_notebook_page(GtkWidget * tabs, const char *name, gint pad, gint border)
-{
-	GtkWidget *label;
-	GtkWidget *vbox;
-
-	vbox = gtk_vbox_new(FALSE, pad);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), border);
-
-	label = gtk_label_new(name);
-	gtk_notebook_append_page(GTK_NOTEBOOK(tabs), vbox, label);
-
-	return vbox;
-}
-
-GtkWidget *ghid_framed_notebook_page(GtkWidget * tabs, const char *name, gint border,
-																		 gint frame_border, gint vbox_pad, gint vbox_border)
-{
-	GtkWidget *vbox;
-
-	vbox = ghid_notebook_page(tabs, name, 0, border);
-	vbox = ghid_framed_vbox(vbox, NULL, frame_border, TRUE, vbox_pad, vbox_border);
-	return vbox;
-}
-
-void ghid_dialog_report(const gchar * title, const gchar * message)
-{
-	GtkWidget *top_win;
-	GtkWidget *dialog;
-	GtkWidget *content_area;
-	GtkWidget *scrolled;
-	GtkWidget *vbox, *vbox1;
-	GtkWidget *label;
-	const gchar *s;
-	gint nlines;
-	GHidPort *out = &ghid_port;
-
-	if (!message)
-		return;
-	top_win = out->top_window;
-	dialog = gtk_dialog_new_with_buttons(title ? title : "PCB",
-																			 GTK_WINDOW(top_win),
-																			 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL);
-	g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog));
-	gtk_window_set_wmclass(GTK_WINDOW(dialog), "PCB_Dialog", "PCB");
-
-	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
-	gtk_box_pack_start(GTK_BOX(content_area), vbox, FALSE, FALSE, 0);
-
-	label = gtk_label_new(message);
-	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
-
-	for (nlines = 0, s = message; *s; ++s)
-		if (*s == '\n')
-			++nlines;
-	if (nlines > 20) {
-		vbox1 = ghid_scrolled_vbox(vbox, &scrolled, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-		gtk_widget_set_size_request(scrolled, -1, 300);
-		gtk_box_pack_start(GTK_BOX(vbox1), label, FALSE, FALSE, 0);
-	}
-	else
-		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-	gtk_widget_show_all(dialog);
-}
-
-
-void ghid_label_set_markup(GtkWidget * label, const gchar * text)
-{
-	if (label)
-		gtk_label_set_markup(GTK_LABEL(label), text ? text : "");
-}
-
-
-static void text_view_append(GtkWidget * view, const gchar * s)
-{
-	GtkTextIter iter;
-	GtkTextBuffer *buffer;
-	GtkTextMark *mark;
-
-	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
-	gtk_text_buffer_get_end_iter(buffer, &iter);
-	/* gtk_text_iter_forward_to_end(&iter); */
-
-	if (strncmp(s, "<b>", 3) == 0)
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "bold", NULL);
-	else if (strncmp(s, "<i>", 3) == 0)
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "italic", NULL);
-	else if (strncmp(s, "<h>", 3) == 0)
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "heading", NULL);
-	else if (strncmp(s, "<c>", 3) == 0)
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "center", NULL);
-	else if (strncmp(s, "<R>", 3) == 0)
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "red", NULL);
-	else if (strncmp(s, "<G>", 3) == 0)
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "green", NULL);
-	else if (strncmp(s, "<B>", 3) == 0)
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "blue", NULL);
-	else if (strncmp(s, "<ul>", 4) == 0)
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 4, -1, "underline", NULL);
-	else
-		gtk_text_buffer_insert(buffer, &iter, s, -1);
-
-	mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, FALSE);
-	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(view), mark, 0, TRUE, 0.0, 1.0);
-	gtk_text_buffer_delete_mark(buffer, mark);
-}
-
-void ghid_text_view_append(GtkWidget * view, const gchar * string)
-{
-	static gchar *tag;
-	const gchar *s;
-
-	s = string;
-	if (*s == '<' && ((*(s + 2) == '>' && !*(s + 3)) || (*(s + 3) == '>' && !*(s + 4)))) {
-		tag = g_strdup(s);
-		return;
-	}
-
-	if (tag) {
-		char *concatenation;
-		concatenation = g_strconcat(tag, string, NULL);
-		text_view_append(view, concatenation);
-		g_free(concatenation);
-		g_free(tag);
-		tag = NULL;
-	}
-	else
-		text_view_append(view, string);
-}
-
-void ghid_text_view_append_strings(GtkWidget * view, const gchar ** string, gint n_strings)
-{
-	gchar *tag = NULL;
-	const gchar *s;
-	gint i;
-
-	for (i = 0; i < n_strings; ++i) {
-		s = string[i];
-		if (*s == '<' && ((*(s + 2) == '>' && !*(s + 3))
-											|| (*(s + 3) == '>' && !*(s + 4)))) {
-			tag = g_strdup(s);
-			continue;
-		}
-#if defined(ENABLE_NLS)
-		s = gettext(string[i]);
-#else
-		s = string[i];
-#endif
-		if (tag) {
-			char *concatenation;
-			concatenation = g_strconcat(tag, s, NULL);
-			text_view_append(view, concatenation);
-			g_free(concatenation);
-			g_free(tag);
-			tag = NULL;
-		}
-		else
-			text_view_append(view, s);
-	}
-}
-
-
-GtkWidget *ghid_scrolled_text_view(GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy)
-{
-	GtkWidget *scrolled, *view;
-	GtkTextBuffer *buffer;
-
-	scrolled = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), h_policy, v_policy);
-	gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0);
-
-	view = gtk_text_view_new();
-	gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE);
-	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
-	gtk_text_buffer_create_tag(buffer, "heading", "weight", PANGO_WEIGHT_BOLD, "size", 14 * PANGO_SCALE, NULL);
-	gtk_text_buffer_create_tag(buffer, "italic", "style", PANGO_STYLE_ITALIC, NULL);
-	gtk_text_buffer_create_tag(buffer, "bold", "weight", PANGO_WEIGHT_BOLD, NULL);
-	gtk_text_buffer_create_tag(buffer, "center", "justification", GTK_JUSTIFY_CENTER, NULL);
-	gtk_text_buffer_create_tag(buffer, "underline", "underline", PANGO_UNDERLINE_SINGLE, NULL);
-	gtk_text_buffer_create_tag(buffer, "red", "foreground", "#aa0000", NULL);
-	gtk_text_buffer_create_tag(buffer, "green", "foreground", "#00aa00", NULL);
-	gtk_text_buffer_create_tag(buffer, "blue", "foreground", "#0000aa", NULL);
-
-	gtk_container_add(GTK_CONTAINER(scrolled), view);
-	if (scr)
-		*scr = scrolled;
-	return view;
-}
-
-
-/* If src is not utf8, *dst is converted to utf8.
- */
-gboolean utf8_dup_string(gchar ** dst_utf8, const gchar * src)
-{
-	if (!dst_utf8 || (!*dst_utf8 && !src))
-		return FALSE;
-	if (*dst_utf8) {
-		if (src && !strcmp(*dst_utf8, src))
-			return FALSE;
-		g_free(*dst_utf8);
-	}
-	if (src) {
-		if (g_utf8_validate(src, -1, NULL))
-			*dst_utf8 = g_strdup(src);
-		else {
-			*dst_utf8 = g_locale_to_utf8(src, -1, NULL, NULL, NULL);
-			if (!*dst_utf8)
-				*dst_utf8 = g_strdup(src);
-		}
-	}
-	else
-		*dst_utf8 = NULL;
-
-	return TRUE;
-}
diff --git a/src_plugins/hid_gtk/gui.h b/src_plugins/hid_gtk/gui.h
index db54deb..2409bb9 100644
--- a/src_plugins/hid_gtk/gui.h
+++ b/src_plugins/hid_gtk/gui.h
@@ -34,16 +34,21 @@
 #include "data.h"
 
 #include <gtk/gtk.h>
-#include "ghid-coord-entry.h"
 #include "ghid-main-menu.h"
-#include "gui-pinout-preview.h"
-#include "ghid-propedit.h"
 #include "conf_core.h"
 #include "event.h"
 #include "compat_misc.h"
+#include "colors.h"
 
 #include "hid_gtk_conf.h"
 
+/* needed for a type in GhidGui - DO NOT ADD .h files that are not requred for the structs! */
+#include "../src_plugins/lib_gtk_common/bu_cursor_pos.h"
+#include "../src_plugins/lib_gtk_common/ui_zoompan.h"
+#include "../src_plugins/lib_gtk_common/dlg_propedit.h"
+#include "../src_plugins/lib_gtk_common/in_mouse.h"
+
+
 	/* Silk and rats lines are the two additional selectable to draw on.
 	   |  gui code in gui-top-window.c and group code in misc.c must agree
 	   |  on what layer is what!
@@ -59,23 +64,6 @@
 #define LAYER_BUTTON_UI			(PCB_MAX_LAYER + 6)
 #define N_LAYER_BUTTONS				(PCB_MAX_LAYER + 7)
 
-	/* Go from from the grid units in use (millimeters or mils) to PCB units
-	   |  and back again.
-	   |  PCB keeps values internally higher precision, but gui
-	   |  widgets (spin buttons, labels, etc) need mils or millimeters.
-	 */
-#define	FROM_PCB_UNITS(v)	pcb_coord_to_unit(conf_core.editor.grid_unit, v)
-#define	TO_PCB_UNITS(v)		pcb_unit_to_coord(conf_core.editor.grid_unit, v)
-
-#define SIDE_X(x)         ((conf_core.editor.view.flip_x ? PCB->MaxWidth - (x) : (x)))
-#define SIDE_Y(y)         ((conf_core.editor.view.flip_y ? PCB->MaxHeight - (y) : (y)))
-
-#define	DRAW_X(x)         (gint)((SIDE_X(x) - gport->view.x0) / gport->view.coord_per_px)
-#define	DRAW_Y(y)         (gint)((SIDE_Y(y) - gport->view.y0) / gport->view.coord_per_px)
-
-#define	EVENT_TO_PCB_X(x) SIDE_X((gint)((x) * gport->view.coord_per_px + gport->view.x0))
-#define	EVENT_TO_PCB_Y(y) SIDE_Y((gint)((y) * gport->view.coord_per_px + gport->view.y0))
-
 /*
  * Used to intercept "special" hotkeys that gtk doesn't usually pass
  * on to the menu hotkeys.  We catch them and put them back where we
@@ -94,14 +82,13 @@
 typedef struct {
 	GtkActionGroup *main_actions, *change_selected_actions, *displayed_name_actions;
 
-	  GtkWidget
-		* status_line_label,
-		*cursor_position_relative_label, *cursor_position_absolute_label, *grid_units_label, *status_line_hbox, *command_combo_box;
+	pcb_gtk_cursor_pos_t cps;
+
+	GtkWidget *status_line_label, *status_line_hbox, *command_combo_box;
 	GtkEntry *command_entry;
 
 	GtkWidget *top_hbox, *top_bar_background, *menu_hbox, *position_hbox, *menubar_toolbar_vbox, *mode_buttons_frame;
 	GtkWidget *left_toolbar;
-	GtkWidget *grid_units_button;
 	GtkWidget *menu_bar, *layer_selector, *route_style_selector;
 	GtkWidget *mode_toolbar;
 	GtkWidget *mode_toolbar_vbox;
@@ -124,24 +111,12 @@ typedef struct {
 
 	gint settings_mode;
 
-	ghid_propedit_dialog_t propedit_dlg;
+	pcb_gtk_dlg_propedit_t propedit_dlg;
 	GtkWidget *propedit_widget;
-	const char *(*propedit_query)(void *pe, const char *cmd, const char *key, const char *val, int idx);
-	void *propedit_pe;
 } GhidGui;
 
 extern GhidGui _ghidgui, *ghidgui;
 
-typedef struct {
-	double coord_per_px;					/* Zoom level described as PCB units per screen pixel */
-
-	pcb_coord_t x0;
-	pcb_coord_t y0;
-	pcb_coord_t width;
-	pcb_coord_t height;
-
-} view_data;
-
 	/* The output viewport
 	 */
 typedef struct {
@@ -149,7 +124,6 @@ typedef struct {
 	 *drawing_area;								/* and its drawing area */
 	GdkPixmap *pixmap, *mask;
 	GdkDrawable *drawable;				/* Current drawable for drawing routines */
-	gint width, height;
 
 	struct render_priv *render_priv;
 
@@ -157,31 +131,14 @@ typedef struct {
 
 	GdkColormap *colormap;
 
-	GdkCursor *X_cursor;					/* used X cursor */
-	GdkCursorType X_cursor_shape;	/* and its shape */
-
-	gboolean has_entered;
-	gboolean panning;
+	pcb_gtk_mouse_t mouse;
 
-	view_data view;
-	pcb_coord_t pcb_x, pcb_y;						/* PCB coordinates of the mouse pointer */
-	pcb_coord_t crosshair_x, crosshair_y;	/* PCB coordinates of the crosshair     */
+	pcb_gtk_view_t view;
 } GHidPort;
 
 extern GHidPort ghid_port, *gport;
 
 typedef enum {
-	NONE_PRESSED = 0,
-	SHIFT_PRESSED = PCB_M_Shift,
-	CONTROL_PRESSED = PCB_M_Ctrl,
-	MOD1_PRESSED = PCB_M_Mod1,
-	SHIFT_CONTROL_PRESSED = PCB_M_Shift | PCB_M_Ctrl,
-	SHIFT_MOD1_PRESSED = PCB_M_Shift | PCB_M_Mod1,
-	CONTROL_MOD1_PRESSED = PCB_M_Ctrl | PCB_M_Mod1,
-	SHIFT_CONTROL_MOD1_PRESSED = PCB_M_Shift | PCB_M_Ctrl | PCB_M_Mod1
-} ModifierKeysState;
-
-typedef enum {
 	NO_BUTTON_PRESSED,
 	BUTTON1_PRESSED,
 	BUTTON2_PRESSED,
@@ -210,7 +167,6 @@ void ghid_config_handle_units_changed(void);
 void ghid_config_start_backup_timer(void);
 void ghid_config_text_scale_update(void);
 void ghid_config_layer_name_update(gchar * name, gint layer);
-void ghid_config_groups_changed(void);
 
 void ghid_config_init(void);
 void ghid_wgeo_save(int save_to_file, int skip_user);
@@ -222,42 +178,23 @@ void ghid_pack_mode_buttons(void);
 void ghid_layer_buttons_update(void);
 void ghid_layer_buttons_color_update(void);
 
-
-/* gui-misc.c function prototypes
+/* in_mouse.c static variables
 */
-void ghid_status_line_set_text(const gchar * text);
-void ghid_cursor_position_label_set_text(gchar * text);
-void ghid_cursor_position_relative_label_set_text(gchar * text);
-
-void ghid_hand_cursor(void);
-void ghid_point_cursor(void);
-void ghid_watch_cursor(void);
-void ghid_mode_cursor(gint mode);
-void ghid_corner_cursor(void);
-void ghid_restore_cursor(void);
-void ghid_get_user_xy(const gchar * msg);
-void ghid_create_abort_dialog(gchar *);
-gboolean ghid_check_abort(void);
-void ghid_end_abort(void);
-void ghid_get_pointer(gint *, gint *);
-
+extern GdkPixmap *XC_hand_source, *XC_hand_mask;
+extern GdkPixmap *XC_lock_source, *XC_lock_mask;
+extern GdkPixmap *XC_clock_source, *XC_clock_mask;
 
 /* gui-output-events.c function prototypes.
 */
 void ghid_port_ranges_changed(void);
 void ghid_port_ranges_scale(void);
 
-void ghid_note_event_location(GdkEventButton * ev);
-gboolean ghid_port_key_press_cb(GtkWidget * drawing_area, GdkEventKey * kev, gpointer data);
 gboolean ghid_port_key_release_cb(GtkWidget * drawing_area, GdkEventKey * kev, gpointer data);
-gboolean ghid_port_button_press_cb(GtkWidget * drawing_area, GdkEventButton * ev, gpointer data);
-gboolean ghid_port_button_release_cb(GtkWidget * drawing_area, GdkEventButton * ev, gpointer data);
 
 
 gint ghid_port_window_enter_cb(GtkWidget * widget, GdkEventCrossing * ev, GHidPort * out);
 gint ghid_port_window_leave_cb(GtkWidget * widget, GdkEventCrossing * ev, GHidPort * out);
 gint ghid_port_window_motion_cb(GtkWidget * widget, GdkEventMotion * ev, GHidPort * out);
-gint ghid_port_window_mouse_scroll_cb(GtkWidget * widget, GdkEventScroll * ev, GHidPort * out);
 
 
 gint ghid_port_drawing_area_configure_event_cb(GtkWidget * widget, GdkEventConfigure * ev, GHidPort * out);
@@ -267,27 +204,6 @@ gint ghid_port_drawing_area_configure_event_cb(GtkWidget * widget, GdkEventConfi
 */
 #define		GUI_DIALOG_RESPONSE_ALL	1
 
-gchar *ghid_dialog_file_select_open(const gchar * title, gchar ** path, const gchar * shortcuts);
-gchar *ghid_dialog_file_select_save(const gchar * title, gchar ** path, const gchar * file, const gchar * shortcuts, const char **formats, const char **extensions, int *format);
-void ghid_dialog_message(gchar * message);
-gboolean ghid_dialog_confirm(const gchar * message, const gchar * cancelmsg, const gchar * okmsg);
-int ghid_dialog_close_confirm(void);
-#define GUI_DIALOG_CLOSE_CONFIRM_CANCEL 0
-#define GUI_DIALOG_CLOSE_CONFIRM_NOSAVE 1
-#define GUI_DIALOG_CLOSE_CONFIRM_SAVE   2
-gint ghid_dialog_confirm_all(gchar * message);
-gchar *ghid_dialog_input(const char *prompt, const char *initial);
-void ghid_dialog_about(void);
-
-char *ghid_fileselect(const char *, const char *, const char *, const char *, const char *, int);
-
-
-/* gui-dialog-print.c */
-void ghid_dialog_export(void);
-void ghid_dialog_print(pcb_hid_t *);
-
-int ghid_attribute_dialog(pcb_hid_attribute_t *, int, pcb_hid_attr_val_t *, const char *, const char *);
-
 /* gui-drc-window.c */
 void ghid_drc_window_show(gboolean raise);
 void ghid_drc_window_reset_message(void);
@@ -301,46 +217,14 @@ void ghid_notify_save_pcb(const char *file, pcb_bool done);
 void ghid_notify_filename_changed(void);
 void ghid_install_accel_groups(GtkWindow * window, GhidGui * gui);
 void ghid_remove_accel_groups(GtkWindow * window, GhidGui * gui);
-void make_route_style_buttons(GHidRouteStyleSelector * rss);
 
 /* gui-utils.c
 */
-gboolean dup_string(gchar ** dst, const gchar * src);
-gboolean utf8_dup_string(gchar ** dst_utf8, const gchar * src);
-void free_glist_and_data(GList ** list_head);
-
-ModifierKeysState ghid_modifier_keys_state(GdkModifierType * state);
-ButtonState ghid_button_state(GdkModifierType * state);
-gboolean ghid_is_modifier_key_sym(gint ksym);
 gboolean ghid_control_is_pressed(void);
 gboolean ghid_mod1_is_pressed(void);
 gboolean ghid_shift_is_pressed(void);
 
 void ghid_draw_area_update(GHidPort * out, GdkRectangle * rect);
-const gchar *ghid_get_color_name(GdkColor * color);
-void ghid_map_color_string(const gchar * color_string, GdkColor * color);
-const gchar *ghid_entry_get_text(GtkWidget * entry);
-void ghid_check_button_connected(GtkWidget * box, GtkWidget ** button,
-																 gboolean active, gboolean pack_start,
-																 gboolean expand, gboolean fill, gint pad,
-																 void (*cb_func) (GtkToggleButton *, gpointer), gpointer data, const gchar * string);
-void ghid_coord_entry(GtkWidget * box, GtkWidget ** coord_entry, pcb_coord_t value,
-											pcb_coord_t low, pcb_coord_t high, enum ce_step_size step_size, const pcb_unit_t *u,
-											gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
-											gpointer data, const gchar * string_pre, const gchar * string_post);
-void ghid_spin_button(GtkWidget * box, GtkWidget ** spin_button,
-											gfloat value, gfloat low, gfloat high, gfloat step0,
-											gfloat step1, gint digits, gint width,
-											void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, const gchar * string);
-void ghid_table_coord_entry(GtkWidget * table, gint row, gint column,
-														GtkWidget ** coord_entry, pcb_coord_t value,
-														pcb_coord_t low, pcb_coord_t high, enum ce_step_size, gint width,
-														void (*cb_func) (GHidCoordEntry *, gpointer), gpointer data, gboolean right_align, const gchar * string);
-void ghid_table_spin_button(GtkWidget * box, gint row, gint column,
-														GtkWidget ** spin_button, gfloat value,
-														gfloat low, gfloat high, gfloat step0,
-														gfloat step1, gint digits, gint width,
-														void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, const gchar * string);
 
 void ghid_range_control(GtkWidget * box, GtkWidget ** scale_res,
 												gboolean horizontal, GtkPositionType pos,
@@ -348,32 +232,6 @@ void ghid_range_control(GtkWidget * box, GtkWidget ** scale_res,
 												gboolean pack_start, gboolean expand, gboolean fill,
 												guint pad, gfloat value, gfloat low, gfloat high,
 												gfloat step0, gfloat step1, void (*cb_func) (), gpointer data);
-GtkWidget *ghid_scrolled_vbox(GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy);
-GtkWidget *ghid_framed_vbox(GtkWidget * box, gchar * label,
-														gint frame_border_width, gboolean frame_expand, gint vbox_pad, gint vbox_border_width);
-GtkWidget *ghid_framed_vbox_end(GtkWidget * box, gchar * label,
-																gint frame_border_width, gboolean frame_expand, gint vbox_pad, gint vbox_border_width);
-GtkWidget *ghid_category_vbox(GtkWidget * box, const gchar * category_header,
-															gint header_pad, gint box_pad, gboolean pack_start, gboolean bottom_pad);
-GtkWidget *ghid_notebook_page(GtkWidget * tabs, const char *name, gint pad, gint border);
-GtkWidget *ghid_framed_notebook_page(GtkWidget * tabs, const char *name,
-																		 gint border, gint frame_border, gint vbox_pad, gint vbox_border);
-GtkWidget *ghid_scrolled_text_view(GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy);
-void ghid_text_view_append(GtkWidget * view, const gchar * string);
-void ghid_text_view_append_strings(GtkWidget * view, const gchar ** string, gint n_strings);
-GtkTreeSelection *ghid_scrolled_selection(GtkTreeView * treeview,
-																					GtkWidget * box,
-																					GtkSelectionMode s_mode,
-																					GtkPolicyType h_policy,
-																					GtkPolicyType v_policy,
-																					void (*func_cb) (GtkTreeSelection *, gpointer), gpointer data);
-
-void ghid_dialog_report(const gchar * title, const gchar * message);
-void ghid_label_set_markup(GtkWidget * label, const gchar * text);
-
-void ghid_set_cursor_position_labels(void);
-void ghid_set_status_line_label(void);
-
 
 /* gui-netlist-window.c */
 void ghid_netlist_window_create(GHidPort * out);
@@ -390,9 +248,6 @@ void ghid_command_window_show(gboolean raise);
 gchar *ghid_command_entry_get(const gchar * prompt, const gchar * command);
 void ghid_command_use_command_window_sync(void);
 
-/* gui-keyref-window.c */
-void ghid_keyref_window_show(gboolean raise);
-
 /* gui-library-window.c */
 void ghid_library_window_create(GHidPort * out);
 void ghid_library_window_show(GHidPort * out, gboolean raise);
@@ -404,9 +259,6 @@ void ghid_log_window_show(gboolean raise);
 void ghid_log(const char *fmt, ...);
 void ghid_logv(enum pcb_message_level level, const char *fmt, va_list args);
 
-/* gui-pinout-window.c */
-void ghid_pinout_window_show(GHidPort * out, pcb_element_t *Element);
-
 /* gtkhid-gdk.c AND gtkhid-gl.c */
 int ghid_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, unsigned int flags, int is_empty);
 pcb_hid_gc_t ghid_make_gc(void);
@@ -428,31 +280,21 @@ void ghid_notify_crosshair_change(pcb_bool changes_complete);
 void ghid_notify_mark_change(pcb_bool changes_complete);
 void ghid_init_renderer(int *, char ***, GHidPort *);
 void ghid_shutdown_renderer(GHidPort *);
-void ghid_init_drawing_widget(GtkWidget * widget, GHidPort *);
+void ghid_init_drawing_widget(GtkWidget * widget, void *gport);
 void ghid_drawing_area_configure_hook(GHidPort * port);
 void ghid_screen_update(void);
 gboolean ghid_drawing_area_expose_cb(GtkWidget *, GdkEventExpose *, GHidPort *);
 void ghid_port_drawing_realize_cb(GtkWidget *, gpointer);
-gboolean ghid_pinout_preview_expose(GtkWidget * widget, GdkEventExpose * ev);
+gboolean ghid_preview_expose(GtkWidget * widget, GdkEventExpose * ev, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx);
+gboolean ghid_preview_draw(GtkWidget * widget, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx);
 GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height, int depth);
 pcb_hid_t *ghid_request_debug_draw(void);
 void ghid_flush_debug_draw(void);
 void ghid_finish_debug_draw(void);
-pcb_bool ghid_event_to_pcb_coords(int event_x, int event_y, pcb_coord_t * pcb_x, pcb_coord_t * pcb_y);
-pcb_bool ghid_pcb_to_event_coords(pcb_coord_t pcb_x, pcb_coord_t pcb_y, int *event_x, int *event_y);
 
 void ghid_lead_user_to_location(pcb_coord_t x, pcb_coord_t y);
 void ghid_cancel_lead_user(void);
 
-/* gtkhid-main.c */
-void ghid_pan_view_rel(pcb_coord_t dx, pcb_coord_t dy);
-void ghid_get_coords(const char *msg, pcb_coord_t * x, pcb_coord_t * y);
-
-
-extern GdkPixmap *XC_hand_source, *XC_hand_mask;
-extern GdkPixmap *XC_lock_source, *XC_lock_mask;
-extern GdkPixmap *XC_clock_source, *XC_clock_mask;
-
 
 /* Coordinate conversions */
 /* Px converts view->pcb, Vx converts pcb->view */
@@ -481,6 +323,31 @@ static inline int Vz(pcb_coord_t z)
 	return pcb_round((double)z / gport->view.coord_per_px + 0.5);
 }
 
+static inline double Vxd(pcb_coord_t x)
+{
+	double rv;
+	if (conf_core.editor.view.flip_x)
+		rv = (PCB->MaxWidth - x - gport->view.x0) / gport->view.coord_per_px;
+	else
+		rv = (x - gport->view.x0) / gport->view.coord_per_px;
+	return rv;
+}
+
+static inline double Vyd(pcb_coord_t y)
+{
+	double rv;
+	if (conf_core.editor.view.flip_y)
+		rv = (PCB->MaxHeight - y - gport->view.y0) / gport->view.coord_per_px;
+	else
+		rv = (y - gport->view.y0) / gport->view.coord_per_px;
+	return rv;
+}
+
+static inline double Vzd(pcb_coord_t z)
+{
+	return (double)z / gport->view.coord_per_px;
+}
+
 static inline pcb_coord_t Px(int x)
 {
 	pcb_coord_t rv = x * gport->view.coord_per_px + gport->view.x0;
@@ -504,9 +371,7 @@ static inline pcb_coord_t Pz(int z)
 
 extern const char *ghid_cookie;
 extern const char *ghid_menu_cookie;
-extern pcb_hid_cfg_mouse_t ghid_mouse;
 extern pcb_hid_cfg_keys_t ghid_keymap;
-extern int ghid_wheel_zoom;
 
 int ghid_usage(const char *topic);
 void hid_gtk_wgeo_update(void);
diff --git a/src_plugins/hid_gtk/win_place.c b/src_plugins/hid_gtk/win_place.c
deleted file mode 100644
index e01c057..0000000
--- a/src_plugins/hid_gtk/win_place.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  pcb-rnd, interactive printed circuit board design
- *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "config.h"
-#include "win_place.h"
-
-#define CONF_PREFIX "plugins/hid_gtk/window_geometry/"
-static const char *conf_prefix[WPLC_max] = { /* order DOES matter */
-	"top_",
-	"log_",
-	"drc_",
-	"library_",
-	"netlist_",
-	"keyref_",
-	"pinout_",
-	"search_"
-};
-
-static GtkWidget *wplc_windows[WPLC_max];
-
-/* true if the given configuration item has exactly one integer value */
-#define HAVE(native) ((native != NULL) && ((native)->used == 1) && ((native)->type == CFN_INTEGER))
-
-void wplc_place(wplc_win_t id, GtkWidget *new_win)
-{
-	char path[128], *pe;
-	conf_native_t *nx, *ny, *nw, *nh;
-	GtkWidget *win;
-
-	if ((id < 0) || (id >= WPLC_max))
-		return; /* invalid window */
-
-	if (!conf_core.editor.auto_place) {
-		if (new_win != NULL) /* remember window widgets in case editor.auto_place gets enabled later */
-			wplc_windows[id] = new_win;
-		return; /* feature disabled */
-	}
-
-	/* build base path for the specific window */
-	pe = path;
-	strcpy(pe, CONF_PREFIX);      pe += strlen(CONF_PREFIX);
-	strcpy(pe, conf_prefix[id]);  pe += strlen(conf_prefix[id]);
-
-	/* query each parameter */
-	strcpy(pe, "height"); nh = conf_get_field(path);
-	strcpy(pe, "width");  nw = conf_get_field(path);
-	strcpy(pe, "x");      nx = conf_get_field(path);
-	strcpy(pe, "y");      ny = conf_get_field(path);
-
-	if (new_win != NULL) {
-		wplc_windows[id] = new_win;
-		win = new_win;
-		/* for new windows set hint */
-		if (HAVE(nw) && HAVE(nh))
-			gtk_window_set_default_size(GTK_WINDOW(win), nw->val.integer[0], nh->val.integer[0]);
-		if (HAVE(nx) && HAVE(ny))
-			gtk_window_move(GTK_WINDOW(win), nx->val.integer[0], ny->val.integer[0]);
-		else
-			gtk_window_move(GTK_WINDOW(win), 10, 10); /* original behaviour */
-	}
-	else {
-		win = wplc_windows[id];
-		if (win != NULL) {
-			if (HAVE(nw) && HAVE(nh))
-				gtk_window_resize(GTK_WINDOW(win), nw->val.integer[0], nh->val.integer[0]);
-			if (HAVE(nx) && HAVE(ny))
-				gtk_window_move(GTK_WINDOW(win), nx->val.integer[0], ny->val.integer[0]);
-		}
-	}
-}
-#undef HAVE
-
-void wplc_config_event(GtkWidget *win, long *cx, long *cy, long *cw, long *ch)
-{
-	GtkAllocation allocation;
-	gboolean new_w, new_h, new_x, new_y;
-
-	gtk_widget_get_allocation(win, &allocation);
-
-	/* For whatever reason, get_allocation doesn't set these. Gtk. */
-	gtk_window_get_position(GTK_WINDOW(win), &allocation.x, &allocation.y);
-
-	new_w = (*cw != allocation.width);
-	new_h = (*ch != allocation.height);
-	new_x = (*cx != allocation.x);
-	new_y = (*cy != allocation.y);
-
-	*cx = allocation.x;
-	*cy = allocation.y;
-	*cw = allocation.width;
-	*ch = allocation.height;
-
-	if (new_w || new_h || new_x || new_y)
-		hid_gtk_wgeo_update();
-}
diff --git a/src_plugins/hid_gtk/win_place.h b/src_plugins/hid_gtk/win_place.h
deleted file mode 100644
index a2f3a7b..0000000
--- a/src_plugins/hid_gtk/win_place.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef GHID_WIN_PLACE
-#define GHID_WIN_PLACE
-#include "gui.h"
-
-typedef enum {
-	WPLC_TOP,
-	WPLC_LOG,
-	WPLC_DRC,
-	WPLC_LIBRARY,
-	WPLC_NETLIST,
-	WPLC_KEYREF,
-	WPLC_PINOUT,
-	WPLC_SEARCH,
-	WPLC_max
-} wplc_win_t;
-
-/* Place the window if it's enabled and there are coords in the config. */
-void wplc_place(wplc_win_t id, GtkWidget *win);
-
-/* query window current window sizes and update wgeo cache */
-void wplc_config_event(GtkWidget *win, long *cx, long *cy, long *cw, long *ch);
-#endif
diff --git a/src_plugins/hid_gtk3/README b/src_plugins/hid_gtk3/README
new file mode 100644
index 0000000..0e8b17d
--- /dev/null
+++ b/src_plugins/hid_gtk3/README
@@ -0,0 +1,5 @@
+GUI: the GTK3 HID, using cairo for rendering
+
+#state: WIP
+#default: disable
+#implements: hid
diff --git a/src_plugins/hid_gtk3/colors.c b/src_plugins/hid_gtk3/colors.c
new file mode 100644
index 0000000..635e169
--- /dev/null
+++ b/src_plugins/hid_gtk3/colors.c
@@ -0,0 +1,75 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* FIXME: Find a way to get rid of GHidPort *out and gui.h */
+#include "gui.h"
+
+/* FIXME: could be more generic with a pcb_color_s structure depending on Toolkit :
+ * GdkColor for GTK2
+ * GdkRGBA  for GTK3
+ */
+/*#include "colors.h"*/
+
+const gchar *ghid_get_color_name(GdkRGBA * color)
+{
+	static char tmp[16];
+
+	if (!color)
+		return "#000000";
+
+	/*sprintf(tmp, "#%2.2x%2.2x%2.2x", (color->red >> 8) & 0xff, (color->green >> 8) & 0xff, (color->blue >> 8) & 0xff); */
+	tmp = gdk_rgba_to_string(color);
+	/* Note that this string representation may lose some precision, since r, g and b
+	   are represented as 8-bit integers.
+	   If this is a concern, you should use a different representation.
+	 */
+
+	return tmp;
+}
+
+void ghid_map_color_string(const char *color_string, GdkRGBA * color)
+{
+	/*FIXME: Get rid of GdkColormap and GHidPort */
+	static GdkColormap *colormap = NULL;
+	GHidPort *out = &ghid_port;
+	/* Needs a
+	   GdkVisual *visual
+	   to replace GdkColormap, then cairo will handle colors
+	 */
+
+	if (!color || !out->top_window)
+		return;
+	if (colormap == NULL)
+		colormap = gtk_widget_get_colormap(out->top_window);
+	if (color->red || color->green || color->blue)
+		gdk_colormap_free_colors(colormap, color, 1);
+	/*if false then ? */
+	gdk_rgba_parse(color, color_string);
+	gdk_color_alloc(colormap, color);
+}
diff --git a/src_plugins/hid_gtk3/colors.h b/src_plugins/hid_gtk3/colors.h
new file mode 100644
index 0000000..e413ea0
--- /dev/null
+++ b/src_plugins/hid_gtk3/colors.h
@@ -0,0 +1,4 @@
+#include <gdk/gdk.h>
+
+const gchar *ghid_get_color_name(GdkRGBA * color);
+void ghid_map_color_string(const char *color_string, GdkRGBA * color);
diff --git a/src_plugins/hid_lesstif/dialogs.c b/src_plugins/hid_lesstif/dialogs.c
index ca08dc4..cea704a 100644
--- a/src_plugins/hid_lesstif/dialogs.c
+++ b/src_plugins/hid_lesstif/dialogs.c
@@ -281,7 +281,6 @@ static void log_dismiss(Widget w, void *up, void *cbp)
 
 void lesstif_logv(enum pcb_message_level level, const char *fmt, va_list ap)
 {
-	/* TODO(hzeller): do something useful with level (color etc.) */
 	char *buf, *scan;
 	if (!mainwind) {
 		vprintf(fmt, ap);
@@ -336,6 +335,13 @@ void lesstif_logv(enum pcb_message_level level, const char *fmt, va_list ap)
 		pending_newline++;
 		*scan-- = 0;
 	}
+	switch(level) {
+		case PCB_MSG_ERROR:   XmTextInsert(log_text, log_size, "Err: "); break;
+		case PCB_MSG_WARNING: XmTextInsert(log_text, log_size, "Wrn: "); break;
+		case PCB_MSG_INFO:    XmTextInsert(log_text, log_size, "Inf: "); break;
+		case PCB_MSG_DEBUG:   XmTextInsert(log_text, log_size, "Dbg: "); break;
+	}
+	log_size += 5;
 	XmTextInsert(log_text, log_size, buf);
 	log_size += strlen(buf);
 
@@ -1210,217 +1216,9 @@ static int AdjustSizes(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y
 
 /* ------------------------------------------------------------ */
 
-static Widget layer_groups_form = 0;
-static Widget lg_buttonform = 0;
-
-static int lg_setcol[PCB_MAX_LAYERGRP + 2];
-static int lg_width, lg_height;
-static int lg_r[PCB_MAX_LAYER + 3];
-static int lg_c[PCB_MAX_LAYERGRP + 1];
-static int lg_label_width, lg_fa, lg_fd;
-static GC lg_gc = 0;
-
-#if 0
-static Widget lglabels[PCB_MAX_LAYER + 2];
-static Widget lgbuttons[PCB_MAX_LAYER + 2][PCB_MAX_LAYER];
-#endif
-
-typedef struct {
-	XFontStruct *font;
-	Pixel fg, bg, sel;
-} LgResource;
-
-static LgResource lgr;
-
-static XtResource lg_resources[] = {
-	{(char*)"font", (char*)"Font", XtRFontStruct, sizeof(XFontStruct *), XtOffset(LgResource *, font), XtRString, (void *) "fixed"},
-	{(char*)"foreground", (char*)"Foreground", XtRPixel, sizeof(Pixel), XtOffset(LgResource *, fg), XtRString, (void *) "black"},
-	{(char*)"selectColor", (char*)"Foreground", XtRPixel, sizeof(Pixel), XtOffset(LgResource *, sel), XtRString, (void *) "blue"},
-	{(char*)"background", (char*)"Background", XtRPixel, sizeof(Pixel), XtOffset(LgResource *, bg), XtRString, (void *) "white"}
-};
-
-#if 0
-static void lgbutton_cb(Widget w, int ij, void *cbs)
-{
-	int layer, group, k;
-
-	layer = ij / pcb_max_group;
-	group = ij % pcb_max_group;
-	group = pcb_layer_move_to_group(layer, group);
-	for (k = 0; k < pcb_max_group; k++) {
-		if (k == group)
-			XmToggleButtonSetState(lgbuttons[layer][k], 1, 0);
-		else
-			XmToggleButtonSetState(lgbuttons[layer][k], 0, 0);
-	}
-}
-#endif
-
-static void lgbutton_expose(Widget w, XtPointer u, XmDrawingAreaCallbackStruct * cbs)
-{
-	int i;
-	Window win = XtWindow(w);
-
-	if (cbs && cbs->event->xexpose.count)
-		return;
-	if (lg_gc == 0 && !cbs)
-		return;
-	if (lg_gc == 0 && cbs) {
-		lg_gc = XCreateGC(display, win, 0, 0);
-		XSetFont(display, lg_gc, lgr.font->fid);
-	}
-
-	XSetForeground(display, lg_gc, lgr.bg);
-	XFillRectangle(display, win, lg_gc, 0, 0, lg_width, lg_height);
-	XSetForeground(display, lg_gc, lgr.fg);
-	for (i = 0; i < pcb_max_group; i++)
-		XDrawLine(display, win, lg_gc, lg_c[i], 0, lg_c[i], lg_height);
-	for (i = 1; i < pcb_max_copper_layer + 2; i++)
-		XDrawLine(display, win, lg_gc, lg_label_width, lg_r[i], lg_width, lg_r[i]);
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-		int dir;
-		XCharStruct size;
-		int swidth;
-		const char *name;
-
-		if (i == pcb_solder_silk_layer)
-			name = SOLDER_SIDE_NAME;
-		else if (i == pcb_component_silk_layer)
-			name = COMPONENT_SIDE_NAME;
-		else
-			name = PCB->Data->Layer[i].Name;
-		XTextExtents(lgr.font, name, strlen(name), &dir, &lg_fa, &lg_fd, &size);
-		swidth = size.rbearing - size.lbearing;
-		XDrawString(display, win, lg_gc,
-								(lg_label_width - swidth) / 2 - size.lbearing,
-								(lg_r[i] + lg_r[i + 1] + lg_fd + lg_fa) / 2 - 1, name, strlen(name));
-	}
-	XSetForeground(display, lg_gc, lgr.sel);
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-		int c = lg_setcol[i];
-		int x1 = lg_c[c] + 2;
-		int x2 = lg_c[c + 1] - 2;
-		int y1 = lg_r[i] + 2;
-		int y2 = lg_r[i + 1] - 2;
-		XFillRectangle(display, win, lg_gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
-	}
-}
-
-static void lgbutton_input(Widget w, XtPointer u, XmDrawingAreaCallbackStruct * cbs)
-{
-	int layer, group;
-	if (cbs->event->type != ButtonPress)
-		return;
-	layer = cbs->event->xbutton.y * (pcb_max_copper_layer + 2) / lg_height;
-	group = (cbs->event->xbutton.x - lg_label_width) * pcb_max_group / (lg_width - lg_label_width);
-	group = pcb_layer_move_to_group(layer, group);
-	lg_setcol[layer] = group;
-	lgbutton_expose(w, 0, 0);
-	pcb_gui->invalidate_all();
-}
-
-static void lgbutton_resize(Widget w, XtPointer u, XmDrawingAreaCallbackStruct * cbs)
-{
-	int i;
-	Dimension width, height;
-	stdarg_n = 0;
-	stdarg(XmNwidth, &width);
-	stdarg(XmNheight, &height);
-	XtGetValues(w, stdarg_args, stdarg_n);
-	lg_width = width;
-	lg_height = height;
-
-	for (i = 0; i <= pcb_max_group; i++)
-		lg_c[i] = lg_label_width + (lg_width - lg_label_width) * i / pcb_max_group;
-	for (i = 0; i <= pcb_max_copper_layer + 2; i++)
-		lg_r[i] = lg_height * i / (pcb_max_copper_layer + 2);
-	lgbutton_expose(w, 0, 0);
-}
-
 void lesstif_update_layer_groups()
 {
-	int sets[PCB_MAX_LAYERGRP + 2][PCB_MAX_LAYER];
-	int i, j;
-	pcb_layer_group_t *l = &(PCB->LayerGroups);
-
-	if (!layer_groups_form)
-		return;
-
-	memset(sets, 0, sizeof(sets));
-
-	for (i = 0; i < pcb_max_group; i++)
-		for (j = 0; j < l->Number[i]; j++) {
-			sets[l->Entries[i][j]][i] = 1;
-			lg_setcol[l->Entries[i][j]] = i;
-		}
-
-	lg_label_width = 0;
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-		int dir;
-		XCharStruct size;
-		int swidth;
-		const char *name;
-
-		if (i == pcb_solder_silk_layer)
-			name = SOLDER_SIDE_NAME;
-		else if (i == pcb_component_silk_layer)
-			name = COMPONENT_SIDE_NAME;
-		else
-			name = PCB->Data->Layer[i].Name;
-		XTextExtents(lgr.font, name, strlen(name), &dir, &lg_fa, &lg_fd, &size);
-		swidth = size.rbearing - size.lbearing;
-		if (lg_label_width < swidth)
-			lg_label_width = swidth;
-	}
-	lg_label_width += 4;
-
-	stdarg_n = 0;
-	stdarg(XmNwidth, lg_label_width + (lg_fa + lg_fd) * pcb_max_group);
-	stdarg(XmNheight, (lg_fa + lg_fd) * (pcb_max_copper_layer + 2));
-	XtSetValues(lg_buttonform, stdarg_args, stdarg_n);
-	lgbutton_expose(lg_buttonform, 0, 0);
-
-#if 0
-	for (i = 0; i < pcb_max_copper_layer + 2; i++) {
-		char *name = "unknown";
-		stdarg_n = 0;
-		if (i < pcb_max_copper_layer)
-			name = PCB->Data->Layer[i].Name;
-		else if (i == pcb_solder_silk_layer)
-			name = SOLDER_SIDE_NAME;
-		else if (i == pcb_component_silk_layer)
-			name = COMPONENT_SIDE_NAME;
-		stdarg(XmNlabelString, XmStringCreatePCB(name));
-		XtSetValues(lglabels[i], stdarg_args, stdarg_n);
-		for (j = 0; j < pcb_max_group; j++) {
-			if (sets[i][j] != XmToggleButtonGetState(lgbuttons[i][j])) {
-				XmToggleButtonSetState(lgbuttons[i][j], sets[i][j], 0);
-			}
-		}
-	}
-	XtUnmanageChild(lg_buttonform);
-	for (i = 0; i < PCB_MAX_LAYERGRP + 2; i++)
-		for (j = 0; j < PCB_MAX_LAYER; j++) {
-			if (i < pcb_max_copper_layer + 2 && j < pcb_max_group) {
-				XtManageChild(lgbuttons[i][j]);
-				stdarg_n = 0;
-				stdarg(XmNleftPosition, j * (pcb_max_copper_layer + 2));
-				stdarg(XmNrightPosition, (j + 1) * (pcb_max_copper_layer + 2));
-				stdarg(XmNtopPosition, i * pcb_max_group);
-				stdarg(XmNbottomPosition, (i + 1) * pcb_max_group);
-				XtSetValues(lgbuttons[i][j], stdarg_args, stdarg_n);
-			}
-			else
-				XtUnmanageChild(lgbuttons[i][j]);
-		}
-	stdarg_n = 0;
-	stdarg(XmNfractionBase, pcb_max_copper_layer + 2);
-	XtSetValues(layer_groups_form, stdarg_args, stdarg_n);
-	stdarg_n = 0;
-	stdarg(XmNfractionBase, pcb_max_group * (pcb_max_copper_layer + 2));
-	XtSetValues(lg_buttonform, stdarg_args, stdarg_n);
-	XtManageChild(lg_buttonform);
-#endif
+#warning layer TODO: call a redraw on the edit group
 }
 
 static const char editlayergroups_syntax[] = "EditLayerGroups()";
@@ -1439,72 +1237,10 @@ See @ref{ChangeName Action}.
 
 %end-doc */
 
+extern void lesstif_show_layergrp_edit(void);
 static int EditLayerGroups(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
-	if (!layer_groups_form) {
-
-		stdarg_n = 0;
-		stdarg(XmNfractionBase, pcb_max_copper_layer + 2);
-		stdarg(XmNtitle, "Layer Groups");
-		layer_groups_form = XmCreateFormDialog(mainwind, XmStrCast("layers"), stdarg_args, stdarg_n);
-
-		stdarg_n = 0;
-		stdarg(XmNtopAttachment, XmATTACH_FORM);
-		stdarg(XmNbottomAttachment, XmATTACH_FORM);
-		stdarg(XmNrightAttachment, XmATTACH_FORM);
-		stdarg(XmNleftAttachment, XmATTACH_FORM);
-		lg_buttonform = XmCreateDrawingArea(layer_groups_form, XmStrCast("layers"), stdarg_args, stdarg_n);
-		XtManageChild(lg_buttonform);
-
-		XtAddCallback(lg_buttonform, XmNexposeCallback, (XtCallbackProc) lgbutton_expose, 0);
-		XtAddCallback(lg_buttonform, XmNinputCallback, (XtCallbackProc) lgbutton_input, 0);
-		XtAddCallback(lg_buttonform, XmNresizeCallback, (XtCallbackProc) lgbutton_resize, 0);
-
-		XtGetSubresources(layer_groups_form, &lgr, "layergroups", "LayerGroups", lg_resources, XtNumber(lg_resources), 0, 0);
-#if 0
-		stdarg(XmNfractionBase, pcb_max_group * (PCB_MAX_LAYER + 2));
-		lg_buttonform = XmCreateForm(layer_groups_form, "lgbutton", stdarg_args, stdarg_n);
-
-		for (i = 0; i < PCB_MAX_LAYER + 2; i++) {
-			stdarg_n = 0;
-			stdarg(XmNleftAttachment, XmATTACH_FORM);
-			stdarg(XmNtopAttachment, XmATTACH_POSITION);
-			stdarg(XmNtopPosition, i);
-			stdarg(XmNbottomAttachment, XmATTACH_POSITION);
-			stdarg(XmNbottomPosition, i + 1);
-			stdarg(XmNrightAttachment, XmATTACH_WIDGET);
-			stdarg(XmNrightWidget, lg_buttonform);
-			lglabels[i] = XmCreateLabel(layer_groups_form, "layer", stdarg_args, stdarg_n);
-			XtManageChild(lglabels[i]);
-
-			for (j = 0; j < PCB_MAX_LAYER; j++) {
-				stdarg_n = 0;
-				stdarg(XmNleftAttachment, XmATTACH_POSITION);
-				stdarg(XmNleftPosition, j * (PCB_MAX_LAYER + 2));
-				stdarg(XmNrightAttachment, XmATTACH_POSITION);
-				stdarg(XmNrightPosition, (j + 1) * (PCB_MAX_LAYER + 2));
-				stdarg(XmNtopAttachment, XmATTACH_POSITION);
-				stdarg(XmNtopPosition, i * PCB_MAX_LAYER);
-				stdarg(XmNbottomAttachment, XmATTACH_POSITION);
-				stdarg(XmNbottomPosition, (i + 1) * PCB_MAX_LAYER);
-				stdarg(XmNlabelString, XmStringCreatePCB(" "));
-				stdarg(XmNspacing, 0);
-				stdarg(XmNvisibleWhenOff, True);
-				stdarg(XmNfillOnSelect, True);
-				stdarg(XmNshadowThickness, 0);
-				stdarg(XmNmarginWidth, 0);
-				stdarg(XmNmarginHeight, 0);
-				stdarg(XmNhighlightThickness, 0);
-				lgbuttons[i][j] = XmCreateToggleButton(lg_buttonform, "label", stdarg_args, stdarg_n);
-				XtManageChild(lgbuttons[i][j]);
-
-				XtAddCallback(lgbuttons[i][j], XmNvalueChangedCallback, (XtCallbackProc) lgbutton_cb, (XtPointer) (i * pcb_max_group + j));
-			}
-		}
-#endif
-	}
-	lesstif_update_layer_groups();
-	XtManageChild(layer_groups_form);
+	lesstif_show_layergrp_edit();
 	return 1;
 }
 
diff --git a/src_plugins/hid_lesstif/dlg_preview.c b/src_plugins/hid_lesstif/dlg_preview.c
new file mode 100644
index 0000000..085585b
--- /dev/null
+++ b/src_plugins/hid_lesstif/dlg_preview.c
@@ -0,0 +1,257 @@
+/* Directly included by main.c for now */
+
+#define SHOW_SAVES \
+	int save_vx, save_vy, save_vw, save_vh; \
+	int save_fx, save_fy; \
+	double save_vz; \
+	Pixmap save_px
+
+#define SHOW_ENTER \
+do { \
+	pinout = 0; \
+	save_vx = view_left_x; \
+	save_vy = view_top_y; \
+	save_vz = view_zoom; \
+	save_vw = view_width; \
+	save_vh = view_height; \
+	save_fx = conf_core.editor.view.flip_x; \
+	save_fy = conf_core.editor.view.flip_y; \
+	save_px = pixmap; \
+	pixmap = pd->window; \
+	view_left_x = pd->x; \
+	view_top_y = pd->y; \
+	view_zoom = pd->zoom; \
+	view_width = pd->v_width; \
+	view_height = pd->v_height; \
+	use_mask = 0; \
+	conf_force_set_bool(conf_core.editor.view.flip_x, 0); \
+	conf_force_set_bool(conf_core.editor.view.flip_y, 0); \
+} while(0)
+
+#define SHOW_LEAVE \
+do { \
+	view_left_x = save_vx; \
+	view_top_y = save_vy; \
+	view_zoom = save_vz; \
+	view_width = save_vw; \
+	view_height = save_vh; \
+	pixmap = save_px; \
+	conf_force_set_bool(conf_core.editor.view.flip_x, save_fx); \
+	conf_force_set_bool(conf_core.editor.view.flip_y, save_fy); \
+} while(0)
+
+#define SHOW_DRAW \
+do { \
+	XFillRectangle(display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height); \
+	pcb_hid_expose_layer(&lesstif_hid, &pd->ctx); \
+} while(0)
+
+static void show_layer_callback(Widget da, PreviewData * pd, XmDrawingAreaCallbackStruct * cbs)
+{
+	SHOW_SAVES;
+	int reason = cbs ? cbs->reason : 0;
+
+	if (pd->window == 0 && reason == XmCR_RESIZE)
+		return;
+	if (pd->window == 0 || reason == XmCR_RESIZE) {
+		Dimension w, h;
+		double z;
+
+		stdarg_n = 0;
+		stdarg(XmNwidth, &w);
+		stdarg(XmNheight, &h);
+		XtGetValues(da, stdarg_args, stdarg_n);
+
+		pd->window = XtWindow(da);
+		pd->v_width = w;
+		pd->v_height = h;
+		pd->zoom = (pd->right - pd->left + 1) / (double) w;
+		z = (pd->bottom - pd->top + 1) / (double) h;
+		if (pd->zoom < z)
+			pd->zoom = z;
+
+		pd->x = (pd->left + pd->right) / 2 - pd->v_width * pd->zoom / 2;
+		pd->y = (pd->top + pd->bottom) / 2 - pd->v_height * pd->zoom / 2;
+	}
+
+	SHOW_ENTER;
+	SHOW_DRAW;
+
+	SHOW_LEAVE;
+
+}
+
+static void show_layer_inp_callback(Widget da, PreviewData * pd, XmDrawingAreaCallbackStruct * cbs)
+{
+	SHOW_SAVES;
+	pcb_coord_t cx, cy;
+	pcb_hid_cfg_mod_t btn;
+	pcb_hid_mouse_ev_t kind;
+
+	SHOW_ENTER;
+
+	btn = lesstif_mb2cfg(cbs->event->xbutton.button);
+
+	cx = Px(cbs->event->xbutton.x);
+	cy = Py(cbs->event->xbutton.y);
+
+/*	pcb_printf("ev %d;%d %$mm;%$mm %x\n", cbs->event->xbutton.x, cbs->event->xbutton.y, cx, cy, btn);*/
+
+	kind = -1;
+	if (cbs->event->type == ButtonPress) kind = PCB_HID_MOUSE_PRESS;
+	if (cbs->event->type == ButtonRelease) kind = PCB_HID_MOUSE_RELEASE;
+
+	switch(btn) {
+		case PCB_MB_LEFT:
+			if (pd->mouse_ev != NULL)
+				if (pd->mouse_ev(da, kind, cx, cy))
+					SHOW_DRAW;
+			break;
+		case PCB_MB_MIDDLE:
+			if (kind == PCB_HID_MOUSE_PRESS) {
+				pd->pan = 1;
+				pd->pan_ox = cbs->event->xbutton.x;
+				pd->pan_oy = cbs->event->xbutton.y;
+				pd->pan_opx = view_left_x;
+				pd->pan_opy = view_top_y;
+			}
+			else if (kind == PCB_HID_MOUSE_RELEASE)
+				pd->pan = 0;
+			break;
+		case PCB_MB_SCROLL_DOWN:
+			pd->zoom *= 1.25;
+			view_zoom = pd->zoom;
+			SHOW_DRAW;
+			break;
+		case PCB_MB_SCROLL_UP:
+			pd->zoom *= 0.8;
+			view_zoom = pd->zoom;
+			SHOW_DRAW;
+			break;
+		default:;
+	}
+
+	SHOW_LEAVE;
+}
+
+static void show_layer_mot_callback(Widget w, XtPointer pd_, XEvent * e, Boolean * ctd)
+{
+	PreviewData *pd = pd_;
+	SHOW_SAVES;
+	Window root, child;
+	unsigned int keys_buttons;
+	int root_x, root_y, pos_x, pos_y;
+	pcb_coord_t cx, cy;
+
+	while (XCheckMaskEvent(display, PointerMotionMask, e));
+	XQueryPointer(display, e->xmotion.window, &root, &child, &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
+
+	SHOW_ENTER;
+
+	cx = Px(pos_x);
+	cy = Py(pos_y);
+
+/*	pcb_printf("mo %d;%d %$mm;%$mm\n", pos_x, pos_y, cx, cy);*/
+	if (pd->pan) {
+/*		pcb_coord_t ol = pd->x, ot = pd->y;*/
+		pd->x = pd->pan_opx - (pos_x - pd->pan_ox) * view_zoom;
+		pd->y = pd->pan_opy - (pos_y - pd->pan_oy) * view_zoom;
+/*		pd->view_right += ol - pd->view_left_x;
+		pd->view_bottom += ot - pd->view_top_y;*/
+		SHOW_DRAW;
+	}
+	else if (pd->mouse_ev != NULL) {
+		pd->mouse_ev(w, PCB_HID_MOUSE_MOTION, cx, cy);
+		if (pd->overlay_draw != NULL)
+			pd->overlay_draw(pcb_gui, &pd->ctx);
+	}
+
+	SHOW_LEAVE;
+}
+
+
+static void show_layer_unmap(Widget w, PreviewData * pd, void *v)
+{
+	if (pd->pre_close != NULL)
+		pd->pre_close(pd);
+	XtDestroyWidget(XtParent(pd->form));
+	free(pd);
+}
+
+
+static PreviewData *lesstif_show_layer(pcb_layer_id_t layer, const char *title)
+{
+	double scale;
+	Widget da;
+	PreviewData *pd;
+
+	if (!mainwind)
+		return NULL;
+
+	pd = (PreviewData *) calloc(1, sizeof(PreviewData));
+
+	pd->ctx.content.layer_id = layer;
+
+	pd->ctx.view.X1 = pd->left = 0;
+	pd->ctx.view.X2 = pd->right = PCB_MM_TO_COORD(130);
+	pd->ctx.view.Y1 = pd->top = 0;
+	pd->ctx.view.Y2 = pd->bottom = PCB_MM_TO_COORD(130);
+	pd->ctx.force = 1;
+
+	pd->prev = 0;
+	pd->zoom = 0;
+
+	stdarg_n = 0;
+	pd->form = XmCreateFormDialog(mainwind, XmStrCast(title), stdarg_args, stdarg_n);
+	pd->window = 0;
+	XtAddCallback(pd->form, XmNunmapCallback, (XtCallbackProc) show_layer_unmap, (XtPointer) pd);
+
+	scale = sqrt(200.0 * 200.0 / ((pd->right - pd->left + 1.0) * (pd->bottom - pd->top + 1.0)));
+
+	stdarg_n = 0;
+	stdarg(XmNwidth, (int) (scale * (pd->right - pd->left + 1)));
+	stdarg(XmNheight, (int) (scale * (pd->bottom - pd->top + 1)));
+	stdarg(XmNleftAttachment, XmATTACH_FORM);
+	stdarg(XmNrightAttachment, XmATTACH_FORM);
+	stdarg(XmNtopAttachment, XmATTACH_FORM);
+	stdarg(XmNbottomAttachment, XmATTACH_FORM);
+	da = XmCreateDrawingArea(pd->form, XmStrCast(title), stdarg_args, stdarg_n);
+	XtManageChild(da);
+
+	XtAddCallback(da, XmNexposeCallback, (XtCallbackProc) show_layer_callback, (XtPointer) pd);
+	XtAddCallback(da, XmNresizeCallback, (XtCallbackProc) show_layer_callback, (XtPointer) pd);
+	XtAddCallback(da, XmNinputCallback, (XtCallbackProc) show_layer_inp_callback, (XtPointer) pd);
+
+	XtAddEventHandler(da,
+		PointerMotionMask | PointerMotionHintMask | EnterWindowMask | LeaveWindowMask,
+		0, show_layer_mot_callback, pd);
+
+	XtManageChild(pd->form);
+
+	return pd;
+}
+
+/***************** instance for layer group edit **********************/
+
+#include "stub_draw_csect.h"
+
+static PreviewData *layergrp_edit = NULL;
+
+static void layergrp_pre_close(struct PreviewData *pd)
+{
+	if (pd == layergrp_edit)
+		layergrp_edit = NULL;
+}
+
+void lesstif_show_layergrp_edit(void)
+{
+	pcb_layer_id_t lid;
+	if (layergrp_edit != NULL)
+		return;
+	if (pcb_layer_list(PCB_LYT_CSECT, &lid, 1) > 0) {
+		layergrp_edit = lesstif_show_layer(lid, "Layer groups");
+		layergrp_edit->mouse_ev = pcb_stub_draw_csect_mouse_ev;
+		layergrp_edit->overlay_draw = pcb_stub_draw_csect_overlay;
+		layergrp_edit->pre_close = layergrp_pre_close;
+	}
+}
diff --git a/src_plugins/hid_lesstif/main.c b/src_plugins/hid_lesstif/main.c
index e43317f..96a4177 100644
--- a/src_plugins/hid_lesstif/main.c
+++ b/src_plugins/hid_lesstif/main.c
@@ -54,7 +54,7 @@ const char *lesstif_cookie = "lesstif HID";
 
 pcb_hid_cfg_mouse_t lesstif_mouse;
 pcb_hid_cfg_keys_t lesstif_keymap;
-
+int lesstif_active = 0;
 
 #ifndef XtRDouble
 #define XtRDouble "Double"
@@ -115,21 +115,28 @@ static int bgred, bggreen, bgblue;
 static GC arc1_gc, arc2_gc;
 
 /* These are for the pinout windows. */
-typedef struct PinoutData {
-	struct PinoutData *prev, *next;
+typedef struct PreviewData {
+	struct PreviewData *prev, *next;
 	Widget form;
 	Window window;
 	pcb_coord_t left, right, top, bottom;	/* PCB extents of item */
 	pcb_coord_t x, y;										/* PCB coordinates of upper right corner of window */
 	double zoom;									/* PCB units per screen pixel */
 	int v_width, v_height;				/* pixels */
-	void *item;
-} PinoutData;
+
+	pcb_hid_expose_ctx_t ctx;
+	pcb_bool (*mouse_ev)(void *widget, pcb_hid_mouse_ev_t kind, pcb_coord_t x, pcb_coord_t y);
+	void (*pre_close)(struct PreviewData *pd);
+	pcb_hid_expose_t overlay_draw;
+	unsigned pan:1;
+	int pan_ox, pan_oy;
+	pcb_coord_t pan_opx, pan_opy;
+} PreviewData;
 
 /* Linked list of all pinout windows.  */
-static PinoutData *pinouts = 0;
+static PreviewData *pinouts = 0;
 /* If set, we are currently updating this pinout window.  */
-static PinoutData *pinout = 0;
+static PreviewData *pinout = 0;
 
 static int crosshair_x = 0, crosshair_y = 0;
 static int in_move_event = 0, crosshair_in_window = 1;
@@ -226,19 +233,18 @@ Location of the @file{pcb-menu.res} file which defines the menu for the lesstif
 
 PCB_REGISTER_ATTRIBUTES(lesstif_attribute_list, lesstif_cookie)
 
-		 static void lesstif_use_mask(int use_it);
-		 static void zoom_max();
-		 static void zoom_to(double factor, int x, int y);
-		 static void zoom_by(double factor, int x, int y);
-		 static void zoom_toggle(int x, int y);
-		 static void pinout_callback(Widget, PinoutData *, XmDrawingAreaCallbackStruct *);
-		 static void pinout_unmap(Widget, PinoutData *, void *);
-		 static void Pan(int mode, int x, int y);
+static void lesstif_use_mask(int use_it);
+static void zoom_max();
+static void zoom_to(double factor, int x, int y);
+static void zoom_by(double factor, int x, int y);
+static void zoom_toggle(int x, int y);
+static void pinout_callback(Widget, PreviewData *, XmDrawingAreaCallbackStruct *);
+static void pinout_unmap(Widget, PreviewData *, void *);
+static void Pan(int mode, int x, int y);
 
 /* Px converts view->pcb, Vx converts pcb->view */
 
-		 static inline int
-		   Vx(pcb_coord_t x)
+static inline int Vx(pcb_coord_t x)
 {
 	int rv = (x - view_left_x) / view_zoom + 0.5;
 	if (conf_core.editor.view.flip_x)
@@ -313,6 +319,8 @@ static const char *cur_clip()
 static void LesstifBusy(void *user_data, int argc, pcb_event_arg_t argv[])
 {
 	static Cursor busy_cursor = 0;
+	if (!lesstif_active)
+		return;
 	if (busy_cursor == 0)
 		busy_cursor = XCreateFontCursor(display, XC_watch);
 	XDefineCursor(display, window, busy_cursor);
@@ -552,14 +560,13 @@ layer group is visible and active, effectively swapping the ``working
 side'' of the board.
 
 %end-doc */
-
 static int group_showing(int g, int *c)
 {
 	int i, l;
-	*c = PCB->LayerGroups.Entries[g][0];
-	for (i = 0; i < PCB->LayerGroups.Number[g]; i++) {
-		l = PCB->LayerGroups.Entries[g][i];
-		if (l >= 0 && l < pcb_max_copper_layer) {
+	*c = PCB->LayerGroups.grp[g].lid[0];
+	for (i = 0; i < PCB->LayerGroups.grp[g].len; i++) {
+		l = PCB->LayerGroups.grp[g].lid[i];
+		if (l >= 0 && l < pcb_max_layer && (!(pcb_layer_flags(l) & PCB_LYT_SILK))) {
 			*c = l;
 			if (PCB->Data->Layer[l].On)
 				return 1;
@@ -568,16 +575,21 @@ static int group_showing(int g, int *c)
 	return 0;
 }
 
+#warning TODO: ui_zoomplan.c does the same, maybe make the code common?
 static int SwapSides(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
 	int old_shown_side = conf_core.editor.show_solder_side;
-	pcb_layergrp_id_t comp_group = pcb_layer_get_group(pcb_component_silk_layer);
-	pcb_layergrp_id_t solder_group = pcb_layer_get_group(pcb_solder_silk_layer);
+	pcb_layergrp_id_t comp_group = -1, solder_group = -1;
 	pcb_layergrp_id_t active_group = pcb_layer_get_group(pcb_layer_stack[0]);
 	int comp_layer;
 	int solder_layer;
-	int comp_showing = group_showing(comp_group, &comp_layer);
-	int solder_showing = group_showing(solder_group, &solder_layer);
+	int comp_showing = 0, solder_showing = 0;
+
+	if (pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &solder_group, 1) > 0)
+		solder_showing = group_showing(solder_group, &solder_layer);
+
+	if (pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &comp_group, 1) > 0)
+		comp_showing = group_showing(comp_group, &comp_layer);
 
 	if (argc > 0) {
 		switch (argv[0][0]) {
@@ -745,23 +757,24 @@ static int Benchmark(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
 	int i = 0;
 	time_t start, end;
-	pcb_box_t region;
+	pcb_hid_expose_ctx_t ctx;
 	Drawable save_main;
 
+
 	save_main = main_pixmap;
 	main_pixmap = window;
 
-	region.X1 = 0;
-	region.Y1 = 0;
-	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 
 	pixmap = window;
 	XSync(display, 0);
 	time(&start);
 	do {
 		XFillRectangle(display, pixmap, bg_gc, 0, 0, view_width, view_height);
-		pcb_hid_expose_callback(&lesstif_hid, &region, 0);
+		pcb_hid_expose_all(&lesstif_hid, &ctx);
 		XSync(display, 0);
 		time(&end);
 		i++;
@@ -788,93 +801,6 @@ static int Center(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 	return 0;
 }
 
-static const char cursor_syntax[] = "Cursor(Type,DeltaUp,DeltaRight,Units)";
-
-static const char cursor_help[] = "Move the cursor.";
-
-/* %start-doc actions Cursor
-
-This action moves the mouse cursor.  Unlike other actions which take
-coordinates, this action's coordinates are always relative to the
-user's view of the board.  Thus, a positive @var{DeltaUp} may move the
-cursor towards the board origin if the board is inverted.
-
-Type is one of @samp{Pan} or @samp{Warp}.  @samp{Pan} causes the
-viewport to move such that the crosshair is under the mouse cursor.
- at samp{Warp} causes the mouse cursor to move to be above the crosshair.
-
- at var{Units} can be one of the following:
-
- at table @samp
-
- at item mil
- at itemx mm
-The cursor is moved by that amount, in board units.
-
- at item grid
-The cursor is moved by that many grid points.
-
- at item view
-The values are percentages of the viewport's view.  Thus, a pan of
- at samp{100} would scroll the viewport by exactly the width of the
-current view.
-
- at item board
-The values are percentages of the board size.  Thus, a move of
- at samp{50,50} moves you halfway across the board.
-
- at end table
-
-%end-doc */
-
-static int CursorAction(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	pcb_unit_list_t extra_units_x = {
-		{"grid", 0, 0},
-		{"view", 0, UNIT_PERCENT},
-		{"board", 0, UNIT_PERCENT},
-		{"", 0, 0}
-	};
-	pcb_unit_list_t extra_units_y = {
-		{"grid", 0, 0},
-		{"view", 0, UNIT_PERCENT},
-		{"board", 0, UNIT_PERCENT},
-		{"", 0, 0}
-	};
-	int pan_warp = HID_SC_DO_NOTHING;
-	double dx, dy;
-
-	extra_units_x[0].scale = PCB->Grid;
-	extra_units_x[1].scale = Pz(view_width);
-	extra_units_x[2].scale = PCB->MaxWidth;
-
-	extra_units_y[0].scale = PCB->Grid;
-	extra_units_y[1].scale = Pz(view_height);
-	extra_units_y[2].scale = PCB->MaxHeight;
-
-	if (argc != 4)
-		PCB_AFAIL(cursor);
-
-	if (pcb_strcasecmp(argv[0], "pan") == 0)
-		pan_warp = HID_SC_PAN_VIEWPORT;
-	else if (pcb_strcasecmp(argv[0], "warp") == 0)
-		pan_warp = HID_SC_WARP_POINTER;
-	else
-		PCB_AFAIL(cursor);
-
-	dx = pcb_get_value_ex(argv[1], argv[3], NULL, extra_units_x, "mil", NULL);
-	if (conf_core.editor.view.flip_x)
-		dx = -dx;
-	dy = pcb_get_value_ex(argv[2], argv[3], NULL, extra_units_y, "mil", NULL);
-	if (!conf_core.editor.view.flip_y)
-		dy = -dy;
-
-	pcb_event_move_crosshair(pcb_crosshair.X + dx, pcb_crosshair.Y + dy);
-	pcb_gui->set_crosshair(pcb_crosshair.X, pcb_crosshair.Y, pan_warp);
-
-	return 0;
-}
-
 pcb_hid_action_t lesstif_main_action_list[] = {
 	{"SetUnits", 0, SetUnits,
 	 setunits_help, setunits_syntax}
@@ -896,9 +822,6 @@ pcb_hid_action_t lesstif_main_action_list[] = {
 	,
 	{"Center", "Click on a location to center", Center}
 	,
-	{"Cursor", 0, CursorAction,
-	 cursor_help, cursor_syntax}
-	,
 };
 
 PCB_REGISTER_ACTIONS(lesstif_main_action_list, lesstif_cookie)
@@ -2358,29 +2281,30 @@ static Boolean idle_proc(XtPointer dummy)
 {
 	if (need_redraw) {
 		int mx, my;
-		pcb_box_t region;
+		pcb_hid_expose_ctx_t ctx;
+
 		lesstif_use_mask(0);
 		pixmap = main_pixmap;
 		mx = view_width;
 		my = view_height;
-		region.X1 = Px(0);
-		region.Y1 = Py(0);
-		region.X2 = Px(view_width);
-		region.Y2 = Py(view_height);
+		ctx.view.X1 = Px(0);
+		ctx.view.Y1 = Py(0);
+		ctx.view.X2 = Px(view_width);
+		ctx.view.Y2 = Py(view_height);
 		if (conf_core.editor.view.flip_x) {
-			pcb_coord_t tmp = region.X1;
-			region.X1 = region.X2;
-			region.X2 = tmp;
+			pcb_coord_t tmp = ctx.view.X1;
+			ctx.view.X1 = ctx.view.X2;
+			ctx.view.X2 = tmp;
 		}
 		if (conf_core.editor.view.flip_y) {
-			pcb_coord_t tmp = region.Y1;
-			region.Y1 = region.Y2;
-			region.Y2 = tmp;
+			pcb_coord_t tmp = ctx.view.Y1;
+			ctx.view.Y1 = ctx.view.Y2;
+			ctx.view.Y2 = tmp;
 		}
 		XSetForeground(display, bg_gc, bgcolor);
 		XFillRectangle(display, main_pixmap, bg_gc, 0, 0, mx, my);
 
-		if (region.X1 < 0 || region.Y1 < 0 || region.X2 > PCB->MaxWidth || region.Y2 > PCB->MaxHeight) {
+		if (ctx.view.X1 < 0 || ctx.view.Y1 < 0 || ctx.view.X2 > PCB->MaxWidth || ctx.view.Y2 > PCB->MaxHeight) {
 			int leftmost, rightmost, topmost, bottommost;
 
 			leftmost = Vx(0);
@@ -2427,7 +2351,7 @@ static Boolean idle_proc(XtPointer dummy)
 			}
 		}
 		DrawBackgroundImage();
-		pcb_hid_expose_callback(&lesstif_hid, &region, 0);
+		pcb_hid_expose_all(&lesstif_hid, &ctx);
 		draw_grid();
 		lesstif_use_mask(0);
 		show_crosshair(0);					/* To keep the drawn / not drawn info correct */
@@ -2810,13 +2734,13 @@ static int lesstif_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer
 {
 	int idx = group;
 	if (idx >= 0 && idx < pcb_max_group) {
-		int n = PCB->LayerGroups.Number[group];
+		int n = PCB->LayerGroups.grp[group].len;
 		for (idx = 0; idx < n - 1; idx++) {
-			int ni = PCB->LayerGroups.Entries[group][idx];
-			if (ni >= 0 && ni < pcb_max_copper_layer + 2 && PCB->Data->Layer[ni].On)
+			int ni = PCB->LayerGroups.grp[group].lid[idx];
+			if (ni >= 0 && ni < pcb_max_layer && PCB->Data->Layer[ni].On)
 				break;
 		}
-		idx = PCB->LayerGroups.Entries[group][idx];
+		idx = PCB->LayerGroups.grp[group].lid[idx];
 #if 0
 		if (idx == pcb_layer_stack[0]
 				|| pcb_layer_get_group(idx) == pcb_layer_get_group(pcb_layer_stack[0]))
@@ -2830,17 +2754,25 @@ static int lesstif_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer
 		autofade = 0;
 #endif
 
+	/* layers that need special visibility rules */
+	switch (flags & PCB_LYT_ANYTHING) {
+		case PCB_LYT_MASK:
+			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags) && !pinout)
+				return conf_core.editor.show_mask;
+			return 0;
+		case PCB_LYT_PASTE: /* Never draw the paste layer */
+			return 0;
+	}
+
+	/* normal layers */
 	if (flags & PCB_LYT_COPPER)
 		return pinout ? 1 : PCB->Data->Layer[idx].On;
 
+	/* virtual layers */
 	{
 		switch (flags & PCB_LYT_ANYTHING) {
 		case PCB_LYT_INVIS:
 			return pinout ? 0 : PCB->InvisibleObjectsOn;
-		case PCB_LYT_MASK:
-			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags) && !pinout)
-				return conf_core.editor.show_mask;
-			return 0;
 		case PCB_LYT_SILK:
 			if (PCB_LAYERFLG_ON_VISIBLE_SIDE(flags) || pinout) {
 				return PCB->ElementOn;
@@ -3096,6 +3028,12 @@ static void lesstif_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pc
 	height = Vz(height);
 	cx = Vx(cx) - width;
 	cy = Vy(cy) - height;
+
+	if ((delta_angle >= 360.0) || (delta_angle <= -360.0)) {
+		start_angle = 0;
+		delta_angle = 360;
+	}
+
 	if (conf_core.editor.view.flip_x) {
 		start_angle = 180 - start_angle;
 		delta_angle = -delta_angle;
@@ -3463,9 +3401,8 @@ extern void lesstif_report_dialog(const char *title, const char *msg);
 extern int
 lesstif_attribute_dialog(pcb_hid_attribute_t * attrs, int n_attrs, pcb_hid_attr_val_t * results, const char *title, const char *descr);
 
-static void pinout_callback(Widget da, PinoutData * pd, XmDrawingAreaCallbackStruct * cbs)
+static void pinout_callback(Widget da, PreviewData * pd, XmDrawingAreaCallbackStruct * cbs)
 {
-	pcb_box_t region;
 	int save_vx, save_vy, save_vw, save_vh;
 	int save_fx, save_fy;
 	double save_vz;
@@ -3513,13 +3450,13 @@ static void pinout_callback(Widget da, PinoutData * pd, XmDrawingAreaCallbackStr
 	use_mask = 0;
 	conf_force_set_bool(conf_core.editor.view.flip_x, 0);
 	conf_force_set_bool(conf_core.editor.view.flip_y, 0);
-	region.X1 = 0;
+/*	region.X1 = 0;
 	region.Y1 = 0;
 	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	region.Y2 = PCB->MaxHeight;*/
 
 	XFillRectangle(display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height);
-	pcb_hid_expose_callback(&lesstif_hid, &region, pd->item);
+	pcb_hid_expose_pinout(&lesstif_hid, &pd->ctx);
 
 	pinout = 0;
 	view_left_x = save_vx;
@@ -3532,7 +3469,7 @@ static void pinout_callback(Widget da, PinoutData * pd, XmDrawingAreaCallbackStr
 	conf_force_set_bool(conf_core.editor.view.flip_y, save_fy);
 }
 
-static void pinout_unmap(Widget w, PinoutData * pd, void *v)
+static void pinout_unmap(Widget w, PreviewData * pd, void *v)
 {
 	if (pd->prev)
 		pd->prev->next = pd->next;
@@ -3549,19 +3486,19 @@ static void lesstif_show_item(void *item)
 	double scale;
 	Widget da;
 	pcb_box_t *extents;
-	PinoutData *pd;
+	PreviewData *pd;
 
 	for (pd = pinouts; pd; pd = pd->next)
-		if (pd->item == item)
+		if (pd->ctx.content.elem == item)
 			return;
 	if (!mainwind)
 		return;
 
-	pd = (PinoutData *) calloc(1, sizeof(PinoutData));
+	pd = (PreviewData *) calloc(1, sizeof(PreviewData));
 
-	pd->item = item;
+	pd->ctx.content.elem = item;
 
-	extents = pcb_hid_get_extents(item);
+	extents = pcb_hid_get_extents_pinout(&pd->ctx);
 	pd->left = extents->X1;
 	pd->right = extents->X2;
 	pd->top = extents->Y1;
@@ -3602,6 +3539,8 @@ static void lesstif_show_item(void *item)
 	pinout = 0;
 }
 
+#include "dlg_preview.c"
+
 static void lesstif_beep(void)
 {
 	putchar(7);
@@ -3750,6 +3689,13 @@ static void lesstif_finish_debug_draw(void)
 	 */
 }
 
+static void lesstif_get_view_size(pcb_coord_t *width, pcb_coord_t *height)
+{
+	*width = Pz(view_width);
+	*width = Pz(view_height);
+}
+
+
 static int lesstif_usage(const char *topic)
 {
 	fprintf(stderr, "\nLesstif GUI command line arguments:\n\n");
@@ -3810,6 +3756,7 @@ pcb_uninit_t hid_hid_lesstif_init()
 	lesstif_hid.control_is_pressed = lesstif_control_is_pressed;
 	lesstif_hid.mod1_is_pressed = lesstif_mod1_is_pressed;
 	lesstif_hid.get_coords = lesstif_get_coords;
+	lesstif_hid.get_view_size = lesstif_get_view_size;
 	lesstif_hid.set_crosshair = lesstif_set_crosshair;
 	lesstif_hid.add_timer = lesstif_add_timer;
 	lesstif_hid.stop_timer = lesstif_stop_timer;
@@ -3851,6 +3798,7 @@ pcb_uninit_t hid_hid_lesstif_init()
 	return hid_lesstif_uninit;
 }
 
+
 static void lesstif_begin(void)
 {
 	PCB_REGISTER_ACTIONS(lesstif_library_action_list, lesstif_cookie)
@@ -3860,10 +3808,12 @@ static void lesstif_begin(void)
 	PCB_REGISTER_ACTIONS(lesstif_netlist_action_list, lesstif_cookie)
 	PCB_REGISTER_ACTIONS(lesstif_menu_action_list, lesstif_cookie)
 	PCB_REGISTER_ACTIONS(lesstif_styles_action_list, lesstif_cookie)
+	lesstif_active = 1;
 }
 
 static void lesstif_end(void)
 {
 	pcb_hid_remove_actions_by_cookie(lesstif_cookie);
 	pcb_hid_remove_attributes_by_cookie(lesstif_cookie);
+	lesstif_active = 0;
 }
diff --git a/src_plugins/hid_lesstif/menu.c b/src_plugins/hid_lesstif/menu.c
index 54ad821..519a6e8 100644
--- a/src_plugins/hid_lesstif/menu.c
+++ b/src_plugins/hid_lesstif/menu.c
@@ -169,7 +169,7 @@ void LesstifLayersChanged(void *user_data, int argc, pcb_event_arg_t argv[])
 			}
 			XtSetValues(lb->w[i], stdarg_args, stdarg_n);
 
-			if (i >= pcb_max_copper_layer && i < PCB_MAX_LAYER)
+			if ((i >= pcb_max_layer && i < PCB_MAX_LAYER) || (pcb_layer_flags(i) & PCB_LYT_SILK))
 				XtUnmanageChild(lb->w[i]);
 			else
 				XtManageChild(lb->w[i]);
@@ -252,12 +252,12 @@ static void layer_button_callback(Widget w, int layer, XmPushButtonCallbackStruc
 	}
 
 	show_one_layer_button(layer, set);
-	if (layer < pcb_max_copper_layer) {
+	if ((layer < pcb_max_layer) && (!(pcb_layer_flags(layer) & PCB_LYT_SILK))) {
 		int i;
 		pcb_layergrp_id_t group = pcb_layer_get_group(layer);
-		for (i = 0; i < PCB->LayerGroups.Number[group]; i++) {
-			l = PCB->LayerGroups.Entries[group][i];
-			if (l != layer && l < pcb_max_copper_layer) {
+		for (i = 0; i < PCB->LayerGroups.grp[group].len; i++) {
+			l = PCB->LayerGroups.grp[group].lid[i];
+			if (l != layer && (!(pcb_layer_flags(l) & PCB_LYT_SILK))) {
 				show_one_layer_button(l, set);
 				PCB->Data->Layer[l].On = set;
 			}
@@ -272,7 +272,7 @@ static void layerpick_button_callback(Widget w, int layer, XmPushButtonCallbackS
 	const char *name;
 	PCB->RatDraw = (layer == LB_RATS);
 	PCB->SilkActive = (layer == LB_SILK);
-	if (layer < pcb_max_copper_layer)
+	if ((layer < pcb_max_layer) && (!(pcb_layer_flags(layer) & PCB_LYT_SILK)))
 		pcb_layervis_change_group_vis(layer, 1, 1);
 	for (l = 0; l < num_layer_buttons; l++) {
 		LayerButtons *lb = layer_button_list + l;
@@ -368,7 +368,7 @@ static int ToggleView(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 		layer_button_callback(0, LB_BACK, 0);
 	else {
 		l = -1;
-		for (i = 0; i < pcb_max_copper_layer + 2; i++)
+		for (i = 0; i < pcb_max_layer; i++)
 			if (strcmp(argv[0], PCB->Data->Layer[i].Name) == 0) {
 				l = i;
 				break;
@@ -396,17 +396,14 @@ static void insert_layerview_buttons(Widget menu)
 	for (i = 0; i < LB_NUM; i++) {
 		static char namestr[] = "Label ";
 		const char *name = namestr;
-		/*int accel_idx = i;*/
 		Widget btn;
 		namestr[5] = 'A' + i;
 		switch (i) {
 		case LB_SILK:
 			name = "Silk";
-			/*accel_idx = pcb_max_copper_layer;*/
 			break;
 		case LB_RATS:
 			name = "Rat Lines";
-			/*accel_idx = pcb_max_copper_layer + 1;*/
 			break;
 		case LB_PINS:
 			name = "Pins/Pads";
@@ -428,7 +425,7 @@ static void insert_layerview_buttons(Widget menu)
 		lb->w[i] = btn;
 
 		if (i == LB_MASK)
-			note_widget_flag(btn, XmNset, "showmask");
+			note_widget_flag(btn, XmNset, "editor/show_mask");
 	}
 	lb->is_pick = 0;
 	LesstifLayersChanged(0, 0, 0);
@@ -450,19 +447,16 @@ static void insert_layerpick_buttons(Widget menu)
 	for (i = 0; i < LB_NUMPICK; i++) {
 		static char namestr[] = "Label ";
 		const char *name = namestr;
-		/*int accel_idx = i;*/
 		char av[30];
 		Widget btn;
 		namestr[5] = 'A' + i;
 		switch (i) {
 		case LB_SILK:
 			name = "Silk";
-			/*accel_idx = pcb_max_copper_layer;*/
 			strcpy(av, "SelectLayer(Silk)");
 			break;
 		case LB_RATS:
 			name = "Rat Lines";
-			/*accel_idx = pcb_max_copper_layer + 1;*/
 			strcpy(av, "SelectLayer(Rats)");
 			break;
 		default:
diff --git a/src_plugins/hid_remote/proto.c b/src_plugins/hid_remote/proto.c
index 9ea1edd..2e62436 100644
--- a/src_plugins/hid_remote/proto.c
+++ b/src_plugins/hid_remote/proto.c
@@ -31,6 +31,7 @@
 #include "proto_lowsend.h"
 #include "proto_lowparse.h"
 #include "layer.h"
+#include "layer_grp.h"
 
 static const int proto_ver = 1;
 static proto_ctx_t pctx;
@@ -101,12 +102,11 @@ void proto_send_invalidate_all()
 	send_end(&pctx);
 }
 
-int proto_send_set_layer_group(pcb_layergrp_id_t group, unsigned int flags, int is_empty)
+int proto_send_set_layer_group(pcb_layergrp_id_t group, int is_empty)
 {
 	send_begin(&pctx, "setlg");
 	send_open(&pctx, 0, 1);
 	sendf(&pctx, "%ld", group);
-	sendf(&pctx, "%lx", flags);
 	sendf(&pctx, "%d", is_empty);
 	send_close(&pctx);
 	send_end(&pctx);
@@ -127,10 +127,9 @@ static void	pcb_remote_send_layer_flags(unsigned int flags, int first_arg)
 	send_close(&pctx);
 }
 
-
-int pcb_remote_new_layer(const char *name, int idx, unsigned int flags, unsigned int group)
+int pcb_remote_new_layer_group(const char *name, pcb_layergrp_id_t idx, unsigned int flags)
 {
-	send_begin(&pctx, "newly");
+	send_begin(&pctx, "newlg");
 	send_open(&pctx, str_is_bin(name), 1);
 	sends(&pctx, name);
 	sendf(&pctx, "%d", idx);
@@ -139,7 +138,19 @@ int pcb_remote_new_layer(const char *name, int idx, unsigned int flags, unsigned
 	pcb_remote_send_layer_flags(flags & PCB_LYT_ANYTHING, 0);
 	pcb_remote_send_layer_flags(flags & PCB_LYT_ANYPROP, 0);
 	send_close(&pctx);
-	sendf(&pctx, "%d", group);
+	send_close(&pctx);
+	send_end(&pctx);
+	return 0;
+}
+
+
+int pcb_remote_new_layer(const char *name, pcb_layer_id_t lid, unsigned int gid)
+{
+	send_begin(&pctx, "newly");
+	send_open(&pctx, str_is_bin(name), 1);
+	sends(&pctx, name);
+	sendf(&pctx, "%ld", lid);
+	sendf(&pctx, "%ld", gid);
 	send_close(&pctx);
 	send_end(&pctx);
 	return 0;
@@ -229,6 +240,23 @@ void proto_send_draw_line(int gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2
 	send_end(&pctx);
 }
 
+void proto_send_draw_arc(int gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t width, pcb_coord_t height, pcb_angle_t start_angle, pcb_angle_t delta_angle)
+{
+	send_begin(&pctx, "arc");
+	send_open(&pctx, 0, 1);
+	sendf(&pctx, "%d", gc);
+	sendf(&pctx, cfmt, cx);
+	sendf(&pctx, cfmt, cy);
+	sendf(&pctx, cfmt, width);
+	sendf(&pctx, cfmt, height);
+	sendf(&pctx, "%f", start_angle);
+	sendf(&pctx, "%f", delta_angle);
+	send_close(&pctx);
+	send_end(&pctx);
+}
+
+
+
 void proto_send_draw_rect(int gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2, int is_filled)
 {
 	send_begin(&pctx, "rect");
diff --git a/src_plugins/hid_remote/proto.h b/src_plugins/hid_remote/proto.h
index 37f0bc3..b64b9e9 100644
--- a/src_plugins/hid_remote/proto.h
+++ b/src_plugins/hid_remote/proto.h
@@ -29,8 +29,11 @@ void remote_proto_send_unit();
 int remote_proto_send_ready();
 void proto_send_invalidate(int l, int r, int t, int b);
 void proto_send_invalidate_all();
-int proto_send_set_layer_group(pcb_layergrp_id_t group, unsigned int flags, int is_empty);
-int pcb_remote_new_layer(const char *name, int idx, unsigned int flags, unsigned int group);
+
+int pcb_remote_new_layer_group(const char *name, pcb_layergrp_id_t idx, unsigned int flags);
+int pcb_remote_new_layer(const char *name, pcb_layer_id_t idx, unsigned int group);
+int proto_send_set_layer_group(pcb_layergrp_id_t group, int is_empty);
+
 int proto_send_make_gc(void);
 int proto_send_del_gc(int gc);
 void proto_send_set_color(int gc, const char *name);
@@ -38,6 +41,7 @@ void proto_send_set_line_cap(int gc, char style);
 void proto_send_set_line_width(int gc, pcb_coord_t width);
 void proto_send_set_draw_xor(int gc, int xor_set);
 void proto_send_draw_line(int gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2);
+void proto_send_draw_arc(int gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t width, pcb_coord_t height, pcb_angle_t start_angle, pcb_angle_t delta_angle);
 void proto_send_draw_rect(int gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2, int is_filled);
 void proto_send_fill_circle(int gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t radius);
 void proto_send_draw_poly(int gc, int n_coords, pcb_coord_t * x, pcb_coord_t * y);
diff --git a/src_plugins/hid_remote/proto_lowsend.h b/src_plugins/hid_remote/proto_lowsend.h
index 05379b8..41c62f4 100644
--- a/src_plugins/hid_remote/proto_lowsend.h
+++ b/src_plugins/hid_remote/proto_lowsend.h
@@ -151,7 +151,7 @@ static int str_is_bin(const char *str)
 	if ((str == NULL) || (*str == '\0')) /* empty string can be encoded in bin only */
 		return 1;
 	for(s = str, l = 0; *s != '\0'; s++,l++)
-		if ((l > 16) && (chr_is_bin(*s)))
+		if ((l > 16) || (chr_is_bin(*s)))
 			return 1;
 	return 0;
 }
diff --git a/src_plugins/hid_remote/remote.c b/src_plugins/hid_remote/remote.c
index d437a14..d58934b 100644
--- a/src_plugins/hid_remote/remote.c
+++ b/src_plugins/hid_remote/remote.c
@@ -63,13 +63,35 @@ PCB_REGISTER_ACTIONS(remote_action_list, remote_cookie)
 static void remote_send_all_layers()
 {
 	pcb_layer_id_t arr[128];
+	pcb_layergrp_id_t garr[128];
 	int n, used;
 
+	used = pcb_layer_group_list_any(PCB_LYT_ANYTHING | PCB_LYT_ANYWHERE | PCB_LYT_VIRTUAL, garr, sizeof(garr)/sizeof(garr[0]));
+	for(n = 0; n < used; n++) {
+		pcb_layergrp_id_t gid = garr[n];
+		pcb_remote_new_layer_group(pcb_layergrp_name(gid), gid, pcb_layergrp_flags(gid));
+	}
+
 	used = pcb_layer_list_any(PCB_LYT_ANYTHING | PCB_LYT_ANYWHERE | PCB_LYT_VIRTUAL, arr, sizeof(arr)/sizeof(arr[0]));
+
+#warning layer TODO: remove this temporary hack for virtual layers
 	for(n = 0; n < used; n++) {
+		const char *name;
 		pcb_layer_id_t layer_id = arr[n];
-		pcb_layergrp_id_t grp = pcb_layer_get_group(layer_id);
-		pcb_remote_new_layer(pcb_layer_name(layer_id), layer_id, pcb_layer_flags(layer_id), grp);
+		pcb_layergrp_id_t gid = pcb_layer_get_group(layer_id);
+		name = pcb_layer_name(layer_id);
+		if ((gid < 0) && (name != NULL)) {
+			pcb_remote_new_layer_group(name, layer_id, pcb_layer_flags(layer_id));
+			pcb_remote_new_layer(name, layer_id, layer_id);
+		}
+	}
+
+
+	for(n = 0; n < used; n++) {
+		pcb_layer_id_t lid = arr[n];
+		pcb_layergrp_id_t gid = pcb_layer_get_group(lid);
+		if (gid >= 0)
+			pcb_remote_new_layer(pcb_layer_name(lid), lid, gid);
 	}
 }
 
@@ -78,11 +100,12 @@ static void remote_send_all_layers()
 static int remote_stay;
 static void remote_do_export(pcb_hid_attr_val_t * options)
 {
-	pcb_box_t region;
-	region.X1 = 0;
-	region.Y1 = 0;
-	region.X2 = PCB->MaxWidth;
-	region.Y2 = PCB->MaxHeight;
+	pcb_hid_expose_ctx_t ctx;
+
+	ctx.view.X1 = 0;
+	ctx.view.Y1 = 0;
+	ctx.view.X2 = PCB->MaxWidth;
+	ctx.view.Y2 = PCB->MaxHeight;
 
 #warning TODO: wait for a connection?
 	remote_proto_send_ver();
@@ -92,7 +115,7 @@ static void remote_do_export(pcb_hid_attr_val_t * options)
 	if (remote_proto_send_ready() != 0)
 		exit(1);
 
-	pcb_hid_expose_callback(&remote_hid, &region, 0);
+	pcb_hid_expose_all(&remote_hid, &ctx);
 
 /* main loop, parser */
 	if (remote_proto_parse_all() != 0)
@@ -121,7 +144,17 @@ static void remote_invalidate_all(void)
 
 static int remote_set_layer_group(pcb_layergrp_id_t group, pcb_layer_id_t layer, unsigned int flags, int is_empty)
 {
-	proto_send_set_layer_group(group, flags, is_empty);
+	if (flags & PCB_LYT_UI) /* do not draw UI layers yet, we didn't create them */
+		return 0;
+	if (flags & PCB_LYT_CSECT) /* do not draw cross-sect, we didn't create them */
+		return 0;
+	if (group >= 0)
+		proto_send_set_layer_group(group, is_empty);
+	else {
+#warning layer TODO: remove this temporary hack for virtual layers
+		proto_send_set_layer_group(layer, is_empty);
+	}
+
 	return 1; /* do draw */
 }
 
@@ -231,9 +264,11 @@ static void remote_draw_line(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pc
 		proto_send_draw_line(idx, x1, y1, x2, y2);
 }
 
-static void remote_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t width, pcb_coord_t height, pcb_angle_t start_angle, pcb_angle_t end_angle)
+static void remote_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t width, pcb_coord_t height, pcb_angle_t start_angle, pcb_angle_t delta_angle)
 {
-#warning TODO
+	int idx = gc2idx(gc);
+	if (idx >= 0)
+		proto_send_draw_arc(idx, cx, cy, width, height, start_angle, delta_angle);
 }
 
 static void remote_draw_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2)
diff --git a/src_plugins/import_dsn/README b/src_plugins/import_dsn/README
index 1825fb1..175a0b1 100644
--- a/src_plugins/import_dsn/README
+++ b/src_plugins/import_dsn/README
@@ -1,5 +1,5 @@
 Import specctra .dsn files
 
-#state: Work-in-progress
-#default: disable
+#state: works
+#default: enabled
 #implements: import
diff --git a/src_plugins/import_dsn/dsn.c b/src_plugins/import_dsn/dsn.c
index 6a7fecd..eb8c784 100644
--- a/src_plugins/import_dsn/dsn.c
+++ b/src_plugins/import_dsn/dsn.c
@@ -1,10 +1,10 @@
 /*
  *                            COPYRIGHT
  *
- *  PCB, interactive printed circuit board design
+ *  pcb-rnd, interactive printed circuit board design
  *
  *  Specctra .dsn import HID
- *  Copyright (C) 2008, 2011 Josh Jordan, Dan McMahill, and Jared Casper
+ *  Copyright (C) 2017 Tibor 'Igor2' Palinkas
  *
  *  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
@@ -22,12 +22,6 @@
  *
  */
 
-/*
-This program imports specctra .dsn files to geda .pcb files.
-By Josh Jordan and Dan McMahill, modified from bom.c
-  -- Updated to use Coord and other fixes by Jared Casper 16 Sep 2011
-*/
-
 #include "config.h"
 
 #include <stdio.h>
@@ -35,126 +29,261 @@ By Josh Jordan and Dan McMahill, modified from bom.c
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <gensexpr/gsxl.h>
 
 #include "board.h"
 #include "data.h"
-#include "error.h"
-#include "rats.h"
-#include "buffer.h"
-#include "change.h"
-#include "draw.h"
-#include "undo.h"
-#include "pcb-printf.h"
 #include "polygon.h"
-#include "compat_misc.h"
-#include "compat_nls.h"
-#include "obj_pinvia.h"
-#include "obj_rat.h"
 
 #include "action_helper.h"
 #include "hid.h"
-#include "hid_draw_helpers.h"
-#include "hid_nogui.h"
-#include "hid_actions.h"
-#include "hid_init.h"
-#include "hid_attrib.h"
-#include "hid_helper.h"
 #include "plugins.h"
 
 static const char *dsn_cookie = "dsn importer";
 
-/* dsn name */
-#define FREE(x) if((x) != NULL) { free (x); (x) = NULL; }
+typedef enum {
+	TYPE_PCB,
+	TYPE_SESSION
+} dsn_type_t;
 
-static const char load_dsn_syntax[] = "LoadDsnFrom(filename)";
+static void parse_polyline(long int *nlines, pcb_coord_t clear, const gsxl_node_t *n, const char *unit, int workaround0)
+{
+	const gsxl_node_t *c;
+	pcb_coord_t x, y, lx, ly, thick;
+	long pn;
+	const char *slayer = n->children->str;
+	const char *sthick = n->children->next->str;
+	pcb_bool succ;
+	pcb_layer_id_t lid;
+	pcb_layer_t *layer;
+
+	thick = pcb_get_value(sthick, unit, NULL, &succ);
+	if (!succ) {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: skipping polyline because thickness is invalid: %s\n", sthick);
+		return;
+	}
+
+	lid = pcb_layer_by_name(slayer);
+	if (lid < 0) {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: skipping polyline because layer name is invalid: %s\n", slayer);
+		return;
+	}
+	layer = PCB->Data->Layer+lid;
 
-static const char load_dsn_help[] = "Loads the specified dsn resource file.";
+	/*printf("- %s\n", slayer);*/
+	for(pn = 0, c = n->children->next->next; c != NULL; pn++, c = c->next->next) {
+		const char *sx = c->str;
+		const char *sy = c->next->str;
+		x = pcb_get_value(sx, unit, NULL, &succ);
+		if (!succ) {
+			pcb_message(PCB_MSG_ERROR, "import_dsn: skipping polyline segment because x coord is invalid: %s\n", sx);
+			return;
+		}
+		y = pcb_get_value(sy, unit, NULL, &succ);
+		if (!succ) {
+			pcb_message(PCB_MSG_ERROR, "import_dsn: skipping polyline segment because x coord is invalid: %s\n", sy);
+			return;
+		}
+		if (workaround0 && ((y < PCB_MM_TO_COORD(0.01)) || (x < PCB_MM_TO_COORD(0.01)))) /* workaround for broken polyline coords */
+			return;
+		(*nlines)++;
+		if (pn > 0) {
+			pcb_line_t *line = pcb_line_new_merge(layer, lx, PCB->MaxHeight - ly,
+				x, PCB->MaxHeight - y, thick, clear, pcb_flag_make(PCB_FLAG_AUTO | PCB_FLAG_CLEARLINE));
+/*				pcb_poly_clear_from_poly(PCB->Data, PCB_TYPE_LINE, layer, line);*/
+/*				pcb_printf("LINE: %$mm %$mm .. %$mm %$mm\n", lx, ly, x, y);*/
+		}
+		lx = x;
+		ly = y;
+	}
+}
 
-/* %start-doc actions LoaddsnFrom
+static void parse_wire(long int *nlines, pcb_coord_t clear, const gsxl_node_t *wire, dsn_type_t type)
+{
+	const gsxl_node_t *n;
+	for(n = wire->children; n != NULL; n = n->next) {
+		if ((type == TYPE_PCB) && (strcmp(n->str, "polyline_path") == 0))
+			parse_polyline(nlines, clear, n, "mm", 1);
+		else if ((type == TYPE_SESSION) && (strcmp(n->str, "path") == 0))
+			parse_polyline(nlines, clear, n, "nm", 0);
+		else if (strcmp(n->str, "net") == 0) {
+			/* ignore */
+		}
+		else if (strcmp(n->str, "type") == 0) {
+			/* ignore */
+		}
+		else if (strcmp(n->str, "clearance_class") == 0) {
+			/* ignore */
+		}
+		else
+			pcb_message(PCB_MSG_WARNING, "import_dsn: ignoring unknown wire directive %s\n", n->str);
+	}
+}
+
+static void parse_via(pcb_coord_t clear, const gsxl_node_t *via, dsn_type_t type)
+{
+	const gsxl_node_t *c = via->children->next;
+	const char *name = via->children->str;
+	const char *sx = c->str;
+	const char *sy = c->next->str;
+	pcb_bool succ;
+	pcb_coord_t x, y, dia, drill;
+	const char *unit = (type == TYPE_PCB) ? "mm" : "nm";
+
+	if (strncmp(name, "via_", 4) != 0) {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: skipping via with invalid name (prefix): %s\n", name);
+		return;
+	}
+
+	name += 4;
+	if (sscanf(name, "%ld_%ld", &dia, &drill) != 2) {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: skipping via with invalid name (diameters): %s\n", name);
+		return;
+	}
+
+	x = pcb_get_value(sx, unit, NULL, &succ);
+	if (!succ) {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: skipping via segment because x coord is invalid: %s\n", sx);
+		return;
+	}
+	y = pcb_get_value(sy, unit, NULL, &succ);
+	if (!succ) {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: skipping via segment because x coord is invalid: %s\n", sy);
+		return;
+	}
 
- at cindex Specctra routed import
- at findex LoadDsnFrom()
+	pcb_via_new(PCB->Data, x, PCB->MaxHeight - y, dia, clear, 0, drill, 0, pcb_flag_make(PCB_FLAG_AUTO));
+}
 
- at table @var
- at item filename
-Name of the dsn resource file.  If not specified, the user will
-be prompted to enter one.
- at end table
+static const char load_dsn_syntax[] = "LoadDsnFrom(filename)";
 
-%end-doc */
+static const char load_dsn_help[] = "Loads the specified routed dsn file.";
 
 int pcb_act_LoadDsnFrom(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
 	const char *fname = NULL;
-	static char *default_file = NULL;
-	char str[200];
-	FILE *fp;
-	int ret;
-	pcb_coord_t dim1, dim2, x0 = 0, y0 = 0, x1, y1;
-	pcb_coord_t linethick = 0, lineclear, viadiam, viadrill;
-	char lname[200];
-	pcb_layer_t *rlayer = NULL;
-	pcb_line_t *line = NULL;
+	pcb_coord_t clear;
+	FILE *f;
+	gsxl_dom_t dom;
+	int c, seek_quote = 1;
+	long int nlines = 0, nvias = 0;
+	gsx_parse_res_t res;
+	gsxl_node_t *wiring, *w, *routes, *nout, *n;
+	dsn_type_t type;
 
 	fname = argc ? argv[0] : 0;
 
-	if (!fname || !*fname) {
-		fname = pcb_gui->fileselect(_("Load dsn routing session Resource File..."),
-														_("Picks a dsn session resource file to load.\n"
-															"This file could be generated by freeroute.net\n"),
-														default_file, ".ses", "ses", HID_FILESELECT_READ);
+	if ((fname == NULL) || (*fname == '\0')) {
+		fname = pcb_gui->fileselect(
+			"Load a routed dsn or ses file...",
+			"Select dsn or ses file to load.\nThe file could be generated using the tool downloaded from freeroute.net\n",
+			NULL, /* default file name */
+			".dsn", "dsn", HID_FILESELECT_READ);
 		if (fname == NULL)
 			PCB_AFAIL(load_dsn);
-		if (default_file != NULL) {
-			free(default_file);
-			default_file = NULL;
+	}
+
+	/* load and parse the file into a dom tree */
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: can't open %s for read\n", fname);
+		return 1;
+	}
+	gsxl_init(&dom, gsxl_node_t);
+	dom.parse.line_comment_char = '#';
+	do {
+		c = fgetc(f);
+		res = gsxl_parse_char(&dom, c);
+
+		/* Workaround: skip the unbalanced '"' in string_quote */
+		if (seek_quote && (dom.parse.used == 12) && (strncmp(dom.parse.atom, "string_quote", dom.parse.used) == 0)) {
+			do {
+				c = fgetc(f);
+			} while((c != ')') && (c != EOF));
+			res = gsxl_parse_char(&dom, ')');
+			seek_quote = 0;
 		}
+	} while(res == GSX_RES_NEXT);
+	fclose(f);
 
-		if (fname && *fname)
-			default_file = pcb_strdup(fname);
+	if (res != GSX_RES_EOE) {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: parse error in %s at %d:%d\n", fname, dom.parse.line, dom.parse.col);
+		goto error;
 	}
+	gsxl_compact_tree(&dom);
 
-	lineclear = PCB->RouteStyle.array[0].Clearance * 2;
-	fp = fopen(fname, "r");
-	if (!fp) {
-		pcb_message(PCB_MSG_ERROR, "Can't load dsn file %s for read\n", fname);
-		return 1;
+
+	/* parse the tree: find wiring */
+	clear = PCB->RouteStyle.array[0].Clearance * 2;
+	if (strcmp(dom.root->str, "PCB") == 0)
+		type = TYPE_PCB;
+	else if (strcmp(dom.root->str, "session") == 0)
+		type = TYPE_SESSION;
+	else {
+		pcb_message(PCB_MSG_ERROR, "import_dsn: s-expr is not a PCB or session\n");
+		goto error;
 	}
-	while (fgets(str, sizeof(str), fp) != NULL) {
-		/* strip trailing '\n' if it exists */
-		int len = strlen(str) - 1;
-		if (str[len] == '\n')
-			str[len] = 0;
-		ret = sscanf(str, "          (path %s %ld", lname, &dim1);
-		if (ret == 2) {
-			rlayer = 0;
-			LAYER_LOOP(PCB->Data, pcb_max_group) {
-				if (!strcmp(layer->Name, lname))
-					rlayer = layer;
+
+	switch(type) {
+		case TYPE_PCB:
+			for(wiring = dom.root->children; wiring != NULL; wiring = wiring->next)
+				if (strcmp(wiring->str, "wiring") == 0)
+					break;
+
+			if (wiring == NULL) {
+				pcb_message(PCB_MSG_ERROR, "import_dsn: s-expr does not have a wiring section\n");
+				goto error;
 			}
-			PCB_END_LOOP;
-			linethick = dim1;
-			x0 = 0;
-			y0 = 0;
-		}
-		ret = sscanf(str, "            %ld %ld", &dim1, &dim2);
-		if (ret == 2) {
-			x1 = dim1;
-			y1 = dim2;
-			if (x0 != 0 || y0 != 0) {
-				line = pcb_line_new_merge(rlayer, x0, PCB->MaxHeight - y0,
-																			x1, PCB->MaxHeight - y1, linethick, lineclear, pcb_flag_make(PCB_FLAG_AUTO | PCB_FLAG_CLEARLINE));
-				pcb_poly_clear_from_poly(PCB->Data, PCB_TYPE_LINE, rlayer, line);
+
+			/* parse wiring */
+			for(w = wiring->children; w != NULL; w = w->next) {
+				if (strcmp(w->str, "wire") == 0)
+					parse_wire(&nlines, clear, w, type);
+				if (strcmp(w->str, "via") == 0) {
+					parse_via(clear, w, type);
+					nvias++;
+				}
 			}
-			x0 = x1;
-			y0 = y1;
-		}
-		ret = sscanf(str, "        (via via_%ld_%ld %ld %ld", &viadiam, &viadrill, &dim1, &dim2);
-		if (ret == 4) {
-			pcb_via_new(PCB->Data, dim1, PCB->MaxHeight - dim2, viadiam, lineclear, 0, viadrill, 0, pcb_flag_make(PCB_FLAG_AUTO));
-		}
+			break;
+		case TYPE_SESSION:
+			for(routes = dom.root->children; routes != NULL; routes = routes->next)
+				if (strcmp(routes->str, "routes") == 0)
+					break;
+
+			if (routes == NULL) {
+				pcb_message(PCB_MSG_ERROR, "import_dsn: s-expr does not have a routes section\n");
+				goto error;
+			}
+
+			for(nout = routes->children; nout != NULL; nout = nout->next)
+				if (strcmp(nout->str, "network_out") == 0)
+					break;
+
+			if (nout == NULL) {
+				pcb_message(PCB_MSG_ERROR, "import_dsn: s-expr does not have a network_out section\n");
+				goto error;
+			}
+
+			for(n = nout->children; n != NULL; n = n->next) {
+				for(w = n->children; w != NULL; w = w->next) {
+					if (strcmp(w->str, "wire") == 0)
+						parse_wire(&nlines, clear, w, type);
+					if (strcmp(w->str, "via") == 0) {
+						parse_via(clear, w, type);
+						nvias++;
+					}
+				}
+			}
+			break;
 	}
-	fclose(fp);
+
+	pcb_message(PCB_MSG_INFO, "import_dsn: loaded %ld wires and %ld vias\n", nlines, nvias);
+
+	gsxl_uninit(&dom);
+	return 0;
+
+	error:;
+	gsxl_uninit(&dom);
 	return 0;
 }
 
@@ -166,6 +295,7 @@ PCB_REGISTER_ACTIONS(dsn_action_list, dsn_cookie)
 
 static void hid_dsn_uninit()
 {
+	pcb_hid_remove_actions_by_cookie(dsn_cookie);
 
 }
 
diff --git a/src_plugins/import_hyp/hacking.txt b/src_plugins/import_hyp/hacking.txt
new file mode 100644
index 0000000..50df3cf
--- /dev/null
+++ b/src_plugins/import_hyp/hacking.txt
@@ -0,0 +1,16 @@
+
+The hyperlynx file is read using a bison/flex scanner. The flex scanner is in hyp_l, the bison parser in hyp_y.y.  For each hyperlynx construct the parser calls the corresponding exec_* routine in parser.c. Example: if the parser encounters an arc segment, the symbol in scanner/parser is H_ARC, and the routine in parser.c is called exec_arc. 
+
+If you need a rough description of the hyperlynx format, download "bird33" from http://www.ibis.org/birds/bird33.txt . Substitute ".IBP file format" with ".HYP file format" and "SUBSTRATE_OUTLINE" with "BOARD" and you have an (old) description of the hyperlynx format.
+
+Not all CAD programs create compliant .hyp files. The most common omission is not putting quotes around a string. This causes problems if the string contains blank space or commas.
+
+If you change scanner or parser you need to revalidate. Try loading a collection of hyperlynx files generated by diverse CAD programs.
+
+The python script "gensamp" creates a sample hyperlynx file which contains line, arc and unrouted segments, polygons with and without holes, polylines with and without arcs, etc.
+
+Coding style:
+~/.indent.pro:
+  --line-length128 -brs -br -nce --tab-size2 -ut -npsl -npcs -hnl
+~/.vimrc:
+  set tabstop=2
diff --git a/src_plugins/import_hyp/import_hyp.c b/src_plugins/import_hyp/import_hyp.c
index 5485d8c..46e113d 100644
--- a/src_plugins/import_hyp/import_hyp.c
+++ b/src_plugins/import_hyp/import_hyp.c
@@ -60,15 +60,20 @@ int pcb_act_LoadhypFrom(int argc, const char **argv, pcb_coord_t x, pcb_coord_t
 
 	if ((fname == NULL) || (*fname == '\0')) {
 		fname = pcb_gui->fileselect(_("Load .hyp file..."),
-		_("Picks a hyperlynx file to load.\n"),
-		"default.hyp", ".hyp", "hyp", HID_FILESELECT_READ);
+																_("Picks a hyperlynx file to load.\n"), "default.hyp", ".hyp", "hyp", HID_FILESELECT_READ);
 	}
 
 	if (fname == NULL)
 		PCB_AFAIL(load_hyp);
 
 
-	/* debug level */
+	/* 
+   * debug level.
+   * one "debug" argument: hyperlynx logging.
+   * two "debug" arguments: hyperlynx and bison logging.
+   * three "debug" arguments: hyperlynx, bison and flex logging.
+   */
+
 	for (i = 0; i < argc; i++)
 		debug += (strcmp(argv[i], "debug") == 0);
 
@@ -87,9 +92,9 @@ pcb_hid_action_t hyp_action_list[] = {
 
 PCB_REGISTER_ACTIONS(hyp_action_list, hyp_cookie)
 
-static void hid_hyp_uninit()
+static void hid_import_hyp_uninit()
 {
-
+	pcb_hid_remove_actions_by_cookie(hyp_cookie);
 }
 
 #include "dolists.h"
@@ -97,7 +102,7 @@ pcb_uninit_t hid_import_hyp_init()
 {
 #warning TODO: rather register an importer than an action
 	PCB_REGISTER_ACTIONS(hyp_action_list, hyp_cookie)
-	return hid_hyp_uninit;
+	return hid_import_hyp_uninit;
 }
 
 /* not truncated */
diff --git a/src_plugins/import_hyp/parser.c b/src_plugins/import_hyp/parser.c
index 3f2ecd8..673d44f 100644
--- a/src_plugins/import_hyp/parser.c
+++ b/src_plugins/import_hyp/parser.c
@@ -18,6 +18,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/* 
+ * ~/.indent.pro:
+ *   --line-length128 -brs -br -nce --tab-size2 -ut -npsl -npcs -hnl
+ * ~/.vimrc:
+ *   set tabstop=2
+ */
+
 #include "parser.h"
 #include "hyp_l.h"
 #include "hyp_y.h"
@@ -25,13 +32,17 @@
 #include "pcb-printf.h"
 #include "obj_all.h"
 #include "flag_str.h"
+#include "polygon.h"
 #include "board.h"
 #include "layer.h"
 #include "data.h"
+#include "search.h"
+#include "compat_misc.h"
 
 /*
  * the board is shared between all routines.
  */
+
 pcb_data_t *hyp_dest;
 
 /*
@@ -39,63 +50,123 @@ pcb_data_t *hyp_dest;
  */
 
 typedef struct outline_s {
-  pcb_coord_t x1;
-  pcb_coord_t y1;
-  pcb_coord_t x2;
-  pcb_coord_t y2;
-  pcb_coord_t xc;
-  pcb_coord_t yc;
-  pcb_coord_t r;
-  pcb_bool_t is_arc; /* arc or line */
-  pcb_bool_t used; /* already included in outline */
-  struct outline_s *next;
-  } outline_t;
+	pcb_coord_t x1;
+	pcb_coord_t y1;
+	pcb_coord_t x2;
+	pcb_coord_t y2;
+	pcb_coord_t xc;
+	pcb_coord_t yc;
+	pcb_coord_t r;
+	pcb_bool_t is_arc;						/* arc or line */
+	pcb_bool_t used;							/* already included in outline */
+	struct outline_s *next;
+} outline_t;
 
 outline_t *outline_head;
 outline_t *outline_tail;
 
-void hyp_set_origin(); /* set origin so all coordinates are positive */
-void hyp_perimeter(); /* add board outline to pcb */
+void hyp_set_origin();					/* set origin so all coordinates are positive */
+void hyp_perimeter();						/* add board outline to pcb */
+void hyp_create_polygons();			/* add all created polygons to pcb */
 
-int hyp_debug; /* logging on/off switch */
+int hyp_debug;									/* logging on/off switch */
 
 /* Physical constants */
-double inches;                 /* inches to m */
-double copper_imperial_weight; /* metal thickness in ounces/ft2 */
-double copper_metric_weight;   /* metal thickness in grams/cm2 */
-double copper_bulk_resistivity; /* metal resistivity in ohm meter */
-double copper_temperature_coefficient; /* temperature coefficient of bulk resistivity */
-double fr4_epsilon_r;          /* dielectric constant of substrate */
-double fr4_loss_tangent;       /* loss tangent of substrate */
-double conformal_epsilon_r;    /* dielectric constant of conformal coating */
-  
+double inches;									/* inches to m */
+double copper_imperial_weight;	/* metal thickness in ounces/ft2 */
+double copper_metric_weight;		/* metal thickness in grams/cm2 */
+double copper_bulk_resistivity;	/* metal resistivity in ohm meter */
+double copper_temperature_coefficient;	/* temperature coefficient of bulk resistivity */
+double fr4_epsilon_r;						/* dielectric constant of substrate */
+double fr4_loss_tangent;				/* loss tangent of substrate */
+double conformal_epsilon_r;			/* dielectric constant of conformal coating */
+
 /* Hyperlynx UNIT and OPTIONS */
-double unit;                   /* conversion factor: pcb length units to meters */
-double metal_thickness_unit;   /* conversion factor: metal thickness to meters */
+double unit;										/* conversion factor: pcb length units to meters */
+double metal_thickness_unit;		/* conversion factor: metal thickness to meters */
+
+pcb_bool use_die_for_metal;			/* use dielectric constant and loss tangent of dielectric for metal layers */
+
+pcb_coord_t board_clearance;		/* distance between PLANE polygon and copper of different nets; -1 if not set */
+
+/* stackup */
+pcb_bool layer_is_plane[PCB_MAX_LAYER];	/* whether layer is signal or plane layer */
+pcb_coord_t layer_clearance[PCB_MAX_LAYER];	/* separation between fill copper and signals on layer */
+
+/* net */
+char *net_name;									/* name of current copper */
+pcb_coord_t net_clearance;			/* distance between PLANE polygon and net copper */
+
+/* padstack */
+
+typedef struct padstack_s {
+	char *name;
+	pcb_coord_t thickness;
+	pcb_coord_t clearance;
+	pcb_coord_t mask;
+	pcb_coord_t drill_hole;
+	pcb_bool is_round;						/* round or rectangular */
+	struct padstack_s *next;
+} padstack_t;
+
+padstack_t *padstack_head;
+padstack_t *current_padstack;
+
+/* polygons */
+
+/* linked list to store correspondence between hyperlynx polygon id's and pcb polygons. */
+typedef struct hyp_polygon_s {
+	int hyp_poly_id;							/* hyperlynx polygon/polyline id */
+	pcb_polygon_t *polygon;
+	pcb_layer_t *layer;
+	pcb_bool_t is_polygon;				/* whether polygon or polyline */
+	struct hyp_polygon_s *next;
+} hyp_polygon_t;
+
+hyp_polygon_t *polygon_head = NULL;
+
+/* keep track of current polygon */
+
+pcb_polygon_t *current_polygon = NULL;
+
+/* current polyline layer, position, width and clearance */
+pcb_layer_t *current_polyline_layer = NULL;
+pcb_coord_t current_polyline_xpos = 0;
+pcb_coord_t current_polyline_ypos = 0;
+pcb_coord_t current_polyline_width = 0;
+pcb_coord_t current_polyline_clearance = 0;
+
+/* State machine for polygon parsing:
+ * HYP_POLYIDLE idle
+ * HYP_POLYGON parsing a polygon
+ * HYP_POLYLINE parsing a polyline (sequence of lines and arcs)
+ * HYP_POLYGON_HOLE parsing a hole in a polygon
+ * HYP_POLYLINE_HOLE parsing a hole in a polyline
+ */
 
-pcb_bool use_die_for_metal;    /* use dielectric constant and loss tangent of dielectric for metal layers */
-pcb_coord_t plane_separation;       /* distance between PLANE polygon and copper of different nets; -1 if not set */
+enum poly_state_e { HYP_POLYIDLE, HYP_POLYGON, HYP_POLYLINE, HYP_POLYGON_HOLE, HYP_POLYLINE_HOLE };
+enum poly_state_e poly_state = HYP_POLYIDLE;
 
 /* origin. Chosen so all coordinates are positive. */
 pcb_coord_t origin_x;
 pcb_coord_t origin_y;
 
 /*
- * Conversion from hyperlynx to pcb_coord_t - igor2
+ * Conversion from hyperlynx to pcb_coord_t
  */
 
 /* meter to pcb_coord_t */
 
 pcb_coord_t inline m2coord(double m)
 {
-  return ((pcb_coord_t) PCB_MM_TO_COORD(1000.0 * m));
+	return ((pcb_coord_t) PCB_MM_TO_COORD(1000.0 * m));
 }
 
 /* xy coordinates to pcb_coord_t, without offset */
 
 pcb_coord_t inline xy2coord(double f)
 {
-  return (m2coord(unit * f));
+	return (m2coord(unit * f));
 }
 
 
@@ -103,21 +174,21 @@ pcb_coord_t inline xy2coord(double f)
 
 pcb_coord_t inline x2coord(double f)
 {
-  return (m2coord(unit * f) - origin_x);
+	return (m2coord(unit * f) - origin_x);
 }
 
 /* y coordinates to pcb_coord_t, with offset */
 
 pcb_coord_t inline y2coord(double f)
 {
-  return (m2coord(unit * f) - origin_y);
+	return (origin_y - m2coord(unit * f));
 }
 
 /* z coordinates to pcb_coord_t. No offset needed. */
 
 pcb_coord_t inline z2coord(double f)
 {
-  return (m2coord(metal_thickness_unit * f));
+	return (m2coord(metal_thickness_unit * f));
 }
 
 /*
@@ -126,544 +197,1725 @@ pcb_coord_t inline z2coord(double f)
 
 void hyp_init(void)
 {
-  unit = 1;
-  metal_thickness_unit = 1;
-  use_die_for_metal = pcb_false;
-
-  inches  = 0.0254; /* inches to m */
-  copper_imperial_weight = 1.341; /* metal thickness in ounces/ft2. 1 oz/ft2 copper = 1.341 mil */
-  copper_metric_weight = 0.1116;  /* metal thickness in grams/cm2. 1 gr/cm2 copper = 0.1116 cm */
-  copper_bulk_resistivity = 1.724e-8;
-  copper_temperature_coefficient = 0.00393;
-  fr4_epsilon_r = 4.3;
-  fr4_loss_tangent = 0.020;
-  conformal_epsilon_r = 3.3; /* dielectric constant of conformal layer */
-  plane_separation = -1; /* distance between PLANE polygon and copper of different nets; -1 if not set */
-
-  outline_head = NULL;
-  outline_tail = NULL;
-
-  return;
+	int n;
+
+	unit = 1;
+	metal_thickness_unit = 1;
+	use_die_for_metal = pcb_false;
+
+	inches = 0.0254;							/* inches to m */
+	copper_imperial_weight = 1.341;	/* metal thickness in ounces/ft2. 1 oz/ft2 copper = 1.341 mil */
+	copper_metric_weight = 0.1116;	/* metal thickness in grams/cm2. 1 gr/cm2 copper = 0.1116 cm */
+	copper_bulk_resistivity = 1.724e-8;
+	copper_temperature_coefficient = 0.00393;
+	fr4_epsilon_r = 4.3;
+	fr4_loss_tangent = 0.020;
+	conformal_epsilon_r = 3.3;		/* dielectric constant of conformal layer */
+	board_clearance = -1;					/* distance between PLANE polygon and copper of different nets; -1 if not set */
+
+	/* empty board outline */
+	outline_head = NULL;
+	outline_tail = NULL;
+
+	/* clear layer info */
+	for (n = 1; n < PCB_MAX_LAYER; n++) {
+		layer_is_plane[n] = pcb_false;	/* signal layer */
+		layer_clearance[n] = -1;		/* no separation between fill copper and signals on layer */
+	}
+
+	/* clear padstack */
+	padstack_head = NULL;
+	current_padstack = NULL;
+
+	/* clear polygon data */
+	polygon_head = NULL;
+	current_polygon = NULL;
+	poly_state = HYP_POLYIDLE;
+
+	/* clear polyline data */
+	current_polyline_layer = NULL;
+	current_polyline_xpos = 0;
+	current_polyline_ypos = 0;
+	current_polyline_width = 0;
+	current_polyline_clearance = 0;
+
+	/* set origin */
+	origin_x = 0;
+	origin_y = 0;
+
+	return;
 }
 
 /* 
  * called by pcb-rnd to load hyperlynx file 
  */
 
-int hyp_parse(pcb_data_t *dest, const char *fname, int debug)
+int hyp_parse(pcb_data_t * dest, const char *fname, int debug)
 {
-  int retval;
+	int retval;
 
-  hyp_init();
+	hyp_init();
 
-  /* set debug levels */
-  hyyset_debug(debug > 2); /* switch flex logging on */
-  hyydebug = (debug > 1);  /* switch bison logging on */
-  hyp_debug = (debug > 0); /* switch hyperlynx logging on */
+	/* set debug levels */
+	hyyset_debug(debug > 2);			/* switch flex logging on */
+	hyydebug = (debug > 1);				/* switch bison logging on */
+	hyp_debug = (debug > 0);			/* switch hyperlynx logging on */
 
-  /* set shared board */
-  hyp_dest = dest;
+	/* set shared board */
+	hyp_dest = dest;
 
-  /* set origin */
-  origin_x = 0;
-  origin_y = 0;
+	/* parse hyperlynx file */
+	hyyin = fopen(fname, "r");
+	if (hyyin == NULL)
+		return (1);
+	retval = hyyparse();
+	fclose(hyyin);
 
-  /* parse hyperlynx file */
-  hyyin =  fopen(fname, "r");
-  if (hyyin == NULL) return (1);
-  retval = hyyparse();
-  fclose(hyyin);
+	/* finish setting up polygons */
+	hyp_create_polygons();
 
-  /* add board outline last */
-  hyp_perimeter();
+	/* add board outline last */
+	hyp_perimeter();
 
-  /* clear */
-  hyp_dest = NULL;
+	/* clear */
+	hyp_dest = NULL;
 
-  return(retval);
+	return (retval);
 }
- 
+
 /* print error message */
 void hyp_error(const char *msg)
 {
-  pcb_message(PCB_MSG_DEBUG, "line %d: %s at '%s'\n", hyylineno, msg, hyytext);
+	pcb_message(PCB_MSG_DEBUG, "line %d: %s at '%s'\n", hyylineno, msg, hyytext);
+}
+
+/*
+ * find padstack by name 
+ */
+
+padstack_t *hyp_padstack_by_name(char *padstack_name)
+{
+	padstack_t *i;
+	for (i = padstack_head; i != NULL; i = i->next)
+		if (strcmp(i->name, padstack_name) == 0)
+			return i;
+	return NULL;
+}
+
+/*
+ * add segment to board outline
+ */
+
+void hyp_perimeter_segment_add(outline_t * s, pcb_bool_t forward)
+{
+	pcb_layer_id_t outline_id;
+	pcb_layer_t *outline_layer;
+
+	/* get outline layer */
+	outline_id = pcb_layer_by_name("outline");
+	if (outline_id < 0)
+		outline_id = pcb_layer_create(-1, "outline");
+	outline_layer = pcb_get_layer(outline_id);
+
+	if (outline_layer == NULL) {
+		pcb_printf("create outline layer failed.\n");
+		return;
+	}
+
+	/* mark segment as used, so we don't use it twice */
+	s->used = pcb_true;
+
+	/* debugging */
+	if (hyp_debug) {
+		if (forward)
+			pcb_printf("outline: fwd %s from (%ml, %ml) to (%ml, %ml)\n", s->is_arc ? "arc" : "line", s->x1, s->y1, s->x2, s->y2);
+		else
+			pcb_printf("outline: bwd %s from (%ml, %ml) to (%ml, %ml)\n", s->is_arc ? "arc" : "line", s->x2, s->y2, s->x1, s->y1);	/* add segment back to front */
+	}
+
+	if (s->is_arc) {
+		/* counterclockwise arc from (x1, y1) to (x2, y2) */
+		hyp_arc_new(outline_layer, s->x1, s->y1, s->x2, s->y2, s->xc, s->yc, s->r, s->r, pcb_false, 1, 0, pcb_no_flags());
+	}
+	else
+		/* line from (x1, y1) to (x2, y2) */
+		pcb_line_new(outline_layer, s->x1, s->y1, s->x2, s->y2, 1, 0, pcb_no_flags());
+
+	return;
+}
+
+/* 
+ * Check whether point (end_x, end_y) is connected to point (begin_x, begin_y) via un-used segment s and other un-used segments.
+ */
+
+pcb_bool_t hyp_segment_connected(pcb_coord_t begin_x, pcb_coord_t begin_y, pcb_coord_t end_x, pcb_coord_t end_y, outline_t * s)
+{
+	outline_t *i;
+	pcb_bool_t connected;
+
+	connected = (begin_x == end_x) && (begin_y == end_y);	/* trivial case */
+
+	if (!connected) {
+		/* recursive descent */
+		s->used = pcb_true;
+
+		for (i = outline_head; i != NULL; i = i->next) {
+			if (i->used)
+				continue;
+			if ((i->x1 == begin_x) && (i->y1 == begin_y)) {
+				connected = ((i->x2 == end_x) && (i->y2 == end_y)) || hyp_segment_connected(i->x2, i->y2, end_x, end_y, i);
+				if (connected)
+					break;
+			}
+			/* try back-to-front */
+			if ((i->x2 == begin_x) && (i->y2 == begin_y)) {
+				connected = ((i->x1 == end_x) && (i->y1 == end_y)) || hyp_segment_connected(i->x1, i->y1, end_x, end_y, i);
+				if (connected)
+					break;
+			}
+		}
+
+		s->used = pcb_false;
+	}
+
+	return connected;
+}
+
+/* 
+ * Sets (origin_x, origin_y)
+ * Choose origin so that all coordinates are posive. 
+ */
+
+void hyp_set_origin()
+{
+	outline_t *i;
+
+	/* safe initial value */
+	if (outline_head != NULL) {
+		origin_x = outline_head->x1;
+		origin_y = outline_head->y1;
+	}
+	else {
+		origin_x = 0;
+		origin_y = 0;
+	}
+
+	/* choose upper left corner of outline */
+	for (i = outline_head; i != NULL; i = i->next) {
+		/* set origin so all coordinates are positive */
+		if (i->x1 < origin_x)
+			origin_x = i->x1;
+		if (i->x2 < origin_x)
+			origin_x = i->x2;
+		if (i->y1 > origin_y)
+			origin_y = i->y1;
+		if (i->y2 > origin_y)
+			origin_y = i->y2;
+		if (i->is_arc) {
+			if (i->xc - i->r < origin_x)
+				origin_x = i->xc - i->r;
+			if (i->yc + i->r > origin_y)
+				origin_y = i->yc + i->r;
+		}
+	}
+}
+
+/* 
+ * Draw board perimeter.
+ * The first segment is part of the first polygon.
+ * The first polygon of the board perimeter is positive, the rest are holes.
+ * Segments do not necessarily occur in order.
+ */
+
+void hyp_perimeter()
+{
+	pcb_bool_t warn_not_closed;
+	pcb_bool_t segment_found;
+	pcb_bool_t polygon_closed;
+	pcb_coord_t begin_x, begin_y, last_x, last_y;
+	outline_t *i;
+	outline_t *j;
+
+	warn_not_closed = pcb_false;
+
+	/* iterate over perimeter segments and adjust origin */
+	for (i = outline_head; i != NULL; i = i->next) {
+		/* set origin so all coordinates are positive */
+		i->x1 = i->x1 - origin_x;
+		i->y1 = origin_y - i->y1;
+		i->x2 = i->x2 - origin_x;
+		i->y2 = origin_y - i->y2;
+		if (i->is_arc) {
+			i->xc = i->xc - origin_x;
+			i->yc = origin_y - i->yc;
+		}
+	}
+
+	/* iterate over perimeter polygons */
+	while (pcb_true) {
+
+		/* find first free segment */
+		for (i = outline_head; i != NULL; i = i->next)
+			if (i->used == pcb_false)
+				break;
+
+		/* exit if no segments found */
+		if (i == NULL)
+			break;
+
+		/* first point of polygon (begin_x, begin_y) */
+		begin_x = i->x1;
+		begin_y = i->y1;
+
+		/* last point of polygon (last_x, last_y) */
+		last_x = i->x2;
+		last_y = i->y2;
+
+		/* add segment */
+		hyp_perimeter_segment_add(i, pcb_true);
+
+		/* add polygon segments until the polygon is closed */
+		polygon_closed = pcb_false;
+		while (!polygon_closed) {
+
+#undef XXX
+#ifdef XXX
+			pcb_printf("perimeter: last_x = %ml last_y = %ml\n", last_x, last_y);
+			for (i = outline_head; i != NULL; i = i->next)
+				if (!i->used)
+					pcb_printf("perimeter segments available: %s from (%ml, %ml) to (%ml, %ml)\n", i->is_arc ? "arc " : "line", i->x1,
+										 i->y1, i->x2, i->y2);
+#endif
+
+			/* find segment to add to current polygon */
+			segment_found = pcb_false;
+
+			/* XXX prefer closed polygon over open polyline */
+
+			for (i = outline_head; i != NULL; i = i->next) {
+				if (i->used)
+					continue;
+
+				if ((last_x == i->x1) && (last_y == i->y1)) {
+					if (!hyp_segment_connected(i->x2, i->y2, begin_x, begin_y, i))
+						continue;						/* XXX Checkme */
+					/* first point of segment is last point of current edge: add segment to edge */
+					segment_found = pcb_true;
+					hyp_perimeter_segment_add(i, pcb_true);
+					last_x = i->x2;
+					last_y = i->y2;
+				}
+				else if ((last_x == i->x2) && (last_y == i->y2)) {
+					if (!hyp_segment_connected(i->x1, i->y1, begin_x, begin_y, i))
+						continue;						/* XXX Checkme */
+					/* last point of segment is last point of current edge: add segment to edge back to front */
+					segment_found = pcb_true;
+					/* add segment back to front */
+					hyp_perimeter_segment_add(i, pcb_false);
+					last_x = i->x1;
+					last_y = i->y1;
+				}
+				if (segment_found)
+					break;
+			}
+			polygon_closed = (begin_x == last_x) && (begin_y == last_y);
+			if (!polygon_closed && !segment_found)
+				break;									/* can't find anything suitable */
+		}
+		if (polygon_closed) {
+			if (hyp_debug)
+				pcb_printf("outline: closed\n");
+		}
+		else {
+			if (hyp_debug)
+				pcb_printf("outline: open\n");
+			warn_not_closed = pcb_true;
+		}
+	}
+
+	/* free segment memory */
+	for (i = outline_head; i != NULL; i = j) {
+		j = i->next;
+		free(i);
+	}
+	outline_head = outline_tail = NULL;
+
+	if (warn_not_closed)
+		pcb_message(PCB_MSG_DEBUG, "warning: board outline not closed\n");
+
+	return;
+}
+
+/*
+ * Returns the pcb_layer_id of layer "lname". 
+ * If layer lname does not exist, a new copper layer with name "lname" is created.
+ * If the layer name is NULL, a new copper layer with a new, unused layer name is created.
+ */
+
+pcb_layer_id_t hyp_create_layer(char *lname)
+{
+	pcb_layer_id_t layer_id;
+	char new_layer_name[PCB_MAX_LAYER];
+	int n;
+
+	layer_id = -1;
+	if (lname != NULL) {
+		/* we have a layer name. check whether layer already exists */
+		layer_id = pcb_layer_by_name(lname);
+		if (layer_id >= 0)
+			return layer_id;					/* found */
+		/* create new layer */
+		if (hyp_debug)
+			pcb_printf("create layer \"%s\"\n", lname);
+		layer_id = pcb_layer_create(-1, pcb_strdup(lname));
+	}
+	else {
+		/* no layer name given. find unused layer name in range 1..PCB_MAX_LAYER */
+		for (n = 1; n < PCB_MAX_LAYER; n++) {
+			pcb_sprintf(new_layer_name, "%i", n);
+			if (pcb_layer_by_name(new_layer_name) < 0) {
+				/* create new layer */
+				if (hyp_debug)
+					pcb_printf("create auto layer \"%s\"\n", new_layer_name);
+				layer_id = pcb_layer_create(-1, pcb_strdup(new_layer_name));
+				break;
+			}
+		}
+	}
+	/* check if layer valid */
+	if (layer_id < 0) {
+		/* layer creation failed. return the first copper layer you can find. */
+		if (hyp_debug)
+			pcb_printf("running out of layers\n");
+		layer_id = PCB_COMPONENT_SIDE;
+	}
+
+	return layer_id;
+}
+
+/*
+ * convert hyperlynx layer name to pcb layer
+ */
+
+pcb_layer_t *hyp_get_layer(parse_param * h)
+{
+	return pcb_get_layer(hyp_create_layer(h->layer_name));
+}
+
+/*
+ * create all polygons 
+ */
+
+void hyp_create_polygons()
+{
+	hyp_polygon_t *i;
+
+	/* loop over all created polygons and close them */
+	for (i = polygon_head; i != NULL; i = i->next)
+		if ((i->is_polygon) && (i->polygon != NULL) && (i->layer != NULL)) {
+			pcb_add_polygon_on_layer(i->layer, i->polygon);
+			pcb_poly_init_clip(hyp_dest, i->layer, i->polygon);
+		}
+	return;
+}
+
+/*
+ * calculate hyperlynx-style clearance
+ * 
+ * use plane_separation of, in order:
+ * - this copper
+ * - the net this copper belongs to
+ * - the layer this copper is on
+ * - the board
+ * if neither copper, net, layer nor board have plane_separation set, do not set clearance.
+ */
+
+pcb_coord_t hyp_clearance(parse_param * h)
+{
+	pcb_coord_t clearance;
+	pcb_layer_id_t layr_id;
+
+	if (h->layer_name_set)
+		layr_id = hyp_create_layer(h->layer_name);
+	clearance = -1;
+
+	if (h->plane_separation_set)
+		clearance = xy2coord(h->plane_separation);
+	else if (net_clearance >= 0)
+		clearance = net_clearance;
+	else if (h->layer_name_set && (layer_clearance[layr_id] >= 0))
+		clearance = layer_clearance[layr_id];
+	else if (board_clearance >= 0)
+		clearance = board_clearance;
+	else
+		clearance = 0;
+
+	return clearance;
+}
+
+/*
+ * Draw arc from (x1, y1) to (x2, y2) with center (xc, yc) and radius r. 
+ * Direction of arc is clockwise or counter-clockwise, depending upon value of pcb_bool_t Clockwise.
+ */
+
+pcb_arc_t *hyp_arc_new(pcb_layer_t * Layer, pcb_coord_t X1, pcb_coord_t Y1, pcb_coord_t X2, pcb_coord_t Y2, pcb_coord_t XC,
+											 pcb_coord_t YC, pcb_coord_t Width, pcb_coord_t Height, pcb_bool_t Clockwise, pcb_coord_t Thickness,
+											 pcb_coord_t Clearance, pcb_flag_t Flags)
+{
+	pcb_angle_t start_angle;
+	pcb_angle_t end_angle;
+	pcb_angle_t delta;
+	pcb_arc_t *new_arc;
+
+	if (Width < 1) {
+		start_angle = 0.0;
+		end_angle = 360.0;
+	}
+	else {
+		/* note: y-axis points down */
+		start_angle = 180 + 180 * atan2(YC - Y1, X1 - XC) / M_PI;
+		end_angle = 180 + 180 * atan2(YC - Y2, X2 - XC) / M_PI;
+	}
+	start_angle = pcb_normalize_angle(start_angle);
+	end_angle = pcb_normalize_angle(end_angle);
+
+	if (Clockwise)
+		while (start_angle < end_angle)
+			start_angle += 360;
+	else
+		while (end_angle <= start_angle)
+			end_angle += 360;
+
+	delta = end_angle - start_angle;
+
+#undef XXX
+#ifdef XXX
+	if (hyp_debug)
+		pcb_printf("hyp_arc: start_angle: %f end_angle: %f delta: %f\n", start_angle, end_angle, delta);
+#endif
+
+	new_arc = pcb_arc_new(Layer, XC, YC, Width, Height, start_angle, delta, Thickness, Clearance, Flags);
+
+#ifdef XXX
+	/* XXX remove debugging code */
+	if (hyp_debug) {
+		pcb_coord_t x1, y1, x2, y2;
+		pcb_arc_get_end(new_arc, 1, &x1, &y1);
+		pcb_arc_get_end(new_arc, 0, &x2, &y2);
+		pcb_printf("hyp_arc: start_point: (%ml, %ml) end_point: (%ml, %ml)\n", x1, y1, x2, y2);
+	}
+#endif
+
+	return new_arc;
 }
 
-/* exec_* routines are called by parser to interpret hyperlynx file */ 
+/* exec_* routines are called by parser to interpret hyperlynx file */
 
 /*
- * Hyperlynx 'BOARD_FILE' section.
- * Hyperlynx file header.
+ * 'BOARD_FILE' record.
  */
 
-pcb_bool exec_board_file(parse_param *h)
+pcb_bool exec_board_file(parse_param * h)
 {
-  if (hyp_debug) pcb_printf(PCB_MSG_DEBUG, "board\n");
+	if (hyp_debug)
+		pcb_printf("board:\n");
 
-  return 0;
+	return 0;
 }
 
 /*
- * Hyperlynx 'VERSION' record.
+ * 'VERSION' record.
  * Specifies version number.
- * Required record; must be first record of the file.
  */
 
-pcb_bool exec_version(parse_param *h)
+pcb_bool exec_version(parse_param * h)
 {
-  if (hyp_debug) pcb_printf("version: vers = %f\n", h->vers);
+	if (hyp_debug)
+		pcb_printf("version: vers = %f\n", h->vers);
 
-  if (h->vers < 1.0) pcb_message(PCB_MSG_DEBUG, "warning: version 1.x deprecated\n");
+	if (h->vers < 1.0)
+		pcb_message(PCB_MSG_DEBUG, "warning: version 1.x deprecated\n");
 
-  return 0;
+	return 0;
 }
 
 /*
- * Hyperlynx 'DATA_MODE' record.
+ * 'DATA_MODE' record.
  * If DATA_MODE is DETAILED, model can be used for power and signal simulation.
  * If DATA_MODE is SIMPLIFIED, model can be used for signal simulation only.
  */
 
-pcb_bool exec_data_mode(parse_param *h)
+pcb_bool exec_data_mode(parse_param * h)
 {
-  if (hyp_debug) pcb_printf("data_mode: detailed = %i\n", h->detailed);
+	if (hyp_debug)
+		pcb_printf("data_mode: detailed = %i\n", h->detailed);
 
-  return 0;
+	return 0;
 }
 
 /*
- * Hyperlynx 'UNITS' record.
+ * 'UNITS' record.
  * Specifies measurement system (english/metric) for the rest of the file.
  */
 
-pcb_bool exec_units(parse_param *h)
+pcb_bool exec_units(parse_param * h)
 {
-  if (hyp_debug) pcb_printf("units: unit_system_english = %d metal_thickness_weight = %d\n", h->unit_system_english, h->metal_thickness_weight);
+	if (hyp_debug)
+		pcb_printf("units: unit_system_english = %d metal_thickness_weight = %d\n", h->unit_system_english,
+							 h->metal_thickness_weight);
+
+	/* convert everything to meter */
+
+	if (h->unit_system_english) {
+		unit = inches;							/* lengths in inches. 1 in = 2.54 cm = 0.0254 m */
+		if (h->metal_thickness_weight)
+			metal_thickness_unit = copper_imperial_weight * unit;	/* metal thickness in ounces/ft2. 1 oz/ft2 copper = 1.341 mil */
+		else
+			metal_thickness_unit = unit;	/* metal thickness in inches */
+	}
+	else {
+		unit = 0.01;								/* lengths in centimeters. 1 cm = 0.01 m */
+		if (h->metal_thickness_weight)
+			metal_thickness_unit = copper_metric_weight * unit;	/* metal thickness in grams/cm2. 1 gr/cm2 copper = 0.1116 cm */
+		else
+			metal_thickness_unit = unit;	/* metal thickness in centimeters */
+	}
+
+	if (hyp_debug)
+		pcb_printf("units: unit = %f metal_thickness_unit = %f\n", unit, metal_thickness_unit);
+
+	return 0;
+}
 
-  /* convert everything to meter */
+/*
+ * 'PLANE_SEP' record.
+ * Defines default trace to plane clearance.
+ */
 
-  if (h->unit_system_english) {
-    unit = inches;                                /* lengths in inches. 1 in = 2.54 cm = 0.0254 m */
-    if (h->metal_thickness_weight)
-      metal_thickness_unit = copper_imperial_weight * unit;        /* metal thickness in ounces/ft2. 1 oz/ft2 copper = 1.341 mil */
-    else
-      metal_thickness_unit = unit;                /* metal thickness in inches */
-    }
-  else {
-    unit = 0.01;                                  /* lengths in centimeters. 1 cm = 0.01 m */
-    if (h->metal_thickness_weight)
-      metal_thickness_unit = copper_metric_weight * unit;       /* metal thickness in grams/cm2. 1 gr/cm2 copper = 0.1116 cm */
-    else
-      metal_thickness_unit = unit;                /* metal thickness in centimeters */
-    }
+pcb_bool exec_plane_sep(parse_param * h)
+{
+	board_clearance = xy2coord(h->plane_separation);
 
-  if (hyp_debug) pcb_printf("units: unit = %f metal_thickness_unit = %f\n", unit, metal_thickness_unit);
+	if (hyp_debug)
+		pcb_printf("plane_sep: default_plane_separation = %ml\n", board_clearance);
 
-  return 0;
+	return 0;
 }
 
 /*
- * Hyperlynx 'PLANE_SEP' record.
- * Defines default trace to plane separation
+ * 'PERIMETER_SEGMENT' subrecord of 'BOARD' record.
+ * Draws linear board outline segment from (x1, y1) to (x2, y2).
  */
 
-pcb_bool exec_plane_sep(parse_param *h)
+pcb_bool exec_perimeter_segment(parse_param * h)
 {
-  plane_separation = m2coord(h->plane_separation);
+	outline_t *peri_seg;
+
+	peri_seg = malloc(sizeof(outline_t));
+
+	/* convert coordinates */
+	peri_seg->x1 = xy2coord(h->x1);
+	peri_seg->y1 = xy2coord(h->y1);
+	peri_seg->x2 = xy2coord(h->x2);
+	peri_seg->y2 = xy2coord(h->y2);
+	peri_seg->xc = 0;
+	peri_seg->yc = 0;
+	peri_seg->r = 0;
+	peri_seg->is_arc = pcb_false;
+	peri_seg->used = pcb_false;
+	peri_seg->next = NULL;
+
+	if (hyp_debug)
+		pcb_printf("perimeter_segment: x1 = %ml y1 = %ml x2 = %ml y2 = %ml\n", peri_seg->x1, peri_seg->y1, peri_seg->x2,
+							 peri_seg->y2);
+
+	/* append at end of doubly linked list */
+	if (outline_tail == NULL) {
+		outline_head = peri_seg;
+		outline_tail = peri_seg;
+	}
+	else {
+		outline_tail->next = peri_seg;
+		outline_tail = peri_seg;
+	}
+
+	/* set origin so all coordinates are positive */
+	hyp_set_origin();
+
+	return 0;
+}
 
-  if (hyp_debug) pcb_printf("plane_sep: default_plane_separation = %mm\n", plane_separation);
+/*
+ * 'PERIMETER_ARC' subrecord of 'BOARD' record.
+ * Draws arc segment of board outline. 
+ * Arc drawn counterclockwise from (x1, y1) to (x2, y2) with center (xc, yc) and radius r.
+ */
 
-  return 0;
+pcb_bool exec_perimeter_arc(parse_param * h)
+{
+	outline_t *peri_arc;
+
+	peri_arc = malloc(sizeof(outline_t));
+
+	peri_arc->x1 = xy2coord(h->x1);
+	peri_arc->y1 = xy2coord(h->y1);
+	peri_arc->x2 = xy2coord(h->x2);
+	peri_arc->y2 = xy2coord(h->y2);
+	peri_arc->xc = xy2coord(h->xc);
+	peri_arc->yc = xy2coord(h->yc);
+	peri_arc->r = xy2coord(h->r);
+	peri_arc->is_arc = pcb_true;
+	peri_arc->used = pcb_false;
+	peri_arc->next = NULL;
+
+	if (hyp_debug)
+		pcb_printf("perimeter_arc: x1 = %ml y1 = %ml x2 = %ml y2 = %ml xc = %ml yc = %ml r = %ml\n", peri_arc->x1, peri_arc->y1,
+							 peri_arc->x2, peri_arc->y2, peri_arc->xc, peri_arc->yc, peri_arc->r);
+
+	/* append at end of doubly linked list */
+	if (outline_tail == NULL) {
+		outline_head = peri_arc;
+		outline_tail = peri_arc;
+	}
+	else {
+		outline_tail->next = peri_arc;
+		outline_tail = peri_arc;
+	}
+
+	/* set origin so all coordinates are positive */
+	hyp_set_origin();
+
+	return 0;
 }
 
 /*
- * Hyperlynx 'PERIMETER_SEGMENT' subrecord of 'BOARD' record.
- * Draws linear board outline segment.
- * Linear segment drawn from (x1, y1) to (x2, y2).
+ * 'A' attribute subrecord of 'BOARD' record.
+ * Defines board attributes as name/value pairs.
  */
 
-pcb_bool exec_perimeter_segment(parse_param *h)
+pcb_bool exec_board_attribute(parse_param * h)
 {
-  outline_t *peri_seg;
+	if (hyp_debug)
+		pcb_printf("board_attribute: name = \"%s\" value = \"%s\"\n", h->name, h->value);
 
-  peri_seg = malloc(sizeof(outline_t));
+	return 0;
+}
 
-  /* convert coordinates */
-  peri_seg->x1 = xy2coord(h->x1);
-  peri_seg->y1 = xy2coord(h->y1);
-  peri_seg->x2 = xy2coord(h->x2);
-  peri_seg->y2 = xy2coord(h->y2);
-  peri_seg->xc = 0;
-  peri_seg->yc = 0;
-  peri_seg->r = 0;
-  peri_seg->is_arc = pcb_false;
-  peri_seg->used = pcb_false;
-  peri_seg->next = NULL;
+/*
+ * STACKUP section 
+ */
 
-  if (hyp_debug) pcb_printf("perimeter_segment: x1 = %mm y1 = %mm x2 = %mm y2 = %mm\n", peri_seg->x1, peri_seg->y1, peri_seg->x2, peri_seg->y2);
+/*
+ * Debug output for layers
+ */
 
-  /* append at end of doubly linked list */
-  if (outline_tail == NULL) {
-    outline_head = peri_seg;
-    outline_tail = peri_seg;
-    }
-  else {
-    outline_tail->next = peri_seg;
-    outline_tail = peri_seg;
-    }
+void hyp_debug_layer(parse_param * h)
+{
+	if (hyp_debug) {
+		if (h->thickness_set)
+			pcb_printf(" thickness = %ml", z2coord(h->thickness));
+		if (h->plating_thickness_set)
+			pcb_printf(" plating_thickness = %ml", z2coord(h->plating_thickness));
+		if (h->bulk_resistivity_set)
+			pcb_printf(" bulk_resistivity = %f", h->bulk_resistivity);
+		if (h->temperature_coefficient_set)
+			pcb_printf(" temperature_coefficient = %f", h->temperature_coefficient);
+		if (h->epsilon_r_set)
+			pcb_printf(" epsilon_r = %f", h->epsilon_r);
+		if (h->loss_tangent_set)
+			pcb_printf(" loss_tangent = %f", h->loss_tangent);
+		if (h->conformal_set)
+			pcb_printf(" conformal = %i", h->conformal);
+		if (h->prepreg_set)
+			pcb_printf(" prepreg = %i", h->prepreg);
+		if (h->layer_name_set)
+			pcb_printf(" layer_name = \"%s\"", h->layer_name);
+		if (h->material_name_set)
+			pcb_printf(" material_name = \"%s\"", h->material_name);
+		if (h->plane_separation_set)
+			pcb_printf(" plane_separation = %ml", xy2coord(h->plane_separation));
+		pcb_printf("\n");
+	}
+
+	return;
+}
 
-  /* set origin so all coordinates are positive */
-  hyp_set_origin();
+/*
+ * 'OPTIONS' subrecord of 'STACKUP' record.
+ * Defines dielectric constant and loss tangent of metal layers.
+ */
 
-  return 0;
+pcb_bool exec_options(parse_param * h)
+{
+	/* Use dielectric for metal? */
+	if (hyp_debug)
+		pcb_printf("options: use_die_for_metal = %f\n", h->use_die_for_metal);
+	if (h->use_die_for_metal)
+		use_die_for_metal = pcb_true;
+	return 0;
 }
 
 /*
- * Hyperlynx 'PERIMETER_ARC' subrecord of 'BOARD' record.
- * Draws arc segment of board outline. 
- * Arc drawn counterclockwise from (x1, y1) to (x2, y2) with center (xc, yc) and radius r.
+ * SIGNAL subrecord of STACKUP record.
+ * signal layer.
  */
 
-pcb_bool exec_perimeter_arc(parse_param *h)
+pcb_bool exec_signal(parse_param * h)
 {
-  outline_t *peri_arc;
+	pcb_layer_id_t signal_layer_id;
+	signal_layer_id = hyp_create_layer(h->layer_name);
 
-  peri_arc = malloc(sizeof(outline_t));
+	layer_is_plane[signal_layer_id] = pcb_false;
+	if (h->plane_separation_set)
+		layer_clearance[signal_layer_id] = xy2coord(h->plane_separation);
 
-  peri_arc->x1 = xy2coord(h->x1);
-  peri_arc->y1 = xy2coord(h->y1);
-  peri_arc->x2 = xy2coord(h->x2);
-  peri_arc->y2 = xy2coord(h->y2);
-  peri_arc->xc = xy2coord(h->xc);
-  peri_arc->yc = xy2coord(h->yc);
-  peri_arc->r = xy2coord(h->r);
-  peri_arc->is_arc = pcb_true;
-  peri_arc->used = pcb_false;
-  peri_arc->next = NULL;
+	if (hyp_debug)
+		pcb_printf("signal layer: \"%s\"", pcb_layer_name(signal_layer_id));
+	hyp_debug_layer(h);
 
-  if (hyp_debug) pcb_printf("perimeter_arc: x1 = %mm y1 = %mm x2 = %mm y2 = %mm xc = %mm yc = %mm r = %mm\n", peri_arc->x1, peri_arc->y1, peri_arc->x2, peri_arc->y2, peri_arc->xc, peri_arc->yc, peri_arc->r);
+	return 0;
+}
 
-  /* append at end of doubly linked list */
-  if (outline_tail == NULL) {
-    outline_head = peri_arc;
-    outline_tail = peri_arc;
-    }
-  else {
-    outline_tail->next = peri_arc;
-    outline_tail = peri_arc;
-    }
+/*
+ * DIELECTRIC subrecord of STACKUP record.
+ * dielectric layer 
+ */
 
-  /* set origin so all coordinates are positive */
-  hyp_set_origin();
+pcb_bool exec_dielectric(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("dielectric layer: ");
+	hyp_debug_layer(h);
 
-  return 0;
+	return 0;
 }
 
 /*
- * Hyperlynx 'A' attribute subrecord of 'BOARD' record.
- * Defines board attributes as name/value pairs.
+ * PLANE subrecord of STACKUP record.
+ * plane layer - a layer which is flooded with copper.
  */
 
-pcb_bool exec_board_attribute(parse_param *h)
+pcb_bool exec_plane(parse_param * h)
 {
-  if (hyp_debug) pcb_printf("board_attribute: name = %s value = %s\n", h->name, h->value);
+	pcb_layer_id_t plane_layer_id;
+	plane_layer_id = hyp_create_layer(h->layer_name);
+
+	layer_is_plane[plane_layer_id] = pcb_true;
+	if (h->plane_separation_set)
+		layer_clearance[plane_layer_id] = xy2coord(h->plane_separation);
 
-  return 0;
+	/* XXX need to flood layer with copper */
+
+	if (hyp_debug)
+		pcb_printf("plane layer: \"%s\"", pcb_layer_name(plane_layer_id));
+	hyp_debug_layer(h);
+
+	return 0;
 }
 
 /*
- * add segment to board outline
+ * DEVICE record.
  */
 
-void perimeter_segment_add(outline_t *s, pcb_bool_t forward)
+pcb_bool exec_devices(parse_param * h)
 {
-  pcb_layer_t *outline_layer;
+	char *description = NULL;
+	char *name = NULL;
+	char *value = NULL;
+	pcb_coord_t text_x = 0;
+	pcb_coord_t text_y = 0;
+	pcb_uint8_t text_direction = 0;
+	int text_scale = 100;
+
+	if (hyp_debug) {
+		pcb_printf("device: device_type = \"%s\" ref = \"%s\"", h->device_type, h->ref);
+		if (h->name_set)
+			pcb_printf(" name = \"%s\"", h->name);
+		if (h->value_float_set)
+			pcb_printf(" value_float = %f", h->value_float);
+		if (h->value_string_set)
+			pcb_printf(" value_string = \"%s\"", h->value_string);
+		if (h->layer_name_set)
+			pcb_printf(" layer_name = \"%s\"", h->layer_name);
+		if (h->package_set)
+			pcb_printf(" package = \"%s\"", h->package);
+		pcb_printf("\n");
+	}
+
+	/* create pcb element */
+	if (h->name_set)
+		description = pcb_strdup(h->name);
+	else
+		description = pcb_strdup("?");
+	name = pcb_strdup(h->ref);
+	value = pcb_strdup("?");
+	if (h->value_string_set)
+		value = pcb_strdup(h->value_string);
+	if (h->value_float_set) {
+		/* convert double to string */
+		value = (char *) malloc(128);
+		if (value != NULL)
+			pcb_snprintf(value, sizeof(value), "%f", h->value_float);
+	}
+
+	/* place the device at (0.0) for the moment being. when a pin is assigned, move the position to the pin position */
+
+	pcb_element_new(hyp_dest, NULL, &PCB->Font, pcb_no_flags(), description, name, value, text_x, text_y, text_direction,
+									text_scale, pcb_no_flags(), pcb_false);
+
+	return 0;
+}
 
-  /* get outline layer */
-  int outlineCount = 0;
-  int outlineLayerCount = 0;
-  int *outlineLayers = NULL;
-  /* count outline layers */
-  outlineLayerCount = pcb_layer_group_list(PCB_LYT_OUTLINE, NULL, 0);
-  outlineLayers = malloc(sizeof(int) * outlineLayerCount);
-  outlineCount = pcb_layer_list(PCB_LYT_OUTLINE, NULL, 0);
-  pcb_layer_list(PCB_LYT_OUTLINE, outlineLayers, outlineCount);
-  /* XXX fix: add outline layer if necessary */
-  outline_layer = &(hyp_dest->Layer[outlineLayers[0]]);
-  if (outline_layer == NULL) return;
+/*
+ * SUPPLY record.
+ * marks nets as power supply.
+ */
 
-  /* mark segment as used, so we don't use it twice */
-  s->used = pcb_true;
+pcb_bool exec_supplies(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("supplies: name = \"%s\" value_float = %f voltage_specified = %i conversion = %i\n", h->name, h->value_float,
+							 h->voltage_specified, h->conversion);
 
-  /* debugging */
-  if (hyp_debug) {
-    if (forward) pcb_printf("outline: %s from (%mm, %mm) to (%mm, %mm)\n", s->is_arc ? "arc" : "line", s->x1, s->y1, s->x2, s->y2);
-    else pcb_printf("outline: %s from (%mm, %mm) to (%mm, %mm)\n", s->is_arc ? "arc" : "line", s->x2, s->y2, s->x1, s->y1); /* add segment back to front */
-    }
+	return 0;
+}
 
-  if (s->is_arc) {
-    if (forward)
-      hyp_arc_new(outline_layer, s->x1, s->y1, s->x2, s->y2, s->xc, s->yc, s->r, s->r, pcb_false, 1, 0, pcb_no_flags());
-    else
-      hyp_arc_new(outline_layer, s->x2, s->y2, s->x1, s->y1, s->xc, s->yc, s->r, s->r, pcb_false, 1, 0, pcb_no_flags());
-    }
-  else 
-    pcb_line_new(outline_layer, s->x1, s->y1, s->x2, s->y2, 1, 0, pcb_no_flags());
+/* 
+ * PADSTACK record
+ */
 
-  return;
+pcb_bool exec_padstack_element(parse_param * h)
+{
+	if (hyp_debug) {
+		pcb_printf("padstack_element:");
+		if (h->padstack_name_set)
+			pcb_printf(" padstack_name = \"%s\"", h->padstack_name);
+		if (h->drill_size_set)
+			pcb_printf(" drill_size = %ml", xy2coord(h->drill_size));
+		pcb_printf(" layer_name = \"%s\"", h->layer_name);
+		pcb_printf(" pad_shape = %f", h->pad_shape);
+		if (h->pad_shape == 0)
+			pcb_printf(" oval");
+		else if (h->pad_shape == 1)
+			pcb_printf(" rectangular");
+		else if (h->pad_shape == 2)
+			pcb_printf(" oblong");
+		else
+			pcb_printf(" ?");
+		pcb_printf(" pad_sx = %ml", xy2coord(h->pad_sx));
+		pcb_printf(" pad_sy = %ml", xy2coord(h->pad_sy));
+		pcb_printf(" pad_angle = %f", h->pad_angle);
+		if (h->pad_type_set & (h->pad_type == PAD_TYPE_THERMAL_RELIEF)) {
+			pcb_printf(" thermal_clear_shape = %f", h->thermal_clear_shape);
+			if (h->thermal_clear_shape == 0)
+				pcb_printf(" oval");
+			else if (h->thermal_clear_shape == 1)
+				pcb_printf(" rectangular");
+			else if (h->thermal_clear_shape == 2)
+				pcb_printf(" oblong");
+			else
+				pcb_printf(" ?");
+			pcb_printf(" pad_sx = %ml", xy2coord(h->pad_sx));
+			pcb_printf(" pad_sy = %ml", xy2coord(h->pad_sy));
+			pcb_printf(" thermal_clear_sx = %ml", xy2coord(h->thermal_clear_sx));
+			pcb_printf(" thermal_clear_sy = %ml", xy2coord(h->thermal_clear_sy));
+			pcb_printf(" thermal_clear_angle = %f", h->thermal_clear_angle);
+		}
+		if (h->pad_type_set) {
+			pcb_printf(" pad_type = ");
+			switch (h->pad_type) {
+			case PAD_TYPE_METAL:
+				pcb_printf("metal");
+				break;
+			case PAD_TYPE_ANTIPAD:
+				pcb_printf("antipad");
+				break;
+			case PAD_TYPE_THERMAL_RELIEF:
+				pcb_printf("thermal_relief");
+				break;
+			default:
+				pcb_printf("error");
+			}
+		}
+		pcb_printf("\n");
+	}
+
+
+	/* XXX fixme. This reduces the padstack to a pcb_via_new call; a very basic approximation of what a padstack is. */
+
+	if (h->padstack_name_set) {
+		current_padstack = malloc(sizeof(padstack_t));
+		if (current_padstack == NULL)
+			return 1;
+		current_padstack->name = pcb_strdup(h->padstack_name);
+		current_padstack->thickness = xy2coord(h->pad_sx);
+		current_padstack->clearance = 0;
+		current_padstack->mask = xy2coord(h->pad_sx);
+		current_padstack->drill_hole = xy2coord(h->drill_size);
+		current_padstack->is_round = (h->pad_shape != 1);
+	}
+
+	if ((current_padstack != NULL) && h->pad_type_set & (h->pad_type == PAD_TYPE_THERMAL_RELIEF)) {
+		current_padstack->clearance = xy2coord(h->thermal_clear_sx) - current_padstack->thickness;
+		if (current_padstack->clearance < 0)
+			current_padstack->clearance = 0;
+	}
+
+	return 0;
 }
 
-/* 
- * Check whether point (end_x, end_y) is connected to point (begin_x, begin_y) via un-used segment s and other un-used segments.
+
+pcb_bool exec_padstack_end(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("padstack_end\n");
+
+	/* add current padstack to list of padstacks */
+	if (current_padstack != NULL) {
+		current_padstack->next = padstack_head;
+		padstack_head = current_padstack;
+		current_padstack = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * NET record.
  */
 
-pcb_bool_t segment_connected(pcb_coord_t begin_x, pcb_coord_t begin_y, pcb_coord_t end_x, pcb_coord_t end_y, outline_t *s)
+pcb_bool exec_net(parse_param * h)
 {
-  outline_t *i;
-  pcb_bool_t connected;
+	if (hyp_debug)
+		pcb_printf("net: net_name = \"%s\"\n", h->net_name);
 
-  connected = (begin_x == end_x) && (begin_y == end_y); /* trivial case */
+	net_name = pcb_strdup(h->net_name);
+	net_clearance = -1;
 
-  if (!connected)
-  {
-    /* recursive descent */
-    s->used = pcb_true;
+	return 0;
+}
 
-    for (i = outline_head; i != NULL; i = i->next)
-    {
-      if (i->used) continue;
-      if ((i->x1 == begin_x) && (i->y1 == begin_y))
-      {
-        connected = ((i->x2 == end_x) && (i->y2 == end_y)) || segment_connected(i->x2, i->y2, end_x, end_y, i);
-        if (connected) break;
-      }
-      /* try back-to-front */
-      if ((i->x2 == begin_x) && (i->y2 == begin_y))
-      {
-        connected = ((i->x1 == end_x) && (i->y1 == end_y)) || segment_connected(i->x1, i->y1, end_x, end_y, i);
-        if (connected) break;
-      }
-    }
+/*
+ * PS subrecord of NET record. Plane separation.
+ */
+
+pcb_bool exec_net_plane_separation(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("net_plane_separation: plane_separation = %ml\n", xy2coord(h->plane_separation));
 
-    s->used = pcb_false;
-  }
+	net_clearance = xy2coord(h->plane_separation);
 
-  return connected;
+	return 0;
 }
 
-/* 
- * Sets (origin_x, origin_y)
- * Choose origin so that all coordinates are posive. 
+/*
+ * A subrecord of NET record. Attribute.
  */
 
-void hyp_set_origin()
+pcb_bool exec_net_attribute(parse_param * h)
 {
-  pcb_bool_t first;
-  outline_t *i;
+	if (hyp_debug)
+		pcb_printf("net_attribute: name = \"%s\" value = \"%s\"\n", h->name, h->value);
 
-  first = pcb_true;
-  for (i = outline_head; i != NULL; i = i->next) {
-    /* set origin so all coordinates are positive */
-    if ((i->x1 < origin_x) || first) origin_x = i->x1;
-    if ((i->x2 < origin_x) || first) origin_x = i->x2;
-    if ((i->y1 < origin_y) || first) origin_x = i->y1;
-    if ((i->y2 < origin_y) || first) origin_x = i->y2;
-    if (i->is_arc) {
-      if ((i->xc - i->r < origin_x) || first) origin_x = i->xc - i->r;
-      if ((i->yc - i->r < origin_y) || first) origin_y = i->yc - i->r;
-      }
-    first = pcb_false;
-    }
+	return 0;
 }
 
-/* 
- * Draw board perimeter.
- * The first segment is part of the first polygon.
- * The first polygon of the board perimeter is positive, the rest are holes.
- * Segments do not necesarily occur in order.
+/*
+ * SEG subrecord of NET record. line segment.
  */
 
-void hyp_perimeter()
+pcb_bool exec_seg(parse_param * h)
 {
-  pcb_bool_t warn_not_closed;
-  pcb_bool_t segment_found;
-  pcb_bool_t polygon_closed;
-  pcb_coord_t begin_x, begin_y, last_x, last_y;
-  outline_t *i;
-  outline_t *j;
-
-  warn_not_closed = pcb_false;
-
-  /* iterate over perimeter segments and adjust origin */
-  for (i = outline_head; i != NULL; i = i->next) {
-    /* set origin so all coordinates are positive */
-    i->x1 -= origin_x;
-    i->y1 -= origin_y;
-    i->x2 -= origin_x;
-    i->y2 -= origin_y;
-    if (i->is_arc) {
-      i->xc -= origin_x;
-      i->yc -= origin_y;
-      }
-    }
-
-  /* iterate over perimeter polygons */
-  while (pcb_true)
-  {
-
-    /* find first free segment */
-    for (i = outline_head; i != NULL; i = i->next)
-      if (i->used == pcb_false) break;
-
-    /* exit if no segments found */
-    if (i == NULL) break;
-
-    /* first point of polygon (begin_x, begin_y) */
-    begin_x = i->x1;
-    begin_y = i->y1;
-
-    /* last point of polygon (last_x, last_y) */
-    last_x = i->x2;
-    last_y = i->y2;
-
-    /* add segment */
-    perimeter_segment_add(i, pcb_true);
-
-    /* add polygon segments until the polygon is closed */
-    polygon_closed = pcb_false;
-    while (!polygon_closed)
-    {
+	if (hyp_debug) {
+		pcb_printf("seg: x1 = %ml y1 = %ml x2 = %ml y2 = %ml ", x2coord(h->x1), y2coord(h->y1), x2coord(h->x2), y2coord(h->y2));
+		pcb_printf(" width = %ml layer_name = \"%s\"", xy2coord(h->width), h->layer_name);
+		if (h->plane_separation_set)
+			pcb_printf(" plane_separation = %ml ", xy2coord(h->plane_separation));
+		if (h->left_plane_separation_set)
+			pcb_printf(" left_plane_separation = %ml ", xy2coord(h->left_plane_separation));
+		pcb_printf("\n");
+	}
+
+	pcb_line_new(hyp_get_layer(h), x2coord(h->x1), y2coord(h->y1), x2coord(h->x2), y2coord(h->y2), xy2coord(h->width),
+							 hyp_clearance(h), pcb_no_flags());
+
+	return 0;
+}
+
+/*
+ * ARC subrecord of NET record. arc segment, drawn clockwise.
+ */
+
+pcb_bool exec_arc(parse_param * h)
+{
+
+	if (hyp_debug) {
+		pcb_printf("arc: x1 = %ml y1 = %ml x2 = %ml y2 = %ml", x2coord(h->x1), y2coord(h->y1), x2coord(h->x2), y2coord(h->y2));
+		pcb_printf(" xc = %ml yc = %ml r = %ml", x2coord(h->xc), y2coord(h->yc), xy2coord(h->r));
+		pcb_printf(" width = %ml layer_name = \"%s\"", xy2coord(h->width), h->layer_name);
+		if (h->plane_separation_set)
+			pcb_printf(" plane_separation = %ml", xy2coord(h->plane_separation));
+		if (h->left_plane_separation_set)
+			pcb_printf(" left_plane_separation = %ml", xy2coord(h->left_plane_separation));
+		pcb_printf("\n");
+	}
+
+	hyp_arc_new(hyp_get_layer(h), x2coord(h->x1), y2coord(h->y1), x2coord(h->x2), y2coord(h->y2), x2coord(h->xc),
+							y2coord(h->yc), xy2coord(h->r), xy2coord(h->r), pcb_true, xy2coord(h->width), hyp_clearance(h), pcb_no_flags());
+
+	return 0;
+}
+
+/*
+ * VIA subrecord of NET record. 
+ * Draws via using padstack definition.
+ */
+
+pcb_bool exec_via(parse_param * h)
+{
+	padstack_t *padstack;
+	pcb_flag_t flags;
+
+	if (hyp_debug) {
+		pcb_printf("via: x = %ml y = %ml", x2coord(h->x), y2coord(h->y));
+		if (h->layer1_name_set)
+			pcb_printf(" layer1_name = \"%s\"", h->layer1_name);
+		if (h->layer2_name_set)
+			pcb_printf(" layer2_name = \"%s\"", h->layer2_name);
+		if (h->padstack_name_set)
+			pcb_printf(" padstack_name = \"%s\"", h->padstack_name);
+		pcb_printf("\n");
+	}
+
+	if (!h->padstack_name_set) {
+		if (hyp_debug)
+			pcb_printf("via: padstack not set. skipping via x = %ml y = %ml\n", x2coord(h->x), y2coord(h->y));
+		return 0;
+	}
+
+	padstack = hyp_padstack_by_name(h->padstack_name);
+	if (padstack == NULL) {
+		pcb_printf("via: padstack \"%s\" not found. skipping.\n", h->padstack_name);
+		return 0;
+	}
+
+	if (padstack->is_round)
+		flags = pcb_no_flags();
+	else
+		flags = pcb_flag_make(PCB_FLAG_SQUARE);
+
+	pcb_via_new(hyp_dest, x2coord(h->x), y2coord(h->y), padstack->thickness, padstack->clearance, padstack->mask,
+							padstack->drill_hole, "", flags);
+
+	return 0;
+}
+
+/*
+ * VIA subrecord of NET record. 
+ * Draws deprecated v1.x via. Does not use padstack.
+ */
+
+pcb_bool exec_via_v1(parse_param * h)
+{
+	pcb_coord_t thickness;
+	pcb_coord_t clearance;
+	pcb_coord_t mask;
+	pcb_coord_t drill_hole;
+	pcb_bool_t is_round;
+	pcb_flag_t flags;
+
+	if (hyp_debug) {
+		pcb_printf("old via: x = %ml y = %ml", x2coord(h->x), y2coord(h->y));
+		pcb_printf(" drill_size = %ml", xy2coord(h->drill_size));
+		if (h->layer1_name_set)
+			pcb_printf(" layer1_name = \"%s\"", h->layer1_name);
+		if (h->layer2_name_set)
+			pcb_printf(" layer2_name = \"%s\"", h->layer2_name);
+		pcb_printf(" pad1_shape = \"%s\" pad1_sx = %ml pad1_sy = %ml pad1_angle = %f", h->pad1_shape, xy2coord(h->pad1_sx),
+							 xy2coord(h->pad1_sy), h->pad1_angle);
+		pcb_printf(" pad2_shape = \"%s\" pad2_sx = %ml pad2_sy = %ml pad2_angle = %f", h->pad2_shape, xy2coord(h->pad2_sx),
+							 xy2coord(h->pad2_sy), h->pad2_angle);
+		pcb_printf("\n");
+	}
+
+	thickness = xy2coord(h->pad_sx);
+	clearance = 2 * hyp_clearance(h);
+	mask = xy2coord(h->pad1_sx);
+	drill_hole = xy2coord(h->drill_size);
+	is_round = (strcmp(h->pad1_shape, "RECT") != 0);
+
+	if (is_round)
+		flags = pcb_no_flags();
+	else
+		flags = pcb_flag_make(PCB_FLAG_SQUARE);
+
+	pcb_via_new(hyp_dest, x2coord(h->x), y2coord(h->y), thickness, clearance, mask, drill_hole, NULL, flags);
+
+	return 0;
+}
+
+/*
+ * PIN subrecord of NET record. 
+ * Draws PIN using padstack definiton.
+ */
+
+pcb_bool exec_pin(parse_param * h)
+{
+	pcb_element_t *component;
+	pcb_flag_t flags;
+	padstack_t *padstack;
+	char *component_name = NULL;
+	char *pin_name = NULL;
+	char *dot = NULL;
+	char *pin_net_name = NULL;
+
+	if (hyp_debug) {
+		pcb_printf("pin: x = %ml y = %ml", x2coord(h->x), y2coord(h->y));
+		pcb_printf(" pin_reference = \"%s\"", h->pin_reference);
+		if (h->padstack_name_set)
+			pcb_printf(" padstack_name = \"%s\"", h->padstack_name);
+		if (h->pin_function_set)
+			pcb_printf(" pin_function = %i", h->pin_function);
+		pcb_printf("\n");
+	}
+
+	if (!h->padstack_name_set) {
+		if (hyp_debug)
+			pcb_printf("pin: padstack not set. skipping pin \"%s\"\n", h->pin_reference);
+		return 0;
+	}
+
+	if (net_name != NULL)
+		pin_net_name = pcb_strdup(net_name);
+	else
+		pin_net_name = pcb_strdup("?");
+
+	/* h->pin_reference has format 'component_name.pin_name' */
+	component_name = pcb_strdup(h->pin_reference);
+	pin_name = pcb_strdup("?");
+	dot = strrchr(component_name, '.');
+	if (dot != NULL) {
+		*dot = '\0';
+		pin_name = pcb_strdup(dot + 1);
+		if (hyp_debug)
+			pcb_printf("pin: component_name = \"%s\" pin_name = \"%s\"\n", component_name, pin_name);
+	}
+
+	/* find component by name */
+	component = pcb_search_elem_by_name(hyp_dest, component_name);
+	if (component == NULL) {
+		pcb_printf("pin: component \"%s\" not found. skipping pin \"%s\"\n", component_name, h->pin_reference);
+		return 0;
+	}
+
+	/* find padstack */
+	padstack = hyp_padstack_by_name(h->padstack_name);
+	if (padstack == NULL) {
+		pcb_printf("pin: padstack \"%s\" not found. skipping pin \"%s\"\n", h->padstack_name, h->pin_reference);
+		return 0;
+	}
+
+	/* add new pin */
+	if (padstack->is_round)
+		flags = pcb_no_flags();
+	else
+		flags = pcb_flag_make(PCB_FLAG_SQUARE);
+
+	pcb_element_pin_new(component, x2coord(h->x), y2coord(h->y), padstack->thickness, padstack->clearance, padstack->mask,
+											padstack->drill_hole, pin_net_name, pin_name, flags);
 
-#undef XXX
 #ifdef XXX
-      pcb_printf("perimeter: last_x = %mm last_y = %mm\n", last_x, last_y);
-      for (i = outline_head; i != NULL; i = i->next)
-        if (!i->used) pcb_printf("perimeter segments available: %s from (%mm, %mm) to (%mm, %mm)\n", i->is_arc ? "arc" : "line", i->x1, i->y1, i->x2, i->y2);
+	/* XXX causes crash */
+	/* move component to pin location */
+	pcb_element_move(hyp_dest, component, x2coord(h->x), y2coord(h->y));
 #endif
 
-      /* find segment to add to current polygon */
-      segment_found = pcb_false;
-
-      /* XXX prefer closed polygon over open polyline */
-
-      for (i = outline_head; i != NULL; i = i->next)
-      {
-        if (i->used) continue;
-
-        if ((last_x == i->x1) && (last_y == i->y1))
-        {
-          if (!segment_connected(i->x2, i->y2, begin_x, begin_y, i)) continue; /* XXX Checkme */
-          /* first point of segment is last point of current edge: add segment to edge */
-          segment_found = pcb_true;
-          perimeter_segment_add(i, pcb_true);
-          last_x = i->x2;
-          last_y = i->y2;
-        }
-        else if ((last_x == i->x2) && (last_y == i->y2))
-        {
-          if (!segment_connected(i->x1, i->y1, begin_x, begin_y, i)) continue; /* XXX Checkme */
-          /* last point of segment is last point of current edge: add segment to edge back to front */
-          segment_found = pcb_true;
-          /* add segment back to front */
-          perimeter_segment_add(i, pcb_false);
-          last_x = i->x1;
-          last_y = i->y1;
-        }
-        if (segment_found) break;
-      }
-      polygon_closed = (begin_x == last_x) && (begin_y == last_y);
-      if (!polygon_closed && !segment_found)
-        break;                   /* can't find anything suitable */
-    }
-    if (polygon_closed) { 
-      if (hyp_debug) pcb_printf("outline: closed\n");
-      }
-    else 
-      {
-        if (hyp_debug) pcb_printf("outline: open\n");
-        warn_not_closed = pcb_true;
-      }
-  }
-
-  /* free segment memory */
-  for (i = outline_head; i != NULL; i = j)
-  {
-    j = i->next;
-    free (i);
-  }
-  outline_head = outline_tail = NULL;
-
-  if (warn_not_closed) pcb_message(PCB_MSG_DEBUG, "warning: board outline not closed\n");
-
-  return;
-}
-
-pcb_bool exec_options(parse_param *h){return(0);}
-pcb_bool exec_signal(parse_param *h){return(0);}
-pcb_bool exec_dielectric(parse_param *h){return(0);}
-pcb_bool exec_plane(parse_param *h){return(0);}
-
-pcb_bool exec_devices(parse_param *h){return(0);}
-
-pcb_bool exec_supplies(parse_param *h){return(0);}
-
-pcb_bool exec_padstack_element(parse_param *h){return(0);}
-pcb_bool exec_padstack_end(parse_param *h){return(0);}
-
-pcb_bool exec_net(parse_param *h){return(0);}
-pcb_bool exec_net_plane_separation(parse_param *h){return(0);}
-pcb_bool exec_net_attribute(parse_param *h){return(0);}
-pcb_bool exec_seg(parse_param *h){return(0);}
-pcb_bool exec_arc(parse_param *h){return(0);}
-pcb_bool exec_via(parse_param *h){return(0);}
-pcb_bool exec_via_v1(parse_param *h){return(0);}
-pcb_bool exec_pin(parse_param *h){return(0);}
-pcb_bool exec_pad(parse_param *h){return(0);}
-pcb_bool exec_useg(parse_param *h){return(0);}
-
-pcb_bool exec_polygon_begin(parse_param *h){return(0);}
-pcb_bool exec_polygon_end(parse_param *h){return(0);}
-pcb_bool exec_polyvoid_begin(parse_param *h){return(0);}
-pcb_bool exec_polyvoid_end(parse_param *h){return(0);}
-pcb_bool exec_polyline_begin(parse_param *h){return(0);}
-pcb_bool exec_polyline_end(parse_param *h){return(0);}
-pcb_bool exec_line(parse_param *h){return(0);}
-pcb_bool exec_curve(parse_param *h){return(0);}
-
-pcb_bool exec_net_class(parse_param *h){return(0);}
-pcb_bool exec_net_class_element(parse_param *h){return(0);}
-pcb_bool exec_net_class_attribute(parse_param *h){return(0);}
-
-pcb_bool exec_end(parse_param *h){return(0);}
-pcb_bool exec_key(parse_param *h){return(0);}
+	return 0;
+}
+
+/*
+ * PAD subrecord of NET record. 
+ * Draws deprecated v1.x pad.
+ */
+
+pcb_bool exec_pad(parse_param * h)
+{
+	pcb_element_t *component;
+	pcb_flag_t flags;
+	char pad_component[] = "hyperlynx_pad";
+	pcb_uint8_t text_direction = 0;
+	int text_scale = 100;
+
+	if (hyp_debug) {
+		pcb_printf("pad: x = %ml y = %ml", x2coord(h->x), y2coord(h->y));
+		if (h->layer_name_set)
+			pcb_printf(" layer_name = \"%s\"", h->layer_name);
+		pcb_printf(" pad1_shape = \"%s\" pad1_sx = %ml pad1_sy = %ml pad1_angle = %f", h->pad1_shape, xy2coord(h->pad1_sx),
+							 xy2coord(h->pad1_sy), h->pad1_angle);
+		pcb_printf("\n");
+	}
+
+	/* if necessary, create a device to connect the pad to */
+	component = pcb_search_elem_by_name(hyp_dest, pad_component);
+	if (component == NULL)
+		component = pcb_element_new(hyp_dest, NULL, &PCB->Font, pcb_no_flags(), pad_component, pad_component, "?",
+																x2coord(h->x), y2coord(h->y), text_direction, text_scale, pcb_no_flags(), pcb_false);
+
+	/* add new pad */
+	/* XXX fixme. Pad ought to be on a single layer. This puts the pad on all layers. */
+  /* XXX set flags PCB_COMPONENT_SIDE PCB_SOLDER_SIDE */
+	if (strcmp(h->pad1_shape, "RECT") != 0)
+		flags = pcb_no_flags();
+	else
+		flags = pcb_flag_make(PCB_FLAG_SQUARE);
+
+	pcb_element_pin_new(component, x2coord(h->x), y2coord(h->y), xy2coord(h->pad1_sx), 2 * hyp_clearance(h), xy2coord(h->pad1_sx),
+											0, net_name, "?", flags);
+
+	return 0;
+}
 
 /*
- * Draw arc from (x1, y1) to (x2, y2) with center (xc, yc) and radius r. 
- * Direction of arc is clockwise or counter-clockwise, depending upon value of pcb_bool_t Clockwise.
+ * USEG subrecord of NET record.
+ * unrouted segment.
  */
 
-pcb_arc_t *hyp_arc_new(pcb_layer_t *Layer, pcb_coord_t X1, pcb_coord_t Y1, pcb_coord_t X2, pcb_coord_t Y2, pcb_coord_t XC, pcb_coord_t YC, pcb_coord_t Width, pcb_coord_t Height, pcb_bool_t Clockwise, pcb_coord_t Thickness, pcb_coord_t Clearance, pcb_flag_t Flags)
+pcb_bool exec_useg(parse_param * h)
 {
-  pcb_angle_t start_angle;
-  pcb_angle_t end_angle;
-  pcb_angle_t delta;
+	pcb_layergrp_id_t layer1_grp_id, layer2_grp_id;
+
+	if (hyp_debug) {
+		pcb_printf("useg: x1 = %ml y1 = %ml layer1_name = \"%s\"", x2coord(h->x1), y2coord(h->y1), h->layer1_name);
+		pcb_printf(" x2 = %ml y2 = %ml layer2_name = \"%s\"", x2coord(h->x2), y2coord(h->y2), h->layer2_name);
+		if (h->zlayer_name_set)
+			pcb_printf(" zlayer_name = \"%s\" width = %ml length = %ml", h->zlayer_name, xy2coord(h->width), xy2coord(h->length));
+		if (h->impedance_set)
+			pcb_printf(" impedance = %f delay = %f ", h->impedance, h->delay);
+		if (h->resistance_set)
+			pcb_printf(" resistance = %f ", h->resistance);
+		pcb_printf("\n");
+	}
+
+	/* lookup layer group begin and end layer are on */
+	layer1_grp_id = pcb_layer_get_group(hyp_create_layer(h->layer1_name));
+	layer2_grp_id = pcb_layer_get_group(hyp_create_layer(h->layer2_name));
+
+	if ((layer1_grp_id == -1) || (layer2_grp_id == -1)) {
+		if (hyp_debug)
+			pcb_printf("skipping unrouted segment\n");
+		return 0;
+	}
+
+	pcb_rat_new(hyp_dest, x2coord(h->x1), y2coord(h->y1), x2coord(h->x2), y2coord(h->y2), layer1_grp_id, layer2_grp_id,
+							xy2coord(h->width), pcb_no_flags());
+
+	return 0;
+}
 
-  if (Width < 1) {
-    start_angle = 0.0;
-    delta = 360.0; /* XXX !!! */
-    }
-  else {
-    start_angle = 180*atan2(Y1 - YC, X1 - XC)/M_PI;
-    end_angle = 180*atan2(Y2 - YC, X2 - XC)/M_PI;
-    delta = end_angle - start_angle;
-    }
+/*
+ * POLYGON subrecord of NET record.
+ * draws copper polygon.
+ */
+
+/* XXX still need to implement different types (POUR, COPPER, PLANE) */
+
+pcb_bool exec_polygon_begin(parse_param * h)
+{
+	pcb_layer_t *current_layer;
+	hyp_polygon_t *new_poly;
+
+	if (hyp_debug) {
+		pcb_printf("polygon begin:");
+		if (h->layer_name_set)
+			pcb_printf(" layer_name = \"%s\"", h->layer_name);
+		if (h->width_set)
+			pcb_printf(" width = %ml", xy2coord(h->width));
+		if (h->polygon_type_set) {
+			pcb_printf(" polygon_type = ", h->polygon_type, " ");
+			switch (h->polygon_type) {
+			case POLYGON_TYPE_PLANE:
+				pcb_printf("POLYGON_TYPE_PLANE");
+				break;
+			case POLYGON_TYPE_POUR:
+				pcb_printf("POLYGON_TYPE_POUR");
+				break;
+			case POLYGON_TYPE_COPPER:
+				pcb_printf("POLYGON_TYPE_COPPER");
+				break;
+			default:
+				pcb_printf("Error");
+				break;
+			}
+		}
+		if (h->id_set)
+			pcb_printf(" id = %i", h->id);
+		pcb_printf(" x = %ml y = %ml\n", xy2coord(h->x), xy2coord(h->y));
+	}
+
+	if (!h->layer_name_set) {
+		hyp_error("expected polygon layer L = ");
+		return pcb_true;
+	}
+
+	if (!h->id_set) {
+		hyp_error("expected polygon id ID = ");
+		return pcb_true;
+	}
+
+	/* create empty pcb polygon */
+	current_layer = hyp_get_layer(h);
+	current_polygon = pcb_poly_new(current_layer, pcb_flag_make(PCB_FLAG_CLEARPOLY));
+
+	/* add first vertex */
+	if (current_polygon != NULL)
+		pcb_poly_point_new(current_polygon, x2coord(h->x), y2coord(h->y));
+
+	/* bookkeeping */
+	if ((poly_state != HYP_POLYIDLE) && hyp_debug)
+		pcb_printf("polygon: unexpected polygon. continuing.\n");
+	poly_state = HYP_POLYGON;
+
+	new_poly = malloc(sizeof(hyp_polygon_t));
+	new_poly->hyp_poly_id = h->id;	/* hyperlynx polygon/polyline id */
+	new_poly->polygon = current_polygon;
+	new_poly->layer = current_layer;
+	new_poly->is_polygon = pcb_true;
+
+	new_poly->next = polygon_head;
+	polygon_head = new_poly;
+
+	return 0;
+}
+
+pcb_bool exec_polygon_end(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("polygon end:\n");
 
-  if (Clockwise && (delta < 0.0)) delta += 360.0;
-  if (!Clockwise && (delta > 0.0)) delta = 360.0 - delta;
+	/* bookkeeping */
+	if ((poly_state != HYP_POLYGON) && hyp_debug)
+		pcb_printf("polygon: unexpected polygon end. continuing.\n");
+	poly_state = HYP_POLYIDLE;
+	current_polygon = NULL;
 
-  /* for circle width = height = radius? XXX */
+	return 0;
+}
+
+/*
+ * POLYVOID subrecord of NET record.
+ * same as POLYGON, but instead of creating copper, creates a hole in copper.
+ */
+
+pcb_bool exec_polyvoid_begin(parse_param * h)
+{
+	hyp_polygon_t *i;
+
+	if (hyp_debug) {
+		pcb_printf("polyvoid begin:");
+		if (h->id_set)
+			pcb_printf(" id = %i", h->id);
+		pcb_printf(" x = %ml y = %ml\n", x2coord(h->x), y2coord(h->y));
+	}
+
+	if (!h->id_set) {
+		hyp_error("expected polygon id ID = ");
+		return pcb_true;
+	}
+
+	/* look up polygon with this id */
+	current_polygon = NULL;
+	for (i = polygon_head; i != NULL; i = i->next)
+		if (h->id == i->hyp_poly_id) {
+			if (i->is_polygon)
+				current_polygon = i->polygon;
+			else
+				pcb_printf("polyvoid: polyvoid hole in polyline not implemented.\n");
+		}
+
+	if (i == NULL)
+		pcb_printf("polyvoid: polygon id %i not found\n", h->id);
+
+	if (current_polygon != NULL) {
+		/* create hole in polygon */
+		pcb_poly_hole_new(current_polygon);
+		/* add first vertex of hole */
+		pcb_poly_point_new(current_polygon, x2coord(h->x), y2coord(h->y));
+	}
+
+	/* bookkeeping */
+	if ((poly_state != HYP_POLYIDLE) && hyp_debug)
+		pcb_printf("polyvoid: unexpected polyvoid. continuing.\n");
+	if (i->is_polygon)
+		poly_state = HYP_POLYGON_HOLE;
+	else
+		poly_state = HYP_POLYLINE_HOLE;
+
+	return 0;
+}
+
+pcb_bool exec_polyvoid_end(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("polyvoid end:\n");
+
+	/* bookkeeping */
+	if ((poly_state != HYP_POLYGON_HOLE) && (poly_state != HYP_POLYLINE_HOLE) && hyp_debug)
+		pcb_printf("polyvoid: unexpected polyvoid end. continuing.\n");
+	poly_state = HYP_POLYIDLE;
+
+	return 0;
+}
+
+/*
+ * POLYLINE subrecord of NET record.
+ */
+
+pcb_bool exec_polyline_begin(parse_param * h)
+{
+	hyp_polygon_t *new_poly;
+
+	if (hyp_debug) {
+		pcb_printf("polyline begin:");
+		if (h->layer_name_set)
+			pcb_printf(" layer_name = \"%s\"", h->layer_name);
+		if (h->width_set)
+			pcb_printf(" width = %ml", xy2coord(h->width));
+		if (h->polygon_type_set) {
+			pcb_printf(" polygon_type = ", h->polygon_type, " ");
+			switch (h->polygon_type) {
+			case POLYGON_TYPE_PLANE:
+				pcb_printf("POLYGON_TYPE_PLANE");
+				break;
+			case POLYGON_TYPE_POUR:
+				pcb_printf("POLYGON_TYPE_POUR");
+				break;
+			case POLYGON_TYPE_COPPER:
+				pcb_printf("POLYGON_TYPE_COPPER");
+				break;
+			default:
+				pcb_printf("Error");
+				break;
+			}
+		}
+		if (h->id_set)
+			pcb_printf(" id = %i", h->id);
+		pcb_printf(" x = %ml y = %ml\n", x2coord(h->x), y2coord(h->y));
+	}
+
+	if (!h->layer_name_set) {
+		hyp_error("expected polygon layer L = ");
+		return pcb_true;
+	}
+
+	if (!h->width_set) {
+		hyp_error("expected polygon width W = ");
+		return pcb_true;
+	}
+
+	if (!h->id_set) {
+		hyp_error("expected polygon id ID = ");
+		return pcb_true;
+	}
+
+	/* create polyline */
+	current_polygon = NULL;
+	current_polyline_layer = hyp_get_layer(h);
+	current_polyline_width = xy2coord(h->width);
+	current_polyline_clearance = hyp_clearance(h);
+	current_polyline_xpos = x2coord(h->x);
+	current_polyline_ypos = y2coord(h->y);
+
+	/* bookkeeping */
+	if ((poly_state != HYP_POLYIDLE) && hyp_debug)
+		pcb_printf("polyline: unexpected polyline. continuing.\n");
+	poly_state = HYP_POLYLINE;
+
+	/* we need to store the id of the polyline, in case a matching polyvoid occurs. */
+	new_poly = malloc(sizeof(hyp_polygon_t));
+	new_poly->hyp_poly_id = h->id;	/* hyperlynx polygon/polyline id */
+	new_poly->polygon = NULL;
+	new_poly->layer = current_polyline_layer;
+	new_poly->is_polygon = pcb_false;
+
+	new_poly->next = polygon_head;
+	polygon_head = new_poly;
+
+	return 0;
+}
+
+pcb_bool exec_polyline_end(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("polyline end:\n");
+
+	/* bookkeeping */
+	if ((poly_state != HYP_POLYLINE) && hyp_debug)
+		pcb_printf("polyline: unexpected polyline end. continuing.\n");
+
+	poly_state = HYP_POLYIDLE;
+	current_polygon = NULL;
+	current_polyline_layer = NULL;
+	current_polyline_width = 0;
+	current_polyline_clearance = 0;
+	current_polyline_xpos = 0;
+	current_polyline_ypos = 0;
+
+	return 0;
+}
+
+/*
+ * LINE subrecord of NET record.
+ */
+
+pcb_bool exec_line(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("line: x = %ml y = %ml\n", x2coord(h->x), y2coord(h->y));
+
+	switch (poly_state) {
+	case HYP_POLYIDLE:
+		if (hyp_debug)
+			pcb_printf("line: unexpected. continuing.\n");
+		break;
+	case HYP_POLYGON:
+	case HYP_POLYGON_HOLE:
+		/* add new vertex to polygon */
+		if (current_polygon != NULL)
+			pcb_poly_point_new(current_polygon, x2coord(h->x), y2coord(h->y));
+		break;
+	case HYP_POLYLINE:
+		/* add new point to polyline */
+		if (current_polyline_layer != NULL) {
+			pcb_line_new(current_polyline_layer, current_polyline_xpos, current_polyline_ypos, x2coord(h->x), y2coord(h->y),
+									 current_polyline_width, current_polyline_clearance, pcb_no_flags());
+			/* move on */
+			current_polyline_xpos = x2coord(h->x);
+			current_polyline_ypos = y2coord(h->y);
+		}
+		break;
+	case HYP_POLYLINE_HOLE:
+		/* not implemented */
+		break;
+	default:
+		if (hyp_debug)
+			pcb_printf("line: error\n");
+	}
+
+	return 0;
+}
+
+/*
+ * CURVE subrecord of NET record. 
+ * Clockwise from (x1, y1) to (x2, y2).
+ */
+
+pcb_bool exec_curve(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("curve: x1 = %ml y1 = %ml x2 = %ml y2 = %ml xc = %ml yc = %ml r = %ml\n", x2coord(h->x1), y2coord(h->y1),
+							 x2coord(h->x2), y2coord(h->y2), x2coord(h->xc), y2coord(h->yc), xy2coord(h->r));
+
+	switch (poly_state) {
+	case HYP_POLYIDLE:
+		if (hyp_debug)
+			pcb_printf("curve: unexpected. continuing.\n");
+		break;
+	case HYP_POLYGON:
+	case HYP_POLYGON_HOLE:
+		if (current_polygon != NULL) {
+			/* polygon contains line segments, not arc segments. convert arc segment to line segments. */
+			pcb_poly_point_new(current_polygon, x2coord(h->x2), y2coord(h->y2));	/* 2do XXX */
+		}
+		break;
+	case HYP_POLYLINE:
+		if (current_polyline_layer != NULL) {
+			/* clockwise arc from (x1, y2) to (x2, y2) */
+			hyp_arc_new(current_polyline_layer, x2coord(h->x1), y2coord(h->y1), x2coord(h->x2), y2coord(h->y2), x2coord(h->xc),
+									y2coord(h->yc), 2 * xy2coord(h->r), 2 * xy2coord(h->r), pcb_true, current_polyline_width,
+									current_polyline_clearance, pcb_no_flags());
+
+			/* move on */
+			if ((current_polyline_xpos == x2coord(h->x1)) && (current_polyline_ypos == y2coord(h->y1))) {
+				current_polyline_xpos = x2coord(h->x2);
+				current_polyline_ypos = y2coord(h->y2);
+			}
+			else if ((current_polyline_xpos == x2coord(h->x2)) && (current_polyline_ypos == y2coord(h->y2))) {
+				current_polyline_xpos = x2coord(h->x1);
+				current_polyline_ypos = y2coord(h->y1);
+			}
+		}
+		break;
+	case HYP_POLYLINE_HOLE:
+		/* not implemented */
+		break;
+	default:
+		if (hyp_debug)
+			pcb_printf("curve: error\n");
+	}
+
+	return 0;
+}
+
+/*
+ * NET_CLASS record
+ */
+
+pcb_bool exec_net_class(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("net_class: net_class_name = \"%s\"\n", h->net_class_name);
+
+	return 0;
+}
+
+/*
+ * N net membership subrecord of NET_CLASS record
+ */
+
+pcb_bool exec_net_class_element(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("net_class_element: net_name = \"%s\"\n", h->net_name);
+
+	return 0;
+}
+
+/*
+ * A attribute subrecord of NET_CLASS record
+ */
+
+
+pcb_bool exec_net_class_attribute(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("netclass_attribute: name = \"%s\" value = \"%s\"\n", h->name, h->value);
+
+	return 0;
+}
+
+/* 
+ * KEY record
+ */
+
+pcb_bool exec_key(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("key: key = \"%s\"\n", h->key);
+
+	return 0;
+}
+
+/* 
+ * END record
+ */
+
+pcb_bool exec_end(parse_param * h)
+{
+	if (hyp_debug)
+		pcb_printf("end\n");
 
-  return pcb_arc_new(Layer, XC, YC, Width, Height, start_angle, delta, Thickness, Clearance, Flags);
+	return 0;
 }
 
 /* not truncated */
diff --git a/src_plugins/import_hyp/parser.h b/src_plugins/import_hyp/parser.h
index 06bcae0..e32c330 100644
--- a/src_plugins/import_hyp/parser.h
+++ b/src_plugins/import_hyp/parser.h
@@ -25,208 +25,210 @@
 #include "pcb_bool.h"
 #include "board.h"
 
-  /* 
-   * Parameters passed on by the parser.
-   * All variables added here are initialized in new_record().
-   */
-
-  typedef enum { PAD_TYPE_METAL, PAD_TYPE_ANTIPAD, PAD_TYPE_THERMAL_RELIEF } pad_type_enum;
-
-  typedef enum { PIN_SIM_IN, PIN_SIM_OUT, PIN_SIM_BOTH } pin_function_enum;
-
-  typedef enum { POLYGON_TYPE_POUR, POLYGON_TYPE_PLANE, POLYGON_TYPE_COPPER, POLYGON_TYPE_PAD, POLYGON_TYPE_ANTIPAD } polygon_type_enum;
-
-  typedef struct {
-    double vers;   /* version of the hyp file format */
-    pcb_bool detailed; /* data detailed enough for power integrity */
-    pcb_bool unit_system_english; /* english or metric units */
-    pcb_bool metal_thickness_weight; /* copper by weight or by length */
-    double default_plane_separation; /* trace to plane separation */
-    
-    /* stackup record */
-    pcb_bool use_die_for_metal; /* dielectric constant and loss tangent of dielectric for metal layers */
-    double bulk_resistivity;
-    pcb_bool conformal;
-    double epsilon_r;
-    char *layer_name;
-    double loss_tangent;
-    char *material_name;
-    double plane_separation;
-    double plating_thickness;
-    pcb_bool prepreg;
-    double temperature_coefficient; /* temperature coefficient of resistivity */
-    double thickness; /* layer thickness */
-
-    /* stackup record flags */
-    pcb_bool bulk_resistivity_set;
-    pcb_bool conformal_set;
-    pcb_bool epsilon_r_set;
-    pcb_bool layer_name_set;
-    pcb_bool loss_tangent_set;
-    pcb_bool material_name_set;
-    pcb_bool plane_separation_set;
-    pcb_bool plating_thickness_set;
-    pcb_bool prepreg_set;
-    pcb_bool temperature_coefficient_set;
-    pcb_bool thickness_set;
-    
-    /* device record */
-    char *device_type;
-    char *ref;
-    double value_float;
-    char *value_string;
-    char *package;
-
-    /* device record flags */
-    pcb_bool name_set;
-    pcb_bool value_float_set;
-    pcb_bool value_string_set;
-    pcb_bool package_set;
-
-    /* supplies record */
-    pcb_bool voltage_specified;
-    pcb_bool conversion;
-
-    /* padstack record */
-    char *padstack_name;
-    double drill_size;
-    double pad_shape;
-    double pad_sx;
-    double pad_sy;
-    double pad_angle;
-    double thermal_clear_shape;
-    double thermal_clear_sx;
-    double thermal_clear_sy;
-    double thermal_clear_angle;
-    pad_type_enum pad_type;
-
-    /* padstack record flags */
-    pcb_bool padstack_name_set;
-    pcb_bool drill_size_set;
-    pcb_bool pad_type_set;
-
-    /* net record */
-    double width;
-    double left_plane_separation;
-    pcb_bool width_set;
-    pcb_bool left_plane_separation_set;
-
-    /* via subrecord of net */
-    char *layer1_name;
-    pcb_bool layer1_name_set;
-    char *layer2_name;
-    pcb_bool layer2_name_set;
-    char *pad1_shape;
-    double pad1_sx;
-    double pad1_sy;
-    double pad1_angle;
-    char *pad2_shape;
-    double pad2_sx;
-    double pad2_sy;
-    double pad2_angle;
-
-    /* pin subrecord of net */
-    char *pin_reference;
-    pcb_bool pin_reference_set;
-    pin_function_enum pin_function;
-    pcb_bool pin_function_set;
-
-    /* useg subrecord of net */
-    char *zlayer_name;
-    pcb_bool zlayer_name_set;
-    double length;
-    double impedance;
-    pcb_bool impedance_set;
-    double delay;
-    double resistance;
-    pcb_bool resistance_set;
-
-    /* polygon subrecord of net */
-    int id;
-    pcb_bool id_set;
-    polygon_type_enum polygon_type;
-    pcb_bool polygon_type_set;
-
-    /* net class record */
-    char *net_class_name;
-    char *net_name;
-
-    /* key record */
-    char *key;
-
-    /* Attributes */
-    char *name; /* attribute name */
-    char *value; /* attribute value */
-    
-    /* point, line and arc coordinates */
-    double x; /* coordinates point */
-    double y; /* coordinates point */
-    double x1; /* coordinates point 1 */
-    double y1; /* coordinates point 1 */
-    double x2; /* coordinates point 2 */
-    double y2; /* coordinates point 2 */
-    double xc; /* coordinates arc */
-    double yc; /* coordinates arc */
-    double r; /* coordinates arc */
-  } parse_param;
-
-  /* exec_* routines are called by parser to interpret hyperlynx file */ 
-  pcb_bool exec_board_file(parse_param *h);
-  pcb_bool exec_version(parse_param *h);
-  pcb_bool exec_data_mode(parse_param *h);
-  pcb_bool exec_units(parse_param *h);
-  pcb_bool exec_plane_sep(parse_param *h);
-  pcb_bool exec_perimeter_segment(parse_param *h);
-  pcb_bool exec_perimeter_arc(parse_param *h);
-  pcb_bool exec_board_attribute(parse_param *h);
-  
-  pcb_bool exec_options(parse_param *h);
-  pcb_bool exec_signal(parse_param *h);
-  pcb_bool exec_dielectric(parse_param *h);
-  pcb_bool exec_plane(parse_param *h);
-  
-  pcb_bool exec_devices(parse_param *h);
-  
-  pcb_bool exec_supplies(parse_param *h);
-  
-  pcb_bool exec_padstack_element(parse_param *h);
-  pcb_bool exec_padstack_end(parse_param *h);
-  
-  pcb_bool exec_net(parse_param *h);
-  pcb_bool exec_net_plane_separation(parse_param *h);
-  pcb_bool exec_net_attribute(parse_param *h);
-  pcb_bool exec_seg(parse_param *h);
-  pcb_bool exec_arc(parse_param *h);
-  pcb_bool exec_via(parse_param *h);
-  pcb_bool exec_via_v1(parse_param *h); /* Old style via format */ 
-  pcb_bool exec_pin(parse_param *h);
-  pcb_bool exec_pad(parse_param *h);
-  pcb_bool exec_useg(parse_param *h);
-  
-  pcb_bool exec_polygon_begin(parse_param *h);
-  pcb_bool exec_polygon_end(parse_param *h);
-  pcb_bool exec_polyvoid_begin(parse_param *h);
-  pcb_bool exec_polyvoid_end(parse_param *h);
-  pcb_bool exec_polyline_begin(parse_param *h);
-  pcb_bool exec_polyline_end(parse_param *h);
-  pcb_bool exec_line(parse_param *h);
-  pcb_bool exec_curve(parse_param *h);
-  
-  pcb_bool exec_net_class(parse_param *h);
-  pcb_bool exec_net_class_element(parse_param *h);
-  pcb_bool exec_net_class_attribute(parse_param *h);
-  
-  pcb_bool exec_end(parse_param *h);
-  pcb_bool exec_key(parse_param *h);
-
-  /* called by pcb-rnd to load hyperlynx file */
-  pcb_bool hyp_parse(pcb_data_t *dest, const char *fname, int debug);
-  void hyp_error(const char *msg);
-
-  /* create arc, hyperlynx-style */
-  pcb_arc_t *hyp_arc_new(pcb_layer_t *Layer, pcb_coord_t X1, pcb_coord_t Y1, pcb_coord_t X2, pcb_coord_t Y2, pcb_coord_t XC, pcb_coord_t YC, pcb_coord_t Width, pcb_coord_t Height, pcb_bool_t Clockwise, pcb_coord_t Thickness, pcb_coord_t Clearance, pcb_flag_t Flags);
-
-#endif 
-
-  /* not truncated */
-
+	/* 
+	 * Parameters passed on by the parser.
+	 * All variables added here are initialized in new_record().
+	 */
+
+typedef enum { PAD_TYPE_METAL, PAD_TYPE_ANTIPAD, PAD_TYPE_THERMAL_RELIEF } pad_type_enum;
+
+typedef enum { PIN_SIM_IN, PIN_SIM_OUT, PIN_SIM_BOTH } pin_function_enum;
+
+typedef enum { POLYGON_TYPE_POUR, POLYGON_TYPE_PLANE, POLYGON_TYPE_COPPER, POLYGON_TYPE_PAD,
+		POLYGON_TYPE_ANTIPAD } polygon_type_enum;
+
+typedef struct {
+	double vers;									/* version of the hyp file format */
+	pcb_bool detailed;						/* data detailed enough for power integrity */
+	pcb_bool unit_system_english;	/* english or metric units */
+	pcb_bool metal_thickness_weight;	/* copper by weight or by length */
+	double default_plane_separation;	/* trace to plane separation */
+
+	/* stackup record */
+	pcb_bool use_die_for_metal;		/* dielectric constant and loss tangent of dielectric for metal layers */
+	double bulk_resistivity;
+	pcb_bool conformal;
+	double epsilon_r;
+	char *layer_name;
+	double loss_tangent;
+	char *material_name;
+	double plane_separation;
+	double plating_thickness;
+	pcb_bool prepreg;
+	double temperature_coefficient;	/* temperature coefficient of resistivity */
+	double thickness;							/* layer thickness */
+
+	/* stackup record flags */
+	pcb_bool bulk_resistivity_set;
+	pcb_bool conformal_set;
+	pcb_bool epsilon_r_set;
+	pcb_bool layer_name_set;
+	pcb_bool loss_tangent_set;
+	pcb_bool material_name_set;
+	pcb_bool plane_separation_set;
+	pcb_bool plating_thickness_set;
+	pcb_bool prepreg_set;
+	pcb_bool temperature_coefficient_set;
+	pcb_bool thickness_set;
+
+	/* device record */
+	char *device_type;
+	char *ref;
+	double value_float;
+	char *value_string;
+	char *package;
+
+	/* device record flags */
+	pcb_bool name_set;
+	pcb_bool value_float_set;
+	pcb_bool value_string_set;
+	pcb_bool package_set;
+
+	/* supplies record */
+	pcb_bool voltage_specified;
+	pcb_bool conversion;
+
+	/* padstack record */
+	char *padstack_name;
+	double drill_size;
+	double pad_shape;
+	double pad_sx;
+	double pad_sy;
+	double pad_angle;
+	double thermal_clear_shape;
+	double thermal_clear_sx;
+	double thermal_clear_sy;
+	double thermal_clear_angle;
+	pad_type_enum pad_type;
+
+	/* padstack record flags */
+	pcb_bool padstack_name_set;
+	pcb_bool drill_size_set;
+	pcb_bool pad_type_set;
+
+	/* net record */
+	double width;
+	double left_plane_separation;
+	pcb_bool width_set;
+	pcb_bool left_plane_separation_set;
+
+	/* via subrecord of net */
+	char *layer1_name;
+	pcb_bool layer1_name_set;
+	char *layer2_name;
+	pcb_bool layer2_name_set;
+	char *pad1_shape;
+	double pad1_sx;
+	double pad1_sy;
+	double pad1_angle;
+	char *pad2_shape;
+	double pad2_sx;
+	double pad2_sy;
+	double pad2_angle;
+
+	/* pin subrecord of net */
+	char *pin_reference;
+	pcb_bool pin_reference_set;
+	pin_function_enum pin_function;
+	pcb_bool pin_function_set;
+
+	/* useg subrecord of net */
+	char *zlayer_name;
+	pcb_bool zlayer_name_set;
+	double length;
+	double impedance;
+	pcb_bool impedance_set;
+	double delay;
+	double resistance;
+	pcb_bool resistance_set;
+
+	/* polygon subrecord of net */
+	int id;
+	pcb_bool id_set;
+	polygon_type_enum polygon_type;
+	pcb_bool polygon_type_set;
+
+	/* net class record */
+	char *net_class_name;
+	char *net_name;
+
+	/* key record */
+	char *key;
+
+	/* Attributes */
+	char *name;										/* attribute name */
+	char *value;									/* attribute value */
+
+	/* point, line and arc coordinates */
+	double x;											/* coordinates point */
+	double y;											/* coordinates point */
+	double x1;										/* coordinates point 1 */
+	double y1;										/* coordinates point 1 */
+	double x2;										/* coordinates point 2 */
+	double y2;										/* coordinates point 2 */
+	double xc;										/* coordinates arc */
+	double yc;										/* coordinates arc */
+	double r;											/* coordinates arc */
+} parse_param;
+
+	/* exec_* routines are called by parser to interpret hyperlynx file */
+pcb_bool exec_board_file(parse_param * h);
+pcb_bool exec_version(parse_param * h);
+pcb_bool exec_data_mode(parse_param * h);
+pcb_bool exec_units(parse_param * h);
+pcb_bool exec_plane_sep(parse_param * h);
+pcb_bool exec_perimeter_segment(parse_param * h);
+pcb_bool exec_perimeter_arc(parse_param * h);
+pcb_bool exec_board_attribute(parse_param * h);
+
+pcb_bool exec_options(parse_param * h);
+pcb_bool exec_signal(parse_param * h);
+pcb_bool exec_dielectric(parse_param * h);
+pcb_bool exec_plane(parse_param * h);
+
+pcb_bool exec_devices(parse_param * h);
+
+pcb_bool exec_supplies(parse_param * h);
+
+pcb_bool exec_padstack_element(parse_param * h);
+pcb_bool exec_padstack_end(parse_param * h);
+
+pcb_bool exec_net(parse_param * h);
+pcb_bool exec_net_plane_separation(parse_param * h);
+pcb_bool exec_net_attribute(parse_param * h);
+pcb_bool exec_seg(parse_param * h);
+pcb_bool exec_arc(parse_param * h);
+pcb_bool exec_via(parse_param * h);
+pcb_bool exec_via_v1(parse_param * h);	/* Old style via format */
+pcb_bool exec_pin(parse_param * h);
+pcb_bool exec_pad(parse_param * h);
+pcb_bool exec_useg(parse_param * h);
+
+pcb_bool exec_polygon_begin(parse_param * h);
+pcb_bool exec_polygon_end(parse_param * h);
+pcb_bool exec_polyvoid_begin(parse_param * h);
+pcb_bool exec_polyvoid_end(parse_param * h);
+pcb_bool exec_polyline_begin(parse_param * h);
+pcb_bool exec_polyline_end(parse_param * h);
+pcb_bool exec_line(parse_param * h);
+pcb_bool exec_curve(parse_param * h);
+
+pcb_bool exec_net_class(parse_param * h);
+pcb_bool exec_net_class_element(parse_param * h);
+pcb_bool exec_net_class_attribute(parse_param * h);
+
+pcb_bool exec_end(parse_param * h);
+pcb_bool exec_key(parse_param * h);
+
+	/* called by pcb-rnd to load hyperlynx file */
+pcb_bool hyp_parse(pcb_data_t * dest, const char *fname, int debug);
+void hyp_error(const char *msg);
+
+	/* create arc, hyperlynx-style */
+pcb_arc_t *hyp_arc_new(pcb_layer_t * Layer, pcb_coord_t X1, pcb_coord_t Y1, pcb_coord_t X2, pcb_coord_t Y2, pcb_coord_t XC,
+											 pcb_coord_t YC, pcb_coord_t Width, pcb_coord_t Height, pcb_bool_t Clockwise, pcb_coord_t Thickness,
+											 pcb_coord_t Clearance, pcb_flag_t Flags);
+
+#endif
+
+	/* not truncated */
diff --git a/src_plugins/import_hyp/tests/gensamp b/src_plugins/import_hyp/tests/gensamp
new file mode 100755
index 0000000..164b814
--- /dev/null
+++ b/src_plugins/import_hyp/tests/gensamp
@@ -0,0 +1,143 @@
+#!/usr/bin/python
+"""
+  Generate sample hyperlynx file 
+  Copyright 2017 Koen De Vleeschauwer.
+ 
+  This file is part of pcb-rnd.
+ 
+  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 General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+from math import pi, sin, cos
+
+print "{VERSION=2.0}"
+print "{UNITS=METRIC LENGTH}"
+print "{BOARD"
+print "  (PERIMETER_SEGMENT X1=1.0 Y1=0.0 X2=19.0 Y2=0.0)"
+print "  (PERIMETER_SEGMENT X1=20.0 Y1=1.0 X2=20.0 Y2=9.0)"
+print "  (PERIMETER_SEGMENT X1=19.0 Y1=10.0 X2=1.0 Y2=10.0)"
+print "  (PERIMETER_SEGMENT X1=0.0 Y1=9.0 X2=0.0 Y2=1.0)"
+print "  (PERIMETER_ARC X1=0.0 Y1=1.0 X2=1.0 Y2=0.0 XC=1.0 YC=1.0 R=1.0)"
+print "  (PERIMETER_ARC X1=1.0 Y1=10.0 X2=0.0 Y2=9.0 XC=1.0 YC=9.0 R=1.0)"
+print "  (PERIMETER_ARC X1=20.0 Y1=9.0 X2=19.0 Y2=10.0 XC=19.0 YC=9.0 R=1.0)"
+print "  (PERIMETER_ARC X1=19.0 Y1=0.0 X2=20.0 Y2=1.0 XC=19.0 YC=1.0 R=1.0)"
+print ""
+print "  (PERIMETER_SEGMENT X1=2.0 Y1=1.0 X2=3.0 Y2=1.0)"
+print "  (PERIMETER_SEGMENT X1=3.0 Y1=9.0 X2=2.0 Y2=9.0)"
+print "  (PERIMETER_ARC X1=2.0 Y1=9.0 X2=1.0 Y2=8.0 XC=2.0 YC=8.0 R=1.0)"
+print "  (PERIMETER_SEGMENT X1=1.0 Y1=8.0 X2=1.0 Y2=2.0)"
+print "  (PERIMETER_ARC X1=1.0 Y1=2.0 X2=2.0 Y2=1.0 XC=2.0 YC=2.0 R=1.0)"
+print "  (PERIMETER_SEGMENT X1=4.0 Y1=2.0 X2=4.0 Y2=8.0)"
+print "  (PERIMETER_ARC X1=3.0 Y1=1.0 X2=4.0 Y2=2.0 XC=3.0 YC=2.0 R=1.0)"
+print "  (PERIMETER_ARC X1=4.0 Y1=8.0 X2=3.0 Y2=9.0 XC=3.0 YC=8.0 R=1.0)"
+
+print "  (PERIMETER_ARC X1=5.5 Y1=5.0 X2=5.5 Y2=5.0 XC=5.0 YC=5.0 R=0.5)"
+
+print "  (PERIMETER_ARC X1=5.5 Y1=6.0 X2=4.5 Y2=6.0 XC=5.0 YC=6.0 R=0.5)"
+print "  (PERIMETER_SEGMENT X1=4.5 Y1=6.0 X2=5.5 Y2=6.0)"
+
+print "  (PERIMETER_ARC X1=4.5 Y1=7.5 X2=5.5 Y2=7.5 XC=5.0 YC=7.5 R=0.5)"
+print "  (PERIMETER_SEGMENT X1=4.5 Y1=7.5 X2=5.5 Y2=7.5)"
+
+print "  (PERIMETER_ARC X1=5.5 Y1=8.5 X2=5.0 Y2=8.0 XC=5.0 YC=8.5 R=0.5)"
+print "  (PERIMETER_SEGMENT X1=5.0 Y1=8.0 X2=5.5 Y2=8.5)"
+
+print "}"
+print "{STACKUP"
+print "  (SIGNAL T=0.000700 L=component)"
+print "  (DIELECTRIC T=0.002000 C=4.000000)"
+print "  (PLANE  T=0.000700 L=solder PS=0.001000)"
+print "}"
+print "{DEVICES"
+print "}"
+
+#
+# PADSTACK. MDEF is shorthand for "all copper layers"
+#
+
+print "{PADSTACK=roundpad, 0.3"
+print "  (MDEF, 0, 0.5, 0.5, 0)"
+print "}"
+print "{PADSTACK=squarepad, 0.3"
+print "  (MDEF, 1, 0.5, 0.5, 0)"
+print "}"
+print "{PADSTACK=oblongpad, 0.3"
+print "  (MDEF, 2, 0.5, 0.5, 0)"
+print "}"
+print "{PADSTACK=nodrill,"
+print "  (MDEF, 0, 0.5, 0.5, 0)"
+print "}"
+
+#
+# SEG line segments
+#
+
+x0 = 6
+y0 = 3
+r1 = 0.5
+r2 = 2
+max = 12
+
+print "{NET=segtst"
+
+for x in range (0, max):
+  alpha = x * 2 * pi / max
+  x1 = x0 + r1 * cos (alpha)
+  y1 = y0 + r1 * sin (alpha)
+  r = r1 + (r2 - r1) * (x + 1) / max
+  x2 = x0 + r * cos (alpha)
+  y2 = y0 + r * sin (alpha)
+  w = (x + 1) * 0.1 / max
+  print "  (SEG X1=%f Y1=%f X2=%f Y2=%f W=%f L=component)" % ( x1, y1, x2, y2, w)
+  
+print "}"
+
+#
+# ARC arc segments
+#
+
+max = 8
+x0 = 9
+y0 = 1
+r = 0.1
+w = r / 4
+
+print "{NET=arctst"
+
+for a in range (0, max):
+  for b in range (0, max):
+    alpha = 2 * pi * a / max
+    beta = 2 * pi * b / max
+    xc = x0 + 4  * r * a 
+    yc = y0 + 4  * r * b
+    x1 = xc + r * cos (alpha)
+    y1 = yc + r * sin (alpha)
+    x2 = xc + r * cos (beta)
+    y2 = yc + r * sin (beta)
+    print "  (ARC X1=%f Y1=%f X2=%f Y2=%f XC=%f YC=%f R=%f W=%f L=component)" % ( x1, y1, x2, y2, xc, yc, r, w)
+  
+print "}"
+
+#
+# VIA
+#
+
+print "{NET=viatst"
+print "  (VIA X=13 Y=1 P=roundpad)"
+print "  (VIA X=13 Y=2 P=squarepad)"
+print "  (VIA X=13 Y=3 P=oblongpad)"
+print "  (VIA X=13 Y=4 P=nodrill)"
+print "}"
+
+print "{END}"
diff --git a/src_plugins/import_hyp/tests/samp.hyp b/src_plugins/import_hyp/tests/samp.hyp
new file mode 100644
index 0000000..72a7be6
--- /dev/null
+++ b/src_plugins/import_hyp/tests/samp.hyp
@@ -0,0 +1,134 @@
+{VERSION=2.0}
+{UNITS=METRIC LENGTH}
+{BOARD
+  (PERIMETER_SEGMENT X1=1.0 Y1=0.0 X2=19.0 Y2=0.0)
+  (PERIMETER_SEGMENT X1=20.0 Y1=1.0 X2=20.0 Y2=9.0)
+  (PERIMETER_SEGMENT X1=19.0 Y1=10.0 X2=1.0 Y2=10.0)
+  (PERIMETER_SEGMENT X1=0.0 Y1=9.0 X2=0.0 Y2=1.0)
+  (PERIMETER_ARC X1=0.0 Y1=1.0 X2=1.0 Y2=0.0 XC=1.0 YC=1.0 R=1.0)
+  (PERIMETER_ARC X1=1.0 Y1=10.0 X2=0.0 Y2=9.0 XC=1.0 YC=9.0 R=1.0)
+  (PERIMETER_ARC X1=20.0 Y1=9.0 X2=19.0 Y2=10.0 XC=19.0 YC=9.0 R=1.0)
+  (PERIMETER_ARC X1=19.0 Y1=0.0 X2=20.0 Y2=1.0 XC=19.0 YC=1.0 R=1.0)
+
+  (PERIMETER_SEGMENT X1=2.0 Y1=1.0 X2=3.0 Y2=1.0)
+  (PERIMETER_SEGMENT X1=3.0 Y1=9.0 X2=2.0 Y2=9.0)
+  (PERIMETER_ARC X1=2.0 Y1=9.0 X2=1.0 Y2=8.0 XC=2.0 YC=8.0 R=1.0)
+  (PERIMETER_SEGMENT X1=1.0 Y1=8.0 X2=1.0 Y2=2.0)
+  (PERIMETER_ARC X1=1.0 Y1=2.0 X2=2.0 Y2=1.0 XC=2.0 YC=2.0 R=1.0)
+  (PERIMETER_SEGMENT X1=4.0 Y1=2.0 X2=4.0 Y2=8.0)
+  (PERIMETER_ARC X1=3.0 Y1=1.0 X2=4.0 Y2=2.0 XC=3.0 YC=2.0 R=1.0)
+  (PERIMETER_ARC X1=4.0 Y1=8.0 X2=3.0 Y2=9.0 XC=3.0 YC=8.0 R=1.0)
+  (PERIMETER_ARC X1=5.5 Y1=5.0 X2=5.5 Y2=5.0 XC=5.0 YC=5.0 R=0.5)
+  (PERIMETER_ARC X1=5.5 Y1=6.0 X2=4.5 Y2=6.0 XC=5.0 YC=6.0 R=0.5)
+  (PERIMETER_SEGMENT X1=4.5 Y1=6.0 X2=5.5 Y2=6.0)
+  (PERIMETER_ARC X1=4.5 Y1=7.5 X2=5.5 Y2=7.5 XC=5.0 YC=7.5 R=0.5)
+  (PERIMETER_SEGMENT X1=4.5 Y1=7.5 X2=5.5 Y2=7.5)
+  (PERIMETER_ARC X1=5.5 Y1=8.5 X2=5.0 Y2=8.0 XC=5.0 YC=8.5 R=0.5)
+  (PERIMETER_SEGMENT X1=5.0 Y1=8.0 X2=5.5 Y2=8.5)
+}
+{STACKUP
+  (SIGNAL T=0.000700 L=component)
+  (DIELECTRIC T=0.002000 C=4.000000)
+  (PLANE  T=0.000700 L=solder PS=0.001000)
+}
+{DEVICES
+}
+{PADSTACK=roundpad, 0.3
+  (MDEF, 0, 0.5, 0.5, 0)
+}
+{PADSTACK=squarepad, 0.3
+  (MDEF, 1, 0.5, 0.5, 0)
+}
+{PADSTACK=oblongpad, 0.3
+  (MDEF, 2, 0.5, 0.5, 0)
+}
+{PADSTACK=nodrill,
+  (MDEF, 0, 0.5, 0.5, 0)
+}
+{NET=segtst
+  (SEG X1=6.500000 Y1=3.000000 X2=6.625000 Y2=3.000000 W=0.008333 L=component)
+  (SEG X1=6.433013 Y1=3.250000 X2=6.649519 Y2=3.375000 W=0.016667 L=component)
+  (SEG X1=6.250000 Y1=3.433013 X2=6.437500 Y2=3.757772 W=0.025000 L=component)
+  (SEG X1=6.000000 Y1=3.500000 X2=6.000000 Y2=4.000000 W=0.033333 L=component)
+  (SEG X1=5.750000 Y1=3.433013 X2=5.437500 Y2=3.974279 W=0.041667 L=component)
+  (SEG X1=5.566987 Y1=3.250000 X2=4.917468 Y2=3.625000 W=0.050000 L=component)
+  (SEG X1=5.500000 Y1=3.000000 X2=4.625000 Y2=3.000000 W=0.058333 L=component)
+  (SEG X1=5.566987 Y1=2.750000 X2=4.700962 Y2=2.250000 W=0.066667 L=component)
+  (SEG X1=5.750000 Y1=2.566987 X2=5.187500 Y2=1.592709 W=0.075000 L=component)
+  (SEG X1=6.000000 Y1=2.500000 X2=6.000000 Y2=1.250000 W=0.083333 L=component)
+  (SEG X1=6.250000 Y1=2.566987 X2=6.937500 Y2=1.376202 W=0.091667 L=component)
+  (SEG X1=6.433013 Y1=2.750000 X2=7.732051 Y2=2.000000 W=0.100000 L=component)
+}
+{NET=arctst
+  (ARC X1=9.100000 Y1=1.000000 X2=9.100000 Y2=1.000000 XC=9.000000 YC=1.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.100000 Y1=1.400000 X2=9.070711 Y2=1.470711 XC=9.000000 YC=1.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.100000 Y1=1.800000 X2=9.000000 Y2=1.900000 XC=9.000000 YC=1.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.100000 Y1=2.200000 X2=8.929289 Y2=2.270711 XC=9.000000 YC=2.200000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.100000 Y1=2.600000 X2=8.900000 Y2=2.600000 XC=9.000000 YC=2.600000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.100000 Y1=3.000000 X2=8.929289 Y2=2.929289 XC=9.000000 YC=3.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.100000 Y1=3.400000 X2=9.000000 Y2=3.300000 XC=9.000000 YC=3.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.100000 Y1=3.800000 X2=9.070711 Y2=3.729289 XC=9.000000 YC=3.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.470711 Y1=1.070711 X2=9.500000 Y2=1.000000 XC=9.400000 YC=1.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.470711 Y1=1.470711 X2=9.470711 Y2=1.470711 XC=9.400000 YC=1.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.470711 Y1=1.870711 X2=9.400000 Y2=1.900000 XC=9.400000 YC=1.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.470711 Y1=2.270711 X2=9.329289 Y2=2.270711 XC=9.400000 YC=2.200000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.470711 Y1=2.670711 X2=9.300000 Y2=2.600000 XC=9.400000 YC=2.600000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.470711 Y1=3.070711 X2=9.329289 Y2=2.929289 XC=9.400000 YC=3.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.470711 Y1=3.470711 X2=9.400000 Y2=3.300000 XC=9.400000 YC=3.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.470711 Y1=3.870711 X2=9.470711 Y2=3.729289 XC=9.400000 YC=3.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.800000 Y1=1.100000 X2=9.900000 Y2=1.000000 XC=9.800000 YC=1.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.800000 Y1=1.500000 X2=9.870711 Y2=1.470711 XC=9.800000 YC=1.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.800000 Y1=1.900000 X2=9.800000 Y2=1.900000 XC=9.800000 YC=1.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.800000 Y1=2.300000 X2=9.729289 Y2=2.270711 XC=9.800000 YC=2.200000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.800000 Y1=2.700000 X2=9.700000 Y2=2.600000 XC=9.800000 YC=2.600000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.800000 Y1=3.100000 X2=9.729289 Y2=2.929289 XC=9.800000 YC=3.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.800000 Y1=3.500000 X2=9.800000 Y2=3.300000 XC=9.800000 YC=3.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=9.800000 Y1=3.900000 X2=9.870711 Y2=3.729289 XC=9.800000 YC=3.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.129289 Y1=1.070711 X2=10.300000 Y2=1.000000 XC=10.200000 YC=1.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.129289 Y1=1.470711 X2=10.270711 Y2=1.470711 XC=10.200000 YC=1.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.129289 Y1=1.870711 X2=10.200000 Y2=1.900000 XC=10.200000 YC=1.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.129289 Y1=2.270711 X2=10.129289 Y2=2.270711 XC=10.200000 YC=2.200000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.129289 Y1=2.670711 X2=10.100000 Y2=2.600000 XC=10.200000 YC=2.600000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.129289 Y1=3.070711 X2=10.129289 Y2=2.929289 XC=10.200000 YC=3.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.129289 Y1=3.470711 X2=10.200000 Y2=3.300000 XC=10.200000 YC=3.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.129289 Y1=3.870711 X2=10.270711 Y2=3.729289 XC=10.200000 YC=3.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.500000 Y1=1.000000 X2=10.700000 Y2=1.000000 XC=10.600000 YC=1.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.500000 Y1=1.400000 X2=10.670711 Y2=1.470711 XC=10.600000 YC=1.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.500000 Y1=1.800000 X2=10.600000 Y2=1.900000 XC=10.600000 YC=1.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.500000 Y1=2.200000 X2=10.529289 Y2=2.270711 XC=10.600000 YC=2.200000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.500000 Y1=2.600000 X2=10.500000 Y2=2.600000 XC=10.600000 YC=2.600000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.500000 Y1=3.000000 X2=10.529289 Y2=2.929289 XC=10.600000 YC=3.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.500000 Y1=3.400000 X2=10.600000 Y2=3.300000 XC=10.600000 YC=3.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.500000 Y1=3.800000 X2=10.670711 Y2=3.729289 XC=10.600000 YC=3.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.929289 Y1=0.929289 X2=11.100000 Y2=1.000000 XC=11.000000 YC=1.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.929289 Y1=1.329289 X2=11.070711 Y2=1.470711 XC=11.000000 YC=1.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.929289 Y1=1.729289 X2=11.000000 Y2=1.900000 XC=11.000000 YC=1.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.929289 Y1=2.129289 X2=10.929289 Y2=2.270711 XC=11.000000 YC=2.200000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.929289 Y1=2.529289 X2=10.900000 Y2=2.600000 XC=11.000000 YC=2.600000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.929289 Y1=2.929289 X2=10.929289 Y2=2.929289 XC=11.000000 YC=3.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.929289 Y1=3.329289 X2=11.000000 Y2=3.300000 XC=11.000000 YC=3.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=10.929289 Y1=3.729289 X2=11.070711 Y2=3.729289 XC=11.000000 YC=3.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.400000 Y1=0.900000 X2=11.500000 Y2=1.000000 XC=11.400000 YC=1.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.400000 Y1=1.300000 X2=11.470711 Y2=1.470711 XC=11.400000 YC=1.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.400000 Y1=1.700000 X2=11.400000 Y2=1.900000 XC=11.400000 YC=1.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.400000 Y1=2.100000 X2=11.329289 Y2=2.270711 XC=11.400000 YC=2.200000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.400000 Y1=2.500000 X2=11.300000 Y2=2.600000 XC=11.400000 YC=2.600000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.400000 Y1=2.900000 X2=11.329289 Y2=2.929289 XC=11.400000 YC=3.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.400000 Y1=3.300000 X2=11.400000 Y2=3.300000 XC=11.400000 YC=3.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.400000 Y1=3.700000 X2=11.470711 Y2=3.729289 XC=11.400000 YC=3.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.870711 Y1=0.929289 X2=11.900000 Y2=1.000000 XC=11.800000 YC=1.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.870711 Y1=1.329289 X2=11.870711 Y2=1.470711 XC=11.800000 YC=1.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.870711 Y1=1.729289 X2=11.800000 Y2=1.900000 XC=11.800000 YC=1.800000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.870711 Y1=2.129289 X2=11.729289 Y2=2.270711 XC=11.800000 YC=2.200000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.870711 Y1=2.529289 X2=11.700000 Y2=2.600000 XC=11.800000 YC=2.600000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.870711 Y1=2.929289 X2=11.729289 Y2=2.929289 XC=11.800000 YC=3.000000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.870711 Y1=3.329289 X2=11.800000 Y2=3.300000 XC=11.800000 YC=3.400000 R=0.100000 W=0.025000 L=component)
+  (ARC X1=11.870711 Y1=3.729289 X2=11.870711 Y2=3.729289 XC=11.800000 YC=3.800000 R=0.100000 W=0.025000 L=component)
+}
+{NET=viatst
+  (VIA X=13 Y=1 P=roundpad)
+  (VIA X=13 Y=2 P=squarepad)
+  (VIA X=13 Y=3 P=oblongpad)
+  (VIA X=13 Y=4 P=nodrill)
+}
+{END}
diff --git a/src_plugins/import_ltspice/Makefile b/src_plugins/import_ltspice/Makefile
new file mode 100644
index 0000000..fabdd40
--- /dev/null
+++ b/src_plugins/import_ltspice/Makefile
@@ -0,0 +1,5 @@
+all:
+	cd ../../src && $(MAKE) mod_import_ltspice
+
+clean:
+	rm *.o *.so 2>/dev/null ; true
diff --git a/src_plugins/import_ltspice/Plug.tmpasm b/src_plugins/import_ltspice/Plug.tmpasm
new file mode 100644
index 0000000..f52c721
--- /dev/null
+++ b/src_plugins/import_ltspice/Plug.tmpasm
@@ -0,0 +1,8 @@
+put /local/pcb/mod {import_ltspice}
+put /local/pcb/mod/OBJS [@ $(PLUGDIR)/import_ltspice/ltspice.o @]
+
+switch /local/pcb/import_ltspice/controls
+	case {buildin}   include /local/pcb/tmpasm/buildin; end;
+	case {plugin}    include /local/pcb/tmpasm/plugin; end;
+	case {disable}   include /local/pcb/tmpasm/disable; end;
+end
diff --git a/src_plugins/import_ltspice/README b/src_plugins/import_ltspice/README
new file mode 100644
index 0000000..a96a1d1
--- /dev/null
+++ b/src_plugins/import_ltspice/README
@@ -0,0 +1,5 @@
+Import the netlist and footprints from an ltspice .asc and .net pair of files
+
+#state: works
+#default: buildin
+#implements: import
diff --git a/src_plugins/import_ltspice/ltspice.c b/src_plugins/import_ltspice/ltspice.c
new file mode 100644
index 0000000..9dabcff
--- /dev/null
+++ b/src_plugins/import_ltspice/ltspice.c
@@ -0,0 +1,323 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *
+ *  LTSpice import HID
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *  Copyright (C) 2017 Erich Heinzle (non passive footprint parsing)
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <qparse/qparse.h>
+
+#include "board.h"
+#include "data.h"
+#include "error.h"
+#include "pcb-printf.h"
+#include "compat_misc.h"
+
+#include "action_helper.h"
+#include "hid_actions.h"
+#include "plugins.h"
+#include "hid.h"
+
+static const char *ltspice_cookie = "ltspice importer";
+
+static int ltspice_hdr_asc(FILE *f)
+{
+	char s[1024];
+	while(fgets(s, sizeof(s), f) != NULL)
+		if (strncmp(s, "Version 4", 9) == 0)
+			return 0;
+	return -1;
+}
+
+/* remove leading whitespace */
+#define ltrim(s) while(isspace(*s)) s++
+
+/* remove trailing newline */
+#define rtrim(s) \
+	do { \
+		char *end; \
+		for(end = s + strlen(s) - 1; (end >= s) && ((*end == '\r') || (*end == '\n')); end--) \
+			*end = '\0'; \
+	} while(0)
+
+typedef struct {
+	char *refdes;
+	char *value;
+	char *footprint;
+} symattr_t;
+
+
+#define null_empty(s) ((s) == NULL ? "" : (s))
+
+static void sym_flush(symattr_t *sattr)
+{
+/*	pcb_trace("ltspice sym: refdes=%s val=%s fp=%s\n", sattr->refdes, sattr->value, sattr->footprint);*/
+
+	if (sattr->refdes != NULL) {
+		if (sattr->footprint == NULL)
+			pcb_message(PCB_MSG_ERROR, "ltspice: not importing refdes=%s: no footprint specified\n", sattr->refdes);
+		else
+			pcb_hid_actionl("ElementList", "Need", null_empty(sattr->refdes), null_empty(sattr->footprint), null_empty(sattr->value), NULL);
+	}
+	free(sattr->refdes); sattr->refdes = NULL;
+	free(sattr->value); sattr->value = NULL;
+	free(sattr->footprint); sattr->footprint = NULL;
+}
+
+static int ltspice_parse_asc(FILE *fa)
+{
+	symattr_t sattr;
+	char line[1024];
+
+	memset(&sattr, 0, sizeof(sattr));
+
+	pcb_hid_actionl("ElementList", "start", NULL);
+
+	while(fgets(line, sizeof(line), fa) != NULL) {
+		char *s;
+		int isPassive = 0;
+		s = line;
+		rtrim(s);
+
+		if (strncmp(s, "SYMBOL", 6) == 0)
+			sym_flush(&sattr);
+		else if (strncmp(s, "SYMATTR", 7) == 0) {
+			s+=8;
+			ltrim(s);
+			if (strncmp(s, "InstName", 8) == 0) {
+				s+=9;
+				ltrim(s);
+				free(sattr.refdes);
+				sattr.refdes = pcb_strdup(s);
+				/* figure out if device is passive or not, as this affects
+				   subsequent parsing of the "SYMATTR VALUE .... " line */
+				if (strncmp(s, "R", 1) != 0 && strncmp(s, "L", 1) != 0 &&
+					strncmp(s, "C", 1) != 0) {
+					isPassive = 0;
+				}
+				else {
+					isPassive = 1;
+				}
+			}
+			else {
+				if (strncmp(s, "Value", 5) == 0) {
+					/* we get around non passives having a device quoted with no 
+					mfg= field in the .net file by parsing the device name for
+					an appended .pcb-rnd-TO92 etc...
+					i.e. parse the following: SYMATTR Value 2N2222.pcb-rnd-TO92 */
+					s+=6;
+					ltrim(s);
+					free(sattr.value);
+					if (isPassive) {
+						sattr.value = pcb_strdup(s);
+					}
+					else {
+						char *fp;
+						/*s+=6;*/
+						fp = strstr(s, ".pcb-rnd-");
+						if (fp != NULL) {
+							sattr.value = pcb_strdup(fp);
+							s = fp;							
+							fp += 9;
+							if (*fp == '"') {
+								char *end;
+								fp++;
+								end = strchr(fp, '"');
+								if (end != NULL)
+									*end = '\0';
+							}
+							free(sattr.footprint);
+							sattr.footprint = pcb_strdup(fp);
+                	                	}
+					}
+				}
+				if (strncmp(s, "SpiceLine", 9) == 0) {
+					/* for passives, the SpiceLine include the "mfg=" field */
+					char *fp;
+					s+=6;
+					fp = strstr(s, "mfg=");
+					if (fp != NULL) {
+						fp += 4;
+						if (*fp == '"') {
+							char *end;
+							fp++;
+							end = strchr(fp, '"');
+							if (end != NULL)
+								*end = '\0';
+						}
+						if (strncmp(fp, ".pcb-rnd-", 9) == 0)
+							fp += 9;
+						if (strncmp(fp, "pcb-rnd-", 8) == 0)
+							fp += 8;
+						free(sattr.footprint);
+						sattr.footprint = pcb_strdup(fp);
+					}
+				}
+				/* nothing stops a user inserting 
+				   "SYMATTR Footprint TO92" if keen in the .asc file */
+				if (strncmp(s, "Footprint", 9) == 0) {
+					s+=10;
+					ltrim(s);
+					free(sattr.footprint);
+					sattr.footprint = pcb_strdup(s);
+				}
+			}
+		}
+	}
+	sym_flush(&sattr);
+	pcb_hid_actionl("ElementList", "Done", NULL);
+	return 0;
+}
+
+static int ltspice_parse_net(FILE *fn)
+{
+	char line[1024];
+
+	pcb_hid_actionl("Netlist", "Freeze", NULL);
+	pcb_hid_actionl("Netlist", "Clear", NULL);
+
+	while(fgets(line, sizeof(line), fn) != NULL) {
+		int argc;
+		char **argv, *s;
+
+		s = line;
+		ltrim(s);
+		rtrim(s);
+		argc = qparse2(s, &argv, QPARSE_DOUBLE_QUOTE | QPARSE_SINGLE_QUOTE);
+		if ((argc > 1) && (strcmp(argv[0], "NET") == 0)) {
+			int n;
+			for(n = 2; n < argc; n++) {
+/*				pcb_trace("net-add '%s' '%s'\n", argv[1], argv[n]);*/
+				pcb_hid_actionl("Netlist", "Add",  argv[1], argv[n], NULL);
+			}
+		}
+	}
+
+	pcb_hid_actionl("Netlist", "Sort", NULL);
+	pcb_hid_actionl("Netlist", "Thaw", NULL);
+
+	return 0;
+}
+
+
+static int ltspice_load(const char *fname_net, const char *fname_asc)
+{
+	FILE *fn, *fa;
+	int ret = 0;
+
+	fn = fopen(fname_net, "r");
+	if (fn == NULL) {
+		pcb_message(PCB_MSG_ERROR, "can't open file '%s' for read\n", fname_net);
+		return -1;
+	}
+	fa = fopen(fname_asc, "r");
+	if (fa == NULL) {
+		pcb_message(PCB_MSG_ERROR, "can't open file '%s' for read\n", fname_asc);
+		fclose(fn);
+		return -1;
+	}
+
+	if (ltspice_hdr_asc(fa)) {
+		pcb_message(PCB_MSG_ERROR, "file '%s' doesn't look like a verison 4 asc file\n", fname_asc);
+		goto error;
+	}
+
+
+	if (ltspice_parse_asc(fa) != 0) goto error;
+	if (ltspice_parse_net(fn) != 0) goto error;
+
+	quit:;
+	fclose(fa);
+	fclose(fn);
+	return ret;
+
+	error:
+	ret = -1;
+	goto quit;
+}
+
+static const char pcb_acts_LoadLtspiceFrom[] = "LoadLtspiceFrom(filename)";
+static const char pcb_acth_LoadLtspiceFrom[] = "Loads the specified ltspice .net and .asc file - the netlist must be mentor netlist.";
+int pcb_act_LoadLtspiceFrom(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	const char *fname = NULL, *end;
+	char *fname_asc, *fname_net, *fname_base;
+	static char *default_file = NULL;
+	int res;
+
+	fname = argc ? argv[0] : 0;
+
+	if (!fname || !*fname) {
+		fname = pcb_gui->fileselect("Load ltspice net+asc file pair...",
+																"Picks a ltspice mentor net or asc file to load.\n",
+																default_file, ".asc", "ltspice", HID_FILESELECT_READ);
+		if (fname == NULL)
+			PCB_ACT_FAIL(LoadLtspiceFrom);
+		if (default_file != NULL) {
+			free(default_file);
+			default_file = NULL;
+		}
+	}
+
+	end = strrchr(fname, '.');
+	if (end != NULL) {
+		if (strcmp(end, ".net") == 0)
+			fname_base = pcb_strndup(fname, end - fname);
+		else if (strcmp(end, ".asc") == 0)
+			fname_base = pcb_strndup(fname, end - fname);
+	}
+	else
+		fname_base = pcb_strdup(fname);
+
+	fname_net = pcb_strdup_printf("%s.net", fname_base);
+	fname_asc = pcb_strdup_printf("%s.asc", fname_base);
+	free(fname_base);
+
+	res = ltspice_load(fname_net, fname_asc);
+
+	free(fname_asc);
+	free(fname_net);
+
+	return res;
+}
+
+pcb_hid_action_t ltspice_action_list[] = {
+	{"LoadLtspiceFrom", 0, pcb_act_LoadLtspiceFrom, pcb_acth_LoadLtspiceFrom, pcb_acts_LoadLtspiceFrom}
+};
+
+PCB_REGISTER_ACTIONS(ltspice_action_list, ltspice_cookie)
+
+static void hid_ltspice_uninit()
+{
+	pcb_hid_remove_actions_by_cookie(ltspice_cookie);
+}
+
+#include "dolists.h"
+pcb_uninit_t hid_import_ltspice_init()
+{
+	PCB_REGISTER_ACTIONS(ltspice_action_list, ltspice_cookie)
+		return hid_ltspice_uninit;
+}
diff --git a/src_plugins/import_mucs/Makefile b/src_plugins/import_mucs/Makefile
new file mode 100644
index 0000000..42ce07c
--- /dev/null
+++ b/src_plugins/import_mucs/Makefile
@@ -0,0 +1,5 @@
+all:
+	cd ../../src && $(MAKE) mod_import_mucs
+
+clean:
+	rm *.o *.so 2>/dev/null ; true
diff --git a/src_plugins/import_mucs/Plug.tmpasm b/src_plugins/import_mucs/Plug.tmpasm
new file mode 100644
index 0000000..e865c48
--- /dev/null
+++ b/src_plugins/import_mucs/Plug.tmpasm
@@ -0,0 +1,8 @@
+put /local/pcb/mod {import_mucs}
+put /local/pcb/mod/OBJS [@ $(PLUGDIR)/import_mucs/mucs.o @]
+
+switch /local/pcb/import_mucs/controls
+	case {buildin}   include /local/pcb/tmpasm/buildin; end;
+	case {plugin}    include /local/pcb/tmpasm/plugin; end;
+	case {disable}   include /local/pcb/tmpasm/disable; end;
+end
diff --git a/src_plugins/import_mucs/README b/src_plugins/import_mucs/README
new file mode 100644
index 0000000..20887f6
--- /dev/null
+++ b/src_plugins/import_mucs/README
@@ -0,0 +1,5 @@
+Import lines and vias from MUCS unixplot .pl files
+
+#state: works
+#default: builtin
+#implements: import
diff --git a/src_plugins/import_mucs/mucs.c b/src_plugins/import_mucs/mucs.c
new file mode 100644
index 0000000..1ed92c8
--- /dev/null
+++ b/src_plugins/import_mucs/mucs.c
@@ -0,0 +1,160 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *
+ *  MUCS unixplot import HID
+ *  pcb-rnd Copyright (C) 2017 Erich Heinzle
+ *  Based on up2pcb.cc, a simple unixplot file to pcb syntax converter
+ *  Copyright (C) 2001 Luis Claudio Gamboa Lopes
+ *  And loosely based on dsn.c
+ *  Copyright (C) 2008, 2011 Josh Jordan, Dan McMahill, and Jared Casper
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This plugin imports unixplot format line and via data into pcb-rnd */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "board.h"
+#include "data.h"
+#include "error.h"
+#include "pcb-printf.h"
+#include "compat_misc.h"
+
+#include "action_helper.h"
+#include "hid_actions.h"
+#include "plugins.h"
+#include "layer.h"
+#include "conf_core.h"
+
+static const char *mucs_cookie = "mucs importer";
+
+static const char pcb_acts_LoadMucsFrom[] = "LoadMucsFrom(filename)";
+static const char pcb_acth_LoadMucsFrom[] = "Loads the specified mucs routing file.";
+int pcb_act_LoadMucsFrom(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	const char *fname = NULL;
+	static char *default_file = NULL;
+	FILE *fi;
+	int c, c2;
+	pcb_coord_t x1, y1, x2, y2, r;
+	fname = argc ? argv[0] : 0;
+
+	if (!(pcb_layer_flags(INDEXOFCURRENT) & PCB_LYT_COPPER)) {
+		pcb_message(PCB_MSG_ERROR, "The currently active layer is not a copper layer.\n");
+	}
+
+
+	if (!fname || !*fname) {
+		fname = pcb_gui->fileselect("Load mucs routing session Resource File...",
+																"Picks a mucs session resource file to load.\n"
+																	"This file could be generated by mucs-pcb\n",
+																default_file, ".l1", "unixplot", HID_FILESELECT_READ);
+		if (fname == NULL)
+			PCB_ACT_FAIL(LoadMucsFrom);
+		if (default_file != NULL) {
+			free(default_file);
+			default_file = NULL;
+		}
+
+		if (fname && *fname)
+			default_file = pcb_strdup(fname);
+	}
+
+	fi = fopen(fname, "r");
+	if (!fi) {
+		pcb_message(PCB_MSG_ERROR, "Can't load mucs unixplot file %s for read\n", fname);
+		return 1;
+	}
+
+	while ((c = getc(fi)) != EOF) {
+/*		pcb_trace("Char: %d \n", c); */
+		switch (c) {
+			case 's':
+				x1 = 100 * (getc(fi) + (getc(fi) * 256));
+				y1 = 100 * (getc(fi) + (getc(fi) * 256));
+				x2 = 100 * (getc(fi) + (getc(fi) * 256));
+				y2 = 100 * (getc(fi) + (getc(fi) * 256));
+				pcb_trace("s--%i %i %i %i ???\n", x1, y1, x2, y2);
+				break;
+			case 'l':
+				x1 = (getc(fi) + (getc(fi) * 256));
+				y1 = (getc(fi) + (getc(fi) * 256));
+				x2 = (getc(fi) + (getc(fi) * 256));
+				y2 = (getc(fi) + (getc(fi) * 256));
+				pcb_trace("Line(%d %d %d %d 20 \" \")\n", x1, y1, x2, y2);
+				/* consider a bounds checking function to censor absurd coord sizes */
+				pcb_line_new(CURRENT, PCB_MIL_TO_COORD(x1), PCB_MIL_TO_COORD(y1), PCB_MIL_TO_COORD(x2), PCB_MIL_TO_COORD(y2), PCB_MIL_TO_COORD(10), PCB_MIL_TO_COORD(10), pcb_flag_make(PCB_FLAG_AUTO));
+				break;
+			case 'c':
+				x1 = (getc(fi) + (getc(fi) * 256));
+				y1 = (getc(fi) + (getc(fi) * 256));
+				r = (getc(fi) + (getc(fi) * 256));
+				pcb_trace("Via(%d %d 60 25 \"\" \" \")\n", x1, y1);
+				pcb_via_new(PCB->Data, PCB_MIL_TO_COORD(x1), PCB_MIL_TO_COORD(y1), PCB_MIL_TO_COORD(60), PCB_MIL_TO_COORD(10), 0, PCB_MIL_TO_COORD(30), 0, pcb_flag_make(PCB_FLAG_AUTO));
+				break;
+			case 'n':
+				x1 = (getc(fi) + (getc(fi) * 256));
+				y1 = (getc(fi) + (getc(fi) * 256));
+				pcb_trace("Line(%d %d %d %d 20 \" \")\n", x1, y1, x2, y2);
+				pcb_line_new(CURRENT, PCB_MIL_TO_COORD(x1), PCB_MIL_TO_COORD(y1), PCB_MIL_TO_COORD(x2), PCB_MIL_TO_COORD(y2), PCB_MIL_TO_COORD(10), PCB_MIL_TO_COORD(10), pcb_flag_make(PCB_FLAG_AUTO));
+				x2 = x1;
+				y2 = y1;
+				break;
+			case 'a':
+				x1 = 100 * ((getc(fi) * 256) + getc(fi));
+				y1 = 100 * ((getc(fi) * 256) + getc(fi));
+				x2 = 100 * ((getc(fi) * 256) + getc(fi));
+				y2 = 100 * ((getc(fi) * 256) + getc(fi));
+				r = 100 * ((getc(fi) * 256) + getc(fi));
+				pcb_trace("a--stroke newpath\n%d %d %d %d %d arc\n", x1, y1, x2, y2, r);
+				break;
+			case 'e':
+				break;
+			case 't':
+				do {
+					c2 = getc(fi);
+				} while (c2 != '\0' && c2 != EOF);
+				break;
+		}
+	}
+	fclose(fi);
+	return 0;
+}
+
+pcb_hid_action_t mucs_action_list[] = {
+	{"LoadMucsFrom", 0, pcb_act_LoadMucsFrom, pcb_acth_LoadMucsFrom, pcb_acts_LoadMucsFrom}
+};
+
+PCB_REGISTER_ACTIONS(mucs_action_list, mucs_cookie)
+
+static void hid_mucs_uninit()
+{
+	pcb_hid_remove_actions_by_cookie(mucs_cookie);
+}
+
+#include "dolists.h"
+pcb_uninit_t hid_import_mucs_init()
+{
+	PCB_REGISTER_ACTIONS(mucs_action_list, mucs_cookie)
+		return hid_mucs_uninit;
+}
diff --git a/src_plugins/import_tinycad/Makefile b/src_plugins/import_tinycad/Makefile
new file mode 100644
index 0000000..0e9effa
--- /dev/null
+++ b/src_plugins/import_tinycad/Makefile
@@ -0,0 +1,5 @@
+all:
+	cd ../../src && $(MAKE) mod_import_tinycad
+
+clean:
+	rm *.o *.so 2>/dev/null ; true
diff --git a/src_plugins/import_tinycad/Plug.tmpasm b/src_plugins/import_tinycad/Plug.tmpasm
new file mode 100644
index 0000000..d6510e6
--- /dev/null
+++ b/src_plugins/import_tinycad/Plug.tmpasm
@@ -0,0 +1,8 @@
+put /local/pcb/mod {import_tinycad}
+put /local/pcb/mod/OBJS [@ $(PLUGDIR)/import_tinycad/tinycad.o @]
+
+switch /local/pcb/import_tinycad/controls
+	case {buildin}   include /local/pcb/tmpasm/buildin; end;
+	case {plugin}    include /local/pcb/tmpasm/plugin; end;
+	case {disable}   include /local/pcb/tmpasm/disable; end;
+end
diff --git a/src_plugins/import_tinycad/README b/src_plugins/import_tinycad/README
new file mode 100644
index 0000000..f268d3a
--- /dev/null
+++ b/src_plugins/import_tinycad/README
@@ -0,0 +1,5 @@
+Import the netlist and footprints from a tinycad netlist.
+
+#state: works
+#default: buildin
+#implements: import
diff --git a/src_plugins/import_tinycad/tinycad.c b/src_plugins/import_tinycad/tinycad.c
new file mode 100644
index 0000000..b536ba8
--- /dev/null
+++ b/src_plugins/import_tinycad/tinycad.c
@@ -0,0 +1,207 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *
+ *  tinycad import HID
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <qparse/qparse.h>
+
+#include "board.h"
+#include "data.h"
+#include "error.h"
+#include "pcb-printf.h"
+#include "compat_misc.h"
+
+#include "action_helper.h"
+#include "hid_actions.h"
+#include "plugins.h"
+#include "hid.h"
+
+static const char *tinycad_cookie = "tinycad importer";
+
+/* remove leading whitespace */
+#define ltrim(s) while(isspace(*s)) s++
+
+/* remove trailing newline */
+#define rtrim(s) \
+	do { \
+		char *end; \
+		for(end = s + strlen(s) - 1; (end >= s) && ((*end == '\r') || (*end == '\n')); end--) \
+			*end = '\0'; \
+	} while(0)
+
+typedef struct {
+	char *refdes;
+	char *value;
+	char *footprint;
+} symattr_t;
+
+#define null_empty(s) ((s) == NULL ? "" : (s))
+
+static void sym_flush(symattr_t *sattr)
+{
+	if (sattr->refdes != NULL) {
+/*		pcb_trace("tinycad sym: refdes=%s val=%s fp=%s\n", sattr->refdes, sattr->value, sattr->footprint);*/
+		if (sattr->footprint == NULL)
+			pcb_message(PCB_MSG_ERROR, "tinycad: not importing refdes=%s: no footprint specified\n", sattr->refdes);
+		else
+			pcb_hid_actionl("ElementList", "Need", null_empty(sattr->refdes), null_empty(sattr->footprint), null_empty(sattr->value), NULL);
+	}
+	free(sattr->refdes); sattr->refdes = NULL;
+	free(sattr->value); sattr->value = NULL;
+	free(sattr->footprint); sattr->footprint = NULL;
+}
+
+
+static int tinycad_parse_net(FILE *fn)
+{
+	char line[1024];
+	symattr_t sattr;
+
+	memset(&sattr, 0, sizeof(sattr));
+
+	pcb_hid_actionl("ElementList", "start", NULL);
+	pcb_hid_actionl("Netlist", "Freeze", NULL);
+	pcb_hid_actionl("Netlist", "Clear", NULL);
+
+	while(fgets(line, sizeof(line), fn) != NULL) {
+		int argc;
+		char **argv, *s;
+
+		s = line;
+		ltrim(s);
+		if (*s == ';') /* comment */
+			continue;
+		rtrim(s);
+		argc = qparse2(s, &argv, QPARSE_DOUBLE_QUOTE | QPARSE_SINGLE_QUOTE);
+		if ((argc > 1) && (strcmp(argv[0], "NET") == 0)) {
+			char *curr, *next, *sep;
+
+			for(curr = argv[5]; (curr != NULL) && (*curr != '\0'); curr = next) {
+				next = strchr(curr, ')');
+				if (next != NULL) {
+					*next = '\0';
+					next++;
+					if (*next == ',')
+						next++;
+				}
+				if (*curr == '(')
+					curr++;
+				sep = strchr(curr, ',');
+				if (sep != NULL) {
+					*sep = '-';
+/*					pcb_trace("net-add '%s' '%s'\n", argv[2], curr);*/
+					pcb_hid_actionl("Netlist", "Add",  argv[2], curr, NULL);
+				}
+			}
+		}
+		else if ((argc > 1) && (strcmp(argv[0], "COMPONENT") == 0)) {
+			sym_flush(&sattr);
+			free(sattr.refdes);
+			sattr.refdes = pcb_strdup(argv[1]);
+		}
+		else if ((argc > 3) && (strcmp(argv[0], "OPTION") == 0)) {
+			if (strcmp(argv[3], "..") != 0) {
+				if (strcmp(argv[1], "Package") == 0) {
+					free(sattr.footprint);
+					sattr.footprint = pcb_strdup(argv[3]);
+				}
+				else if (strcmp(argv[1], "Value") == 0) {
+					free(sattr.value);
+					sattr.value = pcb_strdup(argv[3]);
+				}
+			}
+		}
+	}
+
+	sym_flush(&sattr);
+
+	pcb_hid_actionl("Netlist", "Sort", NULL);
+	pcb_hid_actionl("Netlist", "Thaw", NULL);
+	pcb_hid_actionl("ElementList", "Done", NULL);
+
+	return 0;
+}
+
+
+static int tinycad_load(const char *fname_net)
+{
+	FILE *fn;
+	int ret = 0;
+
+	fn = fopen(fname_net, "r");
+	if (fn == NULL) {
+		pcb_message(PCB_MSG_ERROR, "can't open file '%s' for read\n", fname_net);
+		return -1;
+	}
+
+	ret = tinycad_parse_net(fn);
+
+	fclose(fn);
+	return ret;
+}
+
+static const char pcb_acts_LoadtinycadFrom[] = "LoadTinycadFrom(filename)";
+static const char pcb_acth_LoadtinycadFrom[] = "Loads the specified tinycad .net file - the netlist must be tinycad netlist output.";
+int pcb_act_LoadtinycadFrom(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	const char *fname = NULL;
+	static char *default_file = NULL;
+
+	fname = argc ? argv[0] : 0;
+
+	if (!fname || !*fname) {
+		fname = pcb_gui->fileselect("Load tinycad netlist file...",
+																"Picks a tinycad netlist file to load.\n",
+																default_file, ".net", "tinycad", HID_FILESELECT_READ);
+		if (fname == NULL)
+			PCB_ACT_FAIL(LoadtinycadFrom);
+		if (default_file != NULL) {
+			free(default_file);
+			default_file = NULL;
+		}
+	}
+
+	return tinycad_load(fname);
+}
+
+pcb_hid_action_t tinycad_action_list[] = {
+	{"LoadTinycadFrom", 0, pcb_act_LoadtinycadFrom, pcb_acth_LoadtinycadFrom, pcb_acts_LoadtinycadFrom}
+};
+
+PCB_REGISTER_ACTIONS(tinycad_action_list, tinycad_cookie)
+
+static void hid_tinycad_uninit()
+{
+	pcb_hid_remove_actions_by_cookie(tinycad_cookie);
+}
+
+#include "dolists.h"
+pcb_uninit_t hid_import_tinycad_init()
+{
+	PCB_REGISTER_ACTIONS(tinycad_action_list, tinycad_cookie)
+	return hid_tinycad_uninit;
+}
diff --git a/src_plugins/io_kicad/read.c b/src_plugins/io_kicad/read.c
index 7c60830..c92293a 100644
--- a/src_plugins/io_kicad/read.c
+++ b/src_plugins/io_kicad/read.c
@@ -103,7 +103,7 @@ static int kicad_parse_version(read_state_t *st, gsxl_node_t *subtree)
 	if (subtree->str != NULL) {
 		int ver = atoi(subtree->str);
 		printf("kicad version: '%s' == %d\n", subtree->str, ver);
-		if (ver == 3) /* accept version 3 */
+		if (ver == 3 || ver == 4) /* accept version 3 */
 			return 0;
 	}
 	return -1;
@@ -234,7 +234,7 @@ static int kicad_parse_gr_text(read_state_t *st, gsxl_node_t *subtree)
 				if (n->children != NULL && n->children->str != NULL) {
 					pcb_printf("\ttext layer: '%s'\n", (n->children->str));
 					PCBLayer = kicad_get_layeridx(st, n->children->str);
-					if (PCBLayer == -1) {
+					if (PCBLayer < 0) {
 						return -1;
 					} else if (pcb_layer_flags(PCBLayer) & PCB_LYT_BOTTOM) {
 							Flags = pcb_flag_make(PCB_FLAG_ONSOLDER);
@@ -275,12 +275,14 @@ static int kicad_parse_gr_text(read_state_t *st, gsxl_node_t *subtree)
 							}
 						}
 					} else if (m->str != NULL && strcmp("justify", m->str) == 0) {
-						SEEN_NO_DUP(tally, 4);
+						/* SEEN_NO_DUP(tally, 4); */
 						if (m->children != NULL && m->children->str != NULL) {
 							pcb_printf("\ttext justification: '%s'\n", (m->children->str));
 							if (strcmp("mirror", m->children->str) == 0) {
 								mirrored = 1;
+								SEEN_NO_DUP(tally, 4);
 							}
+							/* ignore right or left justification for now */
 						} else {
 							return -1;
 						}
@@ -411,8 +413,10 @@ static int kicad_parse_gr_line(read_state_t *st, gsxl_node_t *subtree)
 					if (n->children != NULL && n->children->str != NULL) {
 						pcb_printf("\tgr_line layer: '%s'\n", (n->children->str));
 						PCBLayer = kicad_get_layeridx(st, n->children->str);
-						if (PCBLayer == -1) {
-							return -1;
+						if (PCBLayer < 0) {
+							pcb_printf("\tNon silk gr_line ignored\n");
+							return 0;
+							/* return -1; */
 						}
 					} else {
 						return -1;
@@ -469,8 +473,9 @@ static int kicad_parse_gr_arc(read_state_t *st, gsxl_node_t *subtree)
 
 	char *end;
 	double val;
-	pcb_coord_t centreX, centreY, endX, endY, width, height, Thickness, Clearance;
+	pcb_coord_t centreX, centreY, endX, endY, width, height, Thickness, Clearance, deltaX, deltaY;
 	pcb_angle_t startAngle = 0.0;
+	pcb_angle_t endAngle= 0.0;
 	pcb_angle_t delta = 360.0; /* these defaults allow a gr_circle to be parsed, which does not specify (angle XXX) */
 	pcb_flag_t Flags = pcb_flag_make(0); /* start with something bland here */
 	int PCBLayer = 0; /* sane default value */
@@ -557,7 +562,7 @@ static int kicad_parse_gr_arc(read_state_t *st, gsxl_node_t *subtree)
 					if (n->children != NULL && n->children->str != NULL) {
 						pcb_printf("\tgr_arc layer: '%s'\n", (n->children->str));
 						PCBLayer = kicad_get_layeridx(st, n->children->str);
-						if (PCBLayer == -1) {
+						if (PCBLayer < 0) {
 							return -1;
 						}
 					} else {
@@ -606,13 +611,30 @@ static int kicad_parse_gr_arc(read_state_t *st, gsxl_node_t *subtree)
         required = BV(0) | BV(1) | BV(2) | BV(3); /* | BV(4); not needed for circles */
         if ((tally & required) == required) { /* need start, end, layer, thickness at a minimum */
 		width = height = pcb_distance(centreX, centreY, endX, endY); /* calculate radius of arc */
+		deltaX = endX - centreX;
+		deltaY = endY - centreY;
 		if (width < 1) { /* degenerate case */
 			startAngle = 0;
 		} else {
-			startAngle = 180*atan2(endY - centreY, endX - centreX)/M_PI;
+			endAngle = 180+180*atan2(-deltaY, deltaX)/M_PI;
+			pcb_printf("\tcalculated end angle: '%f'\n", endAngle);
 			/* avoid using atan2 with zero parameters */
+		
+			if (endAngle < 0.0) {
+				endAngle += 360.0; /*make it 0...360 */
+				pcb_printf("\tadjusted end angle: '%f'\n", endAngle);
+			}
+			startAngle = (endAngle - delta); /* geda is 180 degrees out of phase with kicad, and opposite direction rotation */
+			pcb_printf("\tcalculated start angle: '%f'\n", startAngle);
+			if (startAngle > 360.0) {
+				startAngle -= 360.0;
+			}
+			if (startAngle < 0.0) {
+				startAngle += 360.0;
+			}
+			pcb_printf("\tadjusted start angle: '%f'\n", startAngle);
 		}
-		pcb_arc_new( &st->PCB->Data->Layer[PCBLayer], centreX, centreY, width, height, startAngle, -delta, Thickness, Clearance, Flags);
+		pcb_arc_new( &st->PCB->Data->Layer[PCBLayer], centreX, centreY, width, height, startAngle, delta, Thickness, Clearance, Flags);
 		return 0;
 	}
 	return -1;
@@ -680,7 +702,7 @@ static int kicad_parse_via(read_state_t *st, gsxl_node_t *subtree)
 						if (m->str != NULL) {
 							pcb_printf("\tvia layer: '%s'\n", (m->str));
 /*							PCBLayer = kicad_get_layeridx(st, m->str);
- *							if (PCBLayer == -1) {
+ *							if (PCBLayer < 0) {
  *								return -1;
  *							}   via layers not currently used in PCB
  */   
@@ -782,7 +804,7 @@ static int kicad_parse_segment(read_state_t *st, gsxl_node_t *subtree)
 					if (n->children != NULL && n->children->str != NULL) {
 						pcb_printf("\tsegment layer: '%s'\n", (n->children->str));
 						PCBLayer = kicad_get_layeridx(st, n->children->str);
-						if (PCBLayer == -1) {
+						if (PCBLayer < 0) {
 							return -1;
 						}
 					} else {
@@ -837,36 +859,45 @@ static int kicad_parse_segment(read_state_t *st, gsxl_node_t *subtree)
 /* Parse a layer definition and do all the administration needed for the layer */
 static int kicad_create_layer(read_state_t *st, int lnum, const char *lname, const char *ltype)
 {
-	int id = -1;
+	pcb_layer_id_t id = -1;
+	pcb_layergrp_id_t gid = -1;
 	switch(lnum) {
 		case 0:
-			id = PCB_SOLDER_SIDE;
-			pcb_layer_rename(id, lname);
+/*pcb_hid_actionl("dumpcsect", NULL);*/
+			pcb_layer_group_list(PCB_LYT_COPPER | PCB_LYT_BOTTOM, &gid, 1);
+			id = pcb_layer_create(gid, lname);
+/*printf("------------------------------\n");
+pcb_hid_actionl("dumpcsect", NULL);*/
 			break;
 		case 15:
-			id = PCB_COMPONENT_SIDE;
-			pcb_layer_rename(id, lname);
+			pcb_layer_group_list(PCB_LYT_COPPER | PCB_LYT_TOP, &gid, 1);
+			id = pcb_layer_create(gid, lname);
 			break;
 		default:
 			if (strcmp(lname, "Edge.Cuts") == 0) {
 				/* Edge must be the outline */
-				id = pcb_layer_create(PCB_LYT_OUTLINE, 0, 0, "outline");
+				pcb_layer_group_t *g = pcb_get_grp_new_intern(&PCB->LayerGroups, -1);
+				pcb_layergrp_fix_turn_to_outline(g);
+				id = pcb_layer_create(g - PCB->LayerGroups.grp, lname);
 			}
 			else if ((strcmp(ltype, "signal") == 0) || (strncmp(lname, "Dwgs.", 4) == 0) || (strncmp(lname, "Cmts.", 4) == 0) || (strncmp(lname, "Eco", 3) == 0)) {
 				/* Create a new inner layer for signals and for emulating misc layers */
-				id = pcb_layer_create(PCB_LYT_INTERN | PCB_LYT_COPPER, 0, 0, lname);
+				pcb_layer_group_t *g = pcb_get_grp_new_intern(&PCB->LayerGroups, -1);
+				id = pcb_layer_create(g - PCB->LayerGroups.grp, lname);
 			}
-#if 0
 			else if ((lname[1] == '.') && ((lname[0] == 'F') || (lname[0] == 'B'))) {
 				/* F. or B. layers */
 				if (strcmp(lname+2, "SilkS") == 0) return 0; /* silk layers are implicit */
+#if 0
 				if (strcmp(lname+2, "Adhes") == 0) return 0; /* pcb-rnd has no adhesive support */
 				if (strcmp(lname+2, "Paste") == 0) return 0; /* pcb-rnd has no custom paste support */
 				if (strcmp(lname+2, "Mask") == 0)  return 0; /* pcb-rnd has no custom mask support */
 				return -1; /* unknown F. or B. layer -> error */
-			}
 #endif
+				goto hack1;
+			}
 			else if (lnum > 15) {
+				hack1:;
 				/* HACK/WORKAROUND: remember kicad layers for those that are unsupported */
 				htsi_set(&st->layer_k2i, pcb_strdup(lname), -lnum);
 				return 0;
@@ -877,7 +908,7 @@ static int kicad_create_layer(read_state_t *st, int lnum, const char *lname, con
 
 /* valid layer, save it in the hash */
 	if (id >= 0) {
-	htsi_set(&st->layer_k2i, pcb_strdup(lname), id);
+		htsi_set(&st->layer_k2i, pcb_strdup(lname), id);
 	} else {
 		assert(id < -1);
 	}
@@ -887,9 +918,12 @@ static int kicad_create_layer(read_state_t *st, int lnum, const char *lname, con
 /* Register a kicad layer in the layer hash after looking up the pcb-rnd equivalent */
 static unsigned int kicad_reg_layer(read_state_t *st, const char *kicad_name, unsigned int mask)
 {
-	int id;
-	if (pcb_layer_list(mask, &id, 1) != 1)
-		return 1;
+	pcb_layer_id_t id;
+	if (pcb_layer_list(mask, &id, 1) != 1) {
+		pcb_layergrp_id_t gid;
+		pcb_layer_group_list(mask, &gid, 1);
+		id = pcb_layer_create(gid, kicad_name);
+	}
 	htsi_set(&st->layer_k2i, pcb_strdup(kicad_name), id);
 	return 0;
 }
@@ -911,11 +945,31 @@ static int kicad_parse_layer_definitions(read_state_t *st, gsxl_node_t *subtree)
 	int i;
 	unsigned int res;
 
+
 		if (strcmp(subtree->parent->parent->str, "kicad_pcb") != 0) { /* test if deeper in tree than layer definitions for entire board */  
 			pcb_printf("layer definitions encountered in unexpected place in kicad layout\n");
 			return -1;
 		} else { /* we are just below the top level or root of the tree, so this must be a layer definitions section */
-			pcb_layers_reset();
+			pcb_layergrp_inhibit_inc();
+			pcb_layer_group_setup_default(&PCB->LayerGroups);
+
+			/* set up the hash for implicit layers */
+			res = 0;
+			res |= kicad_reg_layer(st, "F.SilkS", PCB_LYT_SILK | PCB_LYT_TOP);
+			res |= kicad_reg_layer(st, "B.SilkS", PCB_LYT_SILK | PCB_LYT_BOTTOM);
+
+			/*
+			We don't have custom mask layers yet
+			res |= kicad_reg_layer(st, "F.Mask",  PCB_LYT_MASK | PCB_LYT_TOP);
+			res |= kicad_reg_layer(st, "B.Mask",  PCB_LYT_MASK | PCB_LYT_BOTTOM);
+			*/
+
+			if (res != 0) {
+				pcb_message(PCB_MSG_ERROR, "Internal error: can't find a silk or mask layer\n");
+				pcb_layergrp_inhibit_dec();
+				return -1;
+			}
+
 			pcb_printf("Board layer descriptions:\n");
 			for(n = subtree,i = 0; n != NULL; n = n->next, i++) {
 				if ((n->str != NULL) && (n->children->str != NULL) && (n->children->next != NULL) && (n->children->next->str != NULL) ) {
@@ -926,31 +980,19 @@ static int kicad_parse_layer_definitions(read_state_t *st, gsxl_node_t *subtree)
 					pcb_printf("\tlayer #%d layer description/type found:\t%s\n", i, ltype);
 					if (kicad_create_layer(st, lnum, lname, ltype) < 0) {
 						pcb_message(PCB_MSG_ERROR, "Unrecognized layer: %d, %s, %s\n", lnum, lname, ltype);
+						pcb_layergrp_inhibit_dec();
 						return -1;
 					}
 				} else {
 					printf("unexpected board layer definition(s) encountered.\n");
+					pcb_layergrp_inhibit_dec();
 					return -1;
 				}
 			}
-			pcb_layers_finalize();
-
-			/* set up the hash for implicit layers */
-			res = 0;
-			res |= kicad_reg_layer(st, "F.SilkS", PCB_LYT_SILK | PCB_LYT_TOP);
-			res |= kicad_reg_layer(st, "B.SilkS", PCB_LYT_SILK | PCB_LYT_BOTTOM);
 
-			/*
-			We don't have custom mask layers yet
-			res |= kicad_reg_layer(st, "F.Mask",  PCB_LYT_MASK | PCB_LYT_TOP);
-			res |= kicad_reg_layer(st, "B.Mask",  PCB_LYT_MASK | PCB_LYT_BOTTOM);
-			*/
-
-			if (res != 0) {
-				pcb_message(PCB_MSG_ERROR, "Internal error: can't find a silk or mask layer\n");
-				return -1;
-			}
+			pcb_layergrp_fix_old_outline(&PCB->LayerGroups);
 
+			pcb_layergrp_inhibit_dec();
 			return 0;
 		}
 }
@@ -984,11 +1026,14 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 	int moduleDefined = 0;
 	int PCBLayer = 0;
 	int kicadLayer = 15; /* default = top side */
+	int moduleOnTop = 1;
+	int padLayerDefCount = 0;
 	int SMD = 0;
 	int square = 0;
 	int throughHole = 0;
 	int foundRefdes = 0;
 	int refdesScaling  = 100;
+	int moduleEmpty = 1;
 	unsigned long tally = 0, featureTally, required;
 	pcb_coord_t moduleX, moduleY, X, Y, X1, Y1, X2, Y2, centreX, centreY, endX, endY, width, height, Thickness, Clearance, padXsize, padYsize, drill, refdesX, refdesY;
 	pcb_angle_t startAngle = 0.0;
@@ -1017,11 +1062,12 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 				if (n->children != NULL && n->children->str != NULL) {
 					pcb_printf("\tlayer: '%s'\n", (n->children->str));
 					PCBLayer = kicad_get_layeridx(st, n->children->str);
-					if (PCBLayer == -1) {
+					if (PCBLayer < 0) {
 						return -1;
 					} else if (pcb_layer_flags(PCBLayer) & PCB_LYT_BOTTOM) {
 							Flags = pcb_flag_make(PCB_FLAG_ONSOLDER);
 							TextFlags = pcb_flag_make(PCB_FLAG_ONSOLDER);
+							moduleOnTop = 0;
 					}
 				} else {
 					return -1;
@@ -1040,6 +1086,12 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 				} else {
 					return -1;
 				}
+			} else if (n->str != NULL && strcmp("attr", n->str) == 0) {
+				if (n->children != NULL && n->children->str != NULL) {
+					pcb_printf("\tmodule attribute \"attr\": '%s' (not used)\n", (n->children->str));
+				} else {
+					return -1;
+				}
 			} else if (n->str != NULL && strcmp("at", n->str) == 0) {
 				SEEN_NO_DUP(tally, 4);
 				if (n->children != NULL && n->children->str != NULL) {
@@ -1066,7 +1118,8 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 				} else {
 					return -1;
 				}
-
+			} else if (n->str != NULL && strcmp("model", n->str) == 0) {
+				pcb_printf("module 3D model found and ignored\n");
 			} else if (n->str != NULL && strcmp("fp_text", n->str) == 0) {
 					pcb_printf("fp_text found\n");
 					featureTally = 0;
@@ -1116,7 +1169,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 							X = PCB_MM_TO_COORD(val);
 							if (foundRefdes) {
 								refdesX = X;
-								pcb_printf("\tRefdesX = %mm", refdesX);
+								pcb_printf("\tRefdesX = %mm\n", refdesX);
 
 							}
 						}
@@ -1133,7 +1186,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 							Y = PCB_MM_TO_COORD(val);
 							if (foundRefdes) {
 								refdesY = Y;
-								pcb_printf("\tRefdesX = %mm", refdesY);
+								pcb_printf("\tRefdesY = %mm\n", refdesY);
 							}
 						}	
 						if (l->children->next->next != NULL && l->children->next->next->str != NULL) {
@@ -1162,14 +1215,18 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 				if (l->children != NULL && l->children->str != NULL) {
 					pcb_printf("\ttext layer: '%s'\n", (l->children->str));
 					PCBLayer = kicad_get_layeridx(st, l->children->str);
-					if (PCBLayer == -1) {
-						return -1;
+					if (PCBLayer < 0) {
+						pcb_printf("\ttext layer not defined for module text, default being used.\n");
+						Flags = pcb_flag_make(0);
+						/*return -1;*/
 					} else if (pcb_layer_flags(PCBLayer) & PCB_LYT_BOTTOM) {
 							Flags = pcb_flag_make(PCB_FLAG_ONSOLDER);
 					}
 				} else {
 					return -1;
 				}
+			} else if (l->str != NULL && strcmp("hide", l->str) == 0) {
+					pcb_printf("\ttext hidden flag \"hide\" found and ignored.\n");
 			} else if (l->str != NULL && strcmp("effects", l->str) == 0) {
 				SEEN_NO_DUP(featureTally, 5);
 				for(m = l->children; m != NULL; m = m->next) {
@@ -1274,7 +1331,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 		}
 
 		if (moduleValue != NULL && moduleRefdes != NULL && moduleName != NULL && moduleDefined == 0) {
-			moduleDefined = 1;
+			moduleDefined = 1; /* but might be empty, wait and see */
 			printf("now have RefDes %s and Value %s, can now define module/element %s\n", moduleRefdes, moduleValue, moduleName);
 			newModule = pcb_element_new(st->PCB->Data, NULL,
 								 &st->PCB->Font, Flags,
@@ -1319,6 +1376,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 			/* pads next  - have thru_hole, circle, rect, roundrect, to think about*/ 
 			} else if (n->str != NULL && strcmp("pad", n->str) == 0) {
 				featureTally = 0;
+				padLayerDefCount = 0;
 				if (n->children != 0 && n->children->str != NULL) {
 					printf("pad name found: %s\n", n->children->str);
 					pinName = n->children->str;
@@ -1388,14 +1446,28 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 							for(l = m->children; l != NULL; l = l->next) {
 								if (l->str != NULL) {
 									PCBLayer = kicad_get_layeridx(st, l->str);
-									if (PCBLayer == -1) {
-										printf("Unknown layer definition: %s", l->str);
-										return -1;
+									if (PCBLayer < 0) {
+										/* we ignore *.mask, *.paste, etc., if valid layer def already found */
+										printf("Unknown layer definition: %s\n", l->str);
+										if (!padLayerDefCount) {
+											printf("Default placement of pad is the copper layer defined for module as a whole\n");
+
+											/*return -1;*/
+											if (!moduleOnTop) {
+												kicadLayer = 0;
+											}
+										}
 									} else if (PCBLayer < -1) {
-										printf("\tUnimplemented layer definition: %s", l->str);
+										printf("\tUnimplemented layer definition: %s\n", l->str);
 									} else if (pcb_layer_flags(PCBLayer) & PCB_LYT_BOTTOM) {
-										Flags = pcb_flag_make(PCB_FLAG_ONSOLDER);
 										kicadLayer = 0;
+										padLayerDefCount++;
+									} else if (padLayerDefCount) {
+										printf("More than one valid pad layer found, only using the first one found for layer.\n");
+										padLayerDefCount++;
+									} else {
+										padLayerDefCount++;
+										printf("Valid layer defs found for current pad: %d\n", padLayerDefCount);
 									}
 									pcb_printf("\tpad layer: '%s',  PCB layer number %d\n", (l->str), kicad_get_layeridx(st, l->str));
 								} else {
@@ -1467,6 +1539,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 					printf("\tcreating new pin %s in element\n", pinName);
 					required = BV(0) | BV(1) | BV(3) | BV(5);
         				if ((featureTally & required) == required) {
+						moduleEmpty = 0;
 						pcb_element_pin_new(newModule, X + moduleX, Y + moduleY, padXsize, Clearance,
 								Clearance, drill, pinName, pinName, Flags); /* using clearance value for arg 5 = mask too */
 					} else {
@@ -1475,7 +1548,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 				} else if (newModule != NULL) {
 					printf("\tcreating new pad %s in element\n", pinName);
                                         required = BV(0) | BV(1) | BV(2) | BV(5);
-                                        if ((featureTally & required) == required) {	
+                                        if ((featureTally & required) == required) {
 						if (padXsize >= padYsize) { /* square pad or rectangular pad, wider than tall */
 							Y1 = Y2 = Y;
 							X1 = X - (padXsize - padYsize)/2;
@@ -1496,6 +1569,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 						} else {
 							Flags = pcb_flag_make(PCB_FLAG_ONSOLDER);
 						}
+						moduleEmpty = 0;
 						pcb_element_pad_new(newModule, X1 + moduleX, Y1 + moduleY, X2 + moduleX, Y2 + moduleY, Thickness, Clearance, 
 								Clearance, pinName, pinName, Flags); /* using clearance value for arg 7 = mask too */
 					} else {
@@ -1572,7 +1646,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 						pcb_printf("\tfp_line layer: '%s'\n", (l->children->str));
 						SEEN_NO_DUP(featureTally, 7);
 						PCBLayer = kicad_get_layeridx(st, l->children->str);
-						if (PCBLayer == -1) {
+						if (PCBLayer < 0) {
 							return -1;
 						}
 					} else {
@@ -1618,6 +1692,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 	}
 	required = BV(0) | BV(3) | BV(6) | BV(8);
 	if (((featureTally & required) == required) && newModule != NULL) { /* need start, end, layer, thickness at a minimum */
+		moduleEmpty = 0;
 		pcb_element_line_new(newModule, X1, Y1, X2, Y2, Thickness);
 		pcb_printf("\tnew fp_line on layer created\n");
 	}
@@ -1717,7 +1792,7 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 						pcb_printf("\tfp_arc layer: '%s'\n", (l->children->str));
 						SEEN_NO_DUP(featureTally, 7);
 						PCBLayer = kicad_get_layeridx(st, l->children->str);
-						if (PCBLayer == -1) {
+						if (PCBLayer < 0) {
 							return -1;
 						}
 					} else {
@@ -1769,25 +1844,30 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 	}
         required = BV(0) | BV(6) | BV(8);
         if (((featureTally & required) == required) && newModule != NULL) {
+		moduleEmpty = 0;
 		/* need start, layer, thickness at a minimum */
+		/* same code used above for gr_arc parsing */
 		width = height = pcb_distance(centreX, centreY, endX, endY); /* calculate radius of arc */
 		if (width < 1) { /* degenerate case */
 			startAngle = 0;
 		} else {
-			endAngle = 180*atan2(-(endY - centreY), endX - centreX)/M_PI; /* avoid using atan2 with zero parameters */
+			endAngle = 180+180*atan2(-(endY - centreY), endX - centreX)/M_PI; /* avoid using atan2 with zero parameters */
+			pcb_printf("\tcalculated end angle: '%f'\n", endAngle);
 			if (endAngle < 0.0) {
 				endAngle += 360.0; /*make it 0...360 */
+				pcb_printf("\tadjusted end angle: '%f'\n", endAngle);
 			}
-			startAngle = endAngle + delta; /* geda is 180 degrees out of phase with kicad, and opposite direction rotation */
+			startAngle = (endAngle - delta); /* geda is 180 degrees out of phase with kicad, and opposite direction rotation */
+			pcb_printf("\tcalculated start angle: '%f'\n", startAngle);
 			if (startAngle > 360.0) {
 				startAngle -= 360.0;
 			}
 			if (startAngle < 0.0) {
 				startAngle += 360.0;
 			}
-
+			pcb_printf("\tadjusted start angle: '%f'\n", startAngle);
 		}
-		pcb_element_arc_new(newModule, moduleX + centreX, moduleY + centreY, width, height, endAngle, delta, Thickness);
+		pcb_element_arc_new(newModule, moduleX + centreX, moduleY + centreY, width, height, startAngle, delta, Thickness); /* was endAngle */
 
 	}
 
@@ -1802,6 +1882,11 @@ static int kicad_parse_module(read_state_t *st, gsxl_node_t *subtree)
 		}
 
 		if (newModule != NULL) {
+			if (moduleEmpty) {
+				Thickness = PCB_MM_TO_COORD(0.200);
+				pcb_element_line_new(newModule, moduleX, moduleY, moduleX+1, moduleY+1, Thickness);
+				pcb_printf("\tEmpty Module!! 1nm line created at module centroid.\n");
+			}
 			pcb_element_bbox(PCB->Data, newModule, &PCB->Font);
 			return 0; 
 		} else {
@@ -1831,7 +1916,7 @@ static int kicad_parse_zone(read_state_t *st, gsxl_node_t *subtree)
 
 	if (subtree->str != NULL) {
 		printf("Zone element found:\t'%s'\n", subtree->str);
-		for(n = subtree->next,i = 0; n != NULL; n = n->next, i++) {
+		for(n = subtree,i = 0; n != NULL; n = n->next, i++) {
 			if (n->str != NULL && strcmp("net", n->str) == 0) {
 				SEEN_NO_DUP(tally, 0);
 				if (n->children != NULL && n->children->str != NULL) {
@@ -1889,7 +1974,7 @@ static int kicad_parse_zone(read_state_t *st, gsxl_node_t *subtree)
 				if (n->children != NULL && n->children->str != NULL) {
 					pcb_printf("\tzone layer:\t'%s'\n", (n->children->str));
 					PCBLayer = kicad_get_layeridx(st, n->children->str);
-					if (PCBLayer == -1) {
+					if (PCBLayer < 0) {
 						return -1;
 					}
 					polygon = pcb_poly_new(&st->PCB->Data->Layer[PCBLayer], flags);
@@ -2046,6 +2131,7 @@ int io_kicad_read_pcb(pcb_plug_io_t *ctx, pcb_board_t *Ptr, const char *Filename
 
 	/* load the file into the dom */
 	gsxl_init(&st.dom, gsxl_node_t);
+	st.dom.parse.line_comment_char = '#';
 	do {
 		c = fgetc(FP);
 	} while((res = gsxl_parse_char(&st.dom, c)) == GSX_RES_NEXT);
diff --git a/src_plugins/io_kicad/write.c b/src_plugins/io_kicad/write.c
index d38e073..7c6f2d3 100644
--- a/src_plugins/io_kicad/write.c
+++ b/src_plugins/io_kicad/write.c
@@ -70,7 +70,7 @@ int io_kicad_write_buffer(pcb_plug_io_t *ctx, FILE * FP, pcb_buffer_t *buff)
 	pcb_write_element_data(FP, buff->Data, "kicadl");
 
 	/*
-		for (i = 0; i < pcb_max_copper_layer + 2; i++)
+		for (i = 0; i < pcb_max_layer; i++)
 		WriteLayerData(FP, i, &(buff->Data->Layer[i]));
 	*/
 	return (0);
@@ -686,12 +686,12 @@ pcb_box_t *pcb_arc_get_ends(pcb_arc_t *Arc); */
 			pcb_arc_get_end(&localArc, 0, &copperStartX, &copperStartY);
 			copperStartX += xOffset;
 			copperStartY += yOffset;
-			if ((currentLayer < 16) || (currentLayer == 28)) { /* a copper arc, i.e. track, or edge cut, is unsupported by kicad, and will be exported as a line */
+			if ((currentLayer < 16) ) { /*|| (currentLayer == 28)) {  a copper arc, i.e. track, but not edge cut, is unsupported by kicad, and will be exported as a line */
 				fprintf(FP, "%*s", indentation, "");
 				pcb_fprintf(FP, "(segment (start %.3mm %.3mm) (end %.3mm %.3mm) (layer %s) (width %.3mm))\n",
 										copperStartX, copperStartY, xEnd, yEnd,
 										kicad_sexpr_layer_to_text(currentLayer), arc->Thickness); /* neglect (net ___ ) for now */
-			} else if ((currentLayer == 20) || (currentLayer == 21)) { /* a silk arc, or outline */
+			} else if ((currentLayer == 20) || (currentLayer == 21) || (currentLayer == 28)) { /* a silk arc, or outline */
 				fprintf(FP, "%*s", indentation, "");
 				pcb_fprintf(FP, "(gr_arc (start %.3mm %.3mm) (end %.3mm %.3mm) (angle %ma) (layer %s) (width %.3mm))\n",
 										xStart, yStart, xEnd, yEnd, arc->Delta,
diff --git a/src_plugins/io_kicad_legacy/write.c b/src_plugins/io_kicad_legacy/write.c
index f81427a..5e7cbf5 100644
--- a/src_plugins/io_kicad_legacy/write.c
+++ b/src_plugins/io_kicad_legacy/write.c
@@ -67,7 +67,7 @@ int io_kicad_legacy_write_buffer(pcb_plug_io_t *ctx, FILE * FP, pcb_buffer_t *bu
 	pcb_write_element_data(FP, buff->Data, "kicadl");
 
 	/*
-		for (i = 0; i < pcb_max_copper_layer + 2; i++)
+		for (i = 0; i < pcb_max_layer; i++)
 		WriteLayerData(FP, i, &(buff->Data->Layer[i]));
 	*/
 	return (0);
diff --git a/src_plugins/io_lihata/read.c b/src_plugins/io_lihata/read.c
index 2b6caf4..ad93655 100644
--- a/src_plugins/io_lihata/read.c
+++ b/src_plugins/io_lihata/read.c
@@ -536,15 +536,18 @@ static int parse_data_layer(pcb_board_t *pcb, pcb_data_t *dt, lht_node_t *grp, i
 	lht_node_t *n, *lst;
 	lht_dom_iterator_t it;
 
-	pcb_layer_t *ly = &dt->Layer[dt->LayerN];
-	dt->LayerN++;
+	pcb_layer_t *ly = &dt->Layer[layer_id];
+	if (layer_id >= dt->LayerN)
+		dt->LayerN = layer_id+1;
 
 	ly->Name = pcb_strdup(grp->name);
+
 	parse_bool(&ly->On, lht_dom_hash_get(grp, "visible"));
 	if (pcb != NULL) {
 		int grp_id;
 		parse_int(&grp_id, lht_dom_hash_get(grp, "group"));
-		pcb_layer_add_in_group(layer_id, grp_id);
+		dt->Layer[layer_id].grp = grp_id;
+/*		pcb_trace("parse_data_layer name: %d,%d '%s' grp=%d\n", layer_id, dt->LayerN-1, ly->Name, grp_id);*/
 	}
 
 	lst = lht_dom_hash_get(grp, "objects");
@@ -577,7 +580,6 @@ static int parse_data_layers(pcb_board_t *pcb, pcb_data_t *dt, lht_node_t *grp)
 		if (n->type == LHT_HASH)
 			parse_data_layer(pcb, dt, n, id);
 
-	dt->LayerN -= 2; /* for the silk layers... */
 	return 0;
 }
 
@@ -716,26 +718,77 @@ static int parse_data_objects(pcb_board_t *pcb_for_font, pcb_data_t *dt, lht_nod
 	return 0;
 }
 
+static void layer_fixup(pcb_board_t *pcb)
+{
+	int n;
+	pcb_layergrp_id_t top_silk, bottom_silk;
+	pcb_layer_group_t *g;
+
+	pcb_layergrp_inhibit_inc();
+
+	pcb_layer_group_setup_default(&pcb->LayerGroups);
+
+	/* old silk assumption: last two layers are silk, bottom and top */
+	bottom_silk = pcb->Data->Layer[pcb->Data->LayerN-2].grp;
+	top_silk = pcb->Data->Layer[pcb->Data->LayerN-1].grp;
+	pcb->Data->Layer[pcb->Data->LayerN-2].grp = -1;
+	pcb->Data->Layer[pcb->Data->LayerN-1].grp = -1;
+
+/*	pcb_trace("NAME: '%s' '%s'\n", pcb->Data->Layer[pcb->Data->LayerN-1].Name,pcb->Data->Layer[pcb->Data->LayerN-2].Name);*/
+
+	for(n = 0; n < pcb->Data->LayerN - 2; n++) {
+		pcb_layer_t *l = &pcb->Data->Layer[n];
+		pcb_layergrp_id_t grp = l->grp;
+		/*pcb_trace("********* l=%d %s g=%ld (top=%ld bottom=%ld)\n", n, l->Name, grp, top_silk, bottom_silk);*/
+		l->grp = -1;
+
+		if (grp == bottom_silk)
+			g = pcb_get_grp(&pcb->LayerGroups, PCB_LYT_BOTTOM, PCB_LYT_COPPER);
+		else if (grp == top_silk)
+			g = pcb_get_grp(&pcb->LayerGroups, PCB_LYT_TOP, PCB_LYT_COPPER);
+		else
+			g = pcb_get_grp_new_intern(&pcb->LayerGroups, grp);
+/*			pcb_trace(" add %ld\n", g - pcb->LayerGroups.grp);*/
+		pcb_layer_add_in_group_(g, g - pcb->LayerGroups.grp, n);
+		if (strcmp(l->Name, "outline") == 0)
+			pcb_layergrp_fix_turn_to_outline(g);
+	}
+
+	pcb_layergrp_fix_old_outline(&pcb->LayerGroups);
+
+	/* link in the 2 hardwired silks */
+	g = pcb_get_grp(&pcb->LayerGroups, PCB_LYT_BOTTOM, PCB_LYT_SILK);
+	pcb_layer_add_in_group_(g, g - pcb->LayerGroups.grp, pcb->Data->LayerN-2);
+	g = pcb_get_grp(&pcb->LayerGroups, PCB_LYT_TOP, PCB_LYT_SILK);
+	pcb_layer_add_in_group_(g, g - pcb->LayerGroups.grp, pcb->Data->LayerN-1);
+	pcb_layergrp_inhibit_dec();
+}
+
 static pcb_data_t *parse_data(pcb_board_t *pcb, lht_node_t *nd)
 {
 	pcb_data_t *dt;
 	lht_node_t *grp;
+	int need_layer_fixup = 1;
+
 	if (nd->type != LHT_HASH)
 		return NULL;
 
 	dt = calloc(sizeof(pcb_data_t), 1);
+	dt->pcb = pcb;
+	pcb->Data = dt;
 
 	grp = lht_dom_hash_get(nd, "layers");
 	if ((grp != NULL) && (grp->type == LHT_LIST))
 		parse_data_layers(pcb, dt, grp);
 
+#warning layer TODO: read layer groups - if present, set need_layer_fixup to 0
+	if (need_layer_fixup)
+		layer_fixup(pcb);
+
 	grp = lht_dom_hash_get(nd, "objects");
 	if (grp != NULL)
 		parse_data_objects(pcb, dt, grp);
 
-	dt->pcb = pcb;
-
-
 	return dt;
 }
 
@@ -974,7 +1027,7 @@ static int parse_board(pcb_board_t *pcb, lht_node_t *nd)
 		return -1;
 
 	sub = lht_dom_hash_get(nd, "data");
-	if ((sub != NULL) && ((pcb->Data = parse_data(pcb, sub)) == NULL))
+	if ((sub != NULL) && ((parse_data(pcb, sub)) == NULL))
 		return -1;
 
 	sub = lht_dom_hash_get(nd, "font");
@@ -1029,7 +1082,7 @@ int io_lihata_parse_pcb(pcb_plug_io_t *ctx, pcb_board_t *Ptr, const char *Filena
 typedef enum {
 	TPS_UNDECIDED,
 	TPS_GOOD,
-	TPS_BAD,
+	TPS_BAD
 } test_parse_t;
 
 /* expect root to be a ha:pcb-rnd-board-v* */
diff --git a/src_plugins/io_lihata/write.c b/src_plugins/io_lihata/write.c
index 4a08ce8..942ce1f 100644
--- a/src_plugins/io_lihata/write.c
+++ b/src_plugins/io_lihata/write.c
@@ -171,7 +171,7 @@ static lht_node_t *build_flags(pcb_flag_t *f, int object_type)
 	/* thermal flags per layer */
 	lst = lht_dom_node_alloc(LHT_HASH, "thermal");
 
-	for(layer = 0; layer < pcb_max_copper_layer; layer++) {
+	for(layer = 0; layer < pcb_max_layer; layer++) {
 		if (PCB_FLAG_THERM_TEST_ANY(&fh)) {
 			int t = PCB_FLAG_THERM_GET(layer, &fh);
 			if (t != 0) {
@@ -471,11 +471,49 @@ static lht_node_t *build_data_layers(pcb_data_t *data)
 {
 	int n;
 	lht_node_t *layers;
+	pcb_layergrp_id_t gm, grp[PCB_MAX_LAYERGRP], gtop = -1, gbottom = -1;
+	pcb_layer_group_t *g;
+	int v1_layers = 1;
 
 	layers = lht_dom_node_alloc(LHT_LIST, "layers");
 
-	for(n = 0; n < pcb_max_copper_layer + 2; n++)
-		lht_dom_list_append(layers, build_data_layer(data, data->Layer+n, pcb_layer_lookup_group(n)));
+	if (v1_layers) {
+		/* produce an old layer group assignment from top to bottom */
+		gm = 0;
+		for(n = 0; n < pcb_max_group; n++) {
+			unsigned int gflg = pcb_layergrp_flags(n);
+			if (gflg & PCB_LYT_COPPER) {
+				if (gflg & PCB_LYT_TOP)
+					gtop = gm;
+				if (gflg & PCB_LYT_BOTTOM)
+					gbottom = gm;
+				grp[n] = gm;
+/*				pcb_trace("build data layers: %d -> %ld {%ld %ld}\n", n, gm, gtop, gbottom); */
+				gm++;
+			}
+			else
+				grp[n] = -1;
+		}
+
+		g = pcb_get_grp(&PCB->LayerGroups, PCB_LYT_BOTTOM, PCB_LYT_SILK);
+		grp[g - PCB->LayerGroups.grp] = gbottom;
+
+		g = pcb_get_grp(&PCB->LayerGroups, PCB_LYT_TOP, PCB_LYT_SILK);
+		grp[g - PCB->LayerGroups.grp] = gtop;
+	}
+
+	for(n = 0; n < pcb_max_layer; n++) {
+		int gid = pcb_layer_lookup_group(n);
+		if (v1_layers) {
+			if (gid >= 0) {
+				if (gid < sizeof(grp) / sizeof(grp[0]))
+					gid = grp[gid];
+				else
+					gid = -1;
+			}
+		}
+		lht_dom_list_append(layers, build_data_layer(data, data->Layer+n, gid));
+	}
 
 	return layers;
 }
diff --git a/src_plugins/io_lihata/write_style.c b/src_plugins/io_lihata/write_style.c
index 1607779..84b46ac 100644
--- a/src_plugins/io_lihata/write_style.c
+++ b/src_plugins/io_lihata/write_style.c
@@ -27,6 +27,7 @@
 #include "write_style.h"
 
 #define PB_BEGIN     {"*", 2, 2}
+#define PB_BEGINSP   {" *", 3, 3}
 #define PB_BEGINNL   {"\n *", 4, 4}
 #define PB_EMPTY     {"", 1, 1}
 #define PB_SEMICOLON {";", 2, 2}
@@ -70,6 +71,15 @@ static lht_perstyle_t style_newline = {
 	/* name_braced */ 0
 };
 
+static lht_perstyle_t style_newline_sp = {
+	/* buff */        {PB_BEGINSP, PB_EMPTY, PB_EMPTY, PB_EMPTY, PB_EMPTY, PB_NEWLINE},
+	/* has_eq */      1,
+	/* val_brace */   0,
+	/* etype */       0,
+	/* ename */       1,
+	/* name_braced */ 0
+};
+
 static lht_perstyle_t style_istruct = {
 	/* buff */        {PB_SPACE, PB_SPACE, PB_LBRACE, PB_EMPTY, PB_EMPTY, PB_RBRACESC},
 	/* has_eq */      1,
@@ -129,11 +139,11 @@ static lht_perstyle_t early_nl = {
 };
 
 
-static const char *pat_te_flags[]  = {"te:*", "ha:flags", "*", NULL};
-static const char *pat_te_attr[]   = {"te:*", "ha:attributes", "*", NULL};
+static const char *pat_te_flags[]      = {"te:*", "ha:flags", "*", NULL};
+static const char *pat_te_attr[]       = {"te:*", "ha:attributes", "*", NULL};
 static lhtpers_rule_t r_ilists[]   = {
 	{pat_te_flags,  &style_inline_tight, NULL},
-	{pat_te_attr,   &style_newline, NULL},
+	{pat_te_attr,   &style_newline_sp, NULL},
 	{NULL, NULL, NULL}
 };
 
@@ -301,9 +311,11 @@ static lhtpers_rule_t r_data[] = {
 };
 
 static const char *pat_width[]   = {"te:width", "*", NULL};
+static const char *pat_height[]  = {"te:height", "*", NULL};
 static const char *pat_delta[]   = {"te:delta", "*", NULL};
 static lhtpers_rule_t r_symbol[] = {
 	{pat_width,      &style_inline, NULL},
+	{pat_height,     &style_inline, NULL},
 	{pat_delta,      &style_inline, NULL},
 	{pat_objects,    &style_nlstruct, NULL},
 	{pat_attributes,       &style_nlstruct, NULL},
@@ -326,12 +338,14 @@ static const char *pat_li_styles[]   = {"li:styles", "*", NULL};
 static const char *pat_ha_meta[]     = {"ha:meta", "*", NULL};
 static const char *pat_ha_data[]     = {"ha:data", "*", NULL};
 static const char *pat_ha_font[]     = {"ha:font", "*", NULL};
+static const char *pat_ha_netlists[] = {"ha:netlists", "*", NULL};
 static lhtpers_rule_t r_root[] = {
 	{pat_attributes,      &style_nlstruct, NULL},
 	{pat_li_styles,       &style_nlstruct, NULL},
 	{pat_ha_meta,         &style_nlstruct, NULL},
 	{pat_ha_data,         &style_nlstruct, NULL},
 	{pat_ha_font,         &style_nlstruct, NULL},
+	{pat_ha_netlists,     &style_nlstruct, NULL},
 	{NULL, NULL, NULL}
 };
 
@@ -355,7 +369,6 @@ static const char *pat_elem[] = {"ha:element.*", "*", NULL};
 static const char *pat_text[] = {"ha:text.*", "*", NULL};
 static const char *pat_data[] = {"ha:data", "*", NULL};
 static const char *pat_netlists[] = {"ha:netlists", "*", NULL};
-static const char *pat_objs[] = {"li:objects", "*", NULL};
 static const char *pat_font1[] = {"ha:geda_pcb", "ha:font", "*", NULL};
 static const char *pat_layer[] = {"ha:*", "li:layers", "*", NULL};
 static const char *pat_symbol[] = {"ha:*", "ha:symbols", "*", NULL};
@@ -371,34 +384,34 @@ static const char *pat_lconn[] = {"li:conn", "ha:*", "li:*", "ha:netlists", "*",
 static const char *pat_root[] = {"^", NULL};
 
 static lhtpers_rule_t r_istructs[] = {
-	{pat_root,    &style_struct, r_root, NULL},
-
-	{pat_layer,   &style_nlstruct, r_layer, NULL},
-	{pat_symbol,  &style_structi, r_symbol, NULL},
-
-	{pat_line,    &style_structi, r_line, NULL},
-	{pat_rat,     &style_structi, r_rat, NULL},
-	{pat_arc,     &style_structi, r_arc, NULL},
-	{pat_via,     &style_structi, r_pinvia, NULL},
-	{pat_pin,     &style_structi, r_pinvia, NULL},
-	{pat_pad,     &style_structi, r_pad, NULL},
-	{pat_poly,    &style_structs, r_polygon, NULL},
-	{pat_elem,    &style_structi, r_element, NULL},
-	{pat_text,    &style_structi, r_text, NULL},
-	{pat_data,    &style_structi, r_data, NULL},
-	{pat_font1,   &style_structi, r_font1, NULL},
-	{pat_netlists,&style_struct, r_netlists, NULL},
-	{pat_objs,    &style_structi, NULL, NULL},
-	{pat_flag,    &style_newline, NULL, NULL},
-
-	{pat_cell,    &style_inline, NULL, NULL},
-	{pat_thermt,  &style_inline, NULL, NULL},
-	{pat_del_add, &style_struct_thermal, NULL, NULL},
-	{pat_netinfo, &style_struct_thermal, NULL, NULL},
-	{pat_netinft, &style_inline, NULL, NULL},
-	{pat_nettxt,  &style_inline, NULL, NULL},
-	{pat_tconn,   &style_inline, NULL, NULL},
-	{pat_lconn,   &style_struct_thermal, NULL, NULL},
+	{pat_root,    &style_struct, r_root},
+
+	{pat_layer,   &style_nlstruct, r_layer},
+	{pat_symbol,  &style_structi,  r_symbol},
+
+	{pat_line,    &style_structi,  r_line},
+	{pat_rat,     &style_structi,  r_rat},
+	{pat_arc,     &style_structi,  r_arc},
+	{pat_via,     &style_structi,  r_pinvia},
+	{pat_pin,     &style_structi,  r_pinvia},
+	{pat_pad,     &style_structi,  r_pad},
+	{pat_poly,    &style_structs,  r_polygon},
+	{pat_elem,    &style_structi,  r_element},
+	{pat_text,    &style_structi,  r_text},
+	{pat_data,    &style_structi,  r_data},
+	{pat_font1,   &style_structi,  r_font1},
+	{pat_netlists,&style_struct,   r_netlists},
+	{pat_objects, &style_nlstruct, NULL},
+	{pat_flag,    &style_newline,  NULL},
+
+	{pat_cell,    &style_inline,   NULL},
+	{pat_thermt,  &style_inline,   NULL},
+	{pat_del_add, &style_struct_thermal, NULL},
+	{pat_netinfo, &style_struct_thermal, NULL},
+	{pat_netinft, &style_inline,   NULL},
+	{pat_nettxt,  &style_inline,   NULL},
+	{pat_tconn,   &style_inline,   NULL},
+	{pat_lconn,   &style_struct_thermal, NULL},
 	{NULL, NULL, NULL}
 };
 
@@ -463,56 +476,56 @@ static const char *cpat_styl_da[] = {"te:diameter", "ha:*", "li:styles", "*", NU
 
 
 lhtpers_rule_t io_lihata_out_coords[] = {
-	{cpat_rat_x1,   NULL, NULL, NULL},
-	{cpat_rat_y1,   NULL, NULL, NULL},
-	{cpat_rat_x2,   NULL, NULL, NULL},
-	{cpat_rat_y2,   NULL, NULL, NULL},
-	{cpat_line_x1,  NULL, NULL, NULL},
-	{cpat_line_y1,  NULL, NULL, NULL},
-	{cpat_line_x2,  NULL, NULL, NULL},
-	{cpat_line_y2,  NULL, NULL, NULL},
-	{cpat_line_th,  NULL, NULL, NULL},
-	{cpat_line_cl,  NULL, NULL, NULL},
-	{cpat_size_x,   NULL, NULL, NULL},
-	{cpat_size_y,   NULL, NULL, NULL},
-	{cpat_curs_x,   NULL, NULL, NULL},
-	{cpat_curs_y,   NULL, NULL, NULL},
-	{cpat_curs_z,   NULL, NULL, NULL},
-	{cpat_drc_min,  NULL, NULL, NULL},
-	{cpat_drc_blt,  NULL, NULL, NULL},
-	{cpat_drc_shr,  NULL, NULL, NULL},
-	{cpat_grido,    NULL, NULL, NULL},
-	{cpat_grids,    NULL, NULL, NULL},
-	{cpat_arc_x,    NULL, NULL, NULL},
-	{cpat_arc_y,    NULL, NULL, NULL},
-	{cpat_arc_w,    NULL, NULL, NULL},
-	{cpat_arc_h,    NULL, NULL, NULL},
-	{cpat_arc_th,   NULL, NULL, NULL},
-	{cpat_arc_cl,   NULL, NULL, NULL},
-	{cpat_geo_ta,   NULL, NULL, NULL},
-	{cpat_text_x,   NULL, NULL, NULL},
-	{cpat_text_y,   NULL, NULL, NULL},
-	{cpat_pin_x,    NULL, NULL, NULL},
-	{cpat_pin_y,    NULL, NULL, NULL},
-	{cpat_pin_hole, NULL, NULL, NULL},
-	{cpat_pin_mask, NULL, NULL, NULL},
-	{cpat_pad_x1,   NULL, NULL, NULL},
-	{cpat_pad_y1,   NULL, NULL, NULL},
-	{cpat_pad_x2,   NULL, NULL, NULL},
-	{cpat_pad_y2,   NULL, NULL, NULL},
-	{cpat_pad_hole, NULL, NULL, NULL},
-	{cpat_pad_mask, NULL, NULL, NULL},
-	{cpat_elem_x,   NULL, NULL, NULL},
-	{cpat_elem_y,   NULL, NULL, NULL},
-	{cpat_sym_w,    NULL, NULL, NULL},
-	{cpat_sym_h,    NULL, NULL, NULL},
-	{cpat_sym_d,    NULL, NULL, NULL},
-	{cpat_font_w,   NULL, NULL, NULL},
-	{cpat_font_h,   NULL, NULL, NULL},
-	{cpat_styl_th,  NULL, NULL, NULL},
-	{cpat_styl_cl,  NULL, NULL, NULL},
-	{cpat_styl_hl,  NULL, NULL, NULL},
-	{cpat_styl_da,  NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL}
+	{cpat_rat_x1,   NULL, NULL},
+	{cpat_rat_y1,   NULL, NULL},
+	{cpat_rat_x2,   NULL, NULL},
+	{cpat_rat_y2,   NULL, NULL},
+	{cpat_line_x1,  NULL, NULL},
+	{cpat_line_y1,  NULL, NULL},
+	{cpat_line_x2,  NULL, NULL},
+	{cpat_line_y2,  NULL, NULL},
+	{cpat_line_th,  NULL, NULL},
+	{cpat_line_cl,  NULL, NULL},
+	{cpat_size_x,   NULL, NULL},
+	{cpat_size_y,   NULL, NULL},
+	{cpat_curs_x,   NULL, NULL},
+	{cpat_curs_y,   NULL, NULL},
+	{cpat_curs_z,   NULL, NULL},
+	{cpat_drc_min,  NULL, NULL},
+	{cpat_drc_blt,  NULL, NULL},
+	{cpat_drc_shr,  NULL, NULL},
+	{cpat_grido,    NULL, NULL},
+	{cpat_grids,    NULL, NULL},
+	{cpat_arc_x,    NULL, NULL},
+	{cpat_arc_y,    NULL, NULL},
+	{cpat_arc_w,    NULL, NULL},
+	{cpat_arc_h,    NULL, NULL},
+	{cpat_arc_th,   NULL, NULL},
+	{cpat_arc_cl,   NULL, NULL},
+	{cpat_geo_ta,   NULL, NULL},
+	{cpat_text_x,   NULL, NULL},
+	{cpat_text_y,   NULL, NULL},
+	{cpat_pin_x,    NULL, NULL},
+	{cpat_pin_y,    NULL, NULL},
+	{cpat_pin_hole, NULL, NULL},
+	{cpat_pin_mask, NULL, NULL},
+	{cpat_pad_x1,   NULL, NULL},
+	{cpat_pad_y1,   NULL, NULL},
+	{cpat_pad_x2,   NULL, NULL},
+	{cpat_pad_y2,   NULL, NULL},
+	{cpat_pad_hole, NULL, NULL},
+	{cpat_pad_mask, NULL, NULL},
+	{cpat_elem_x,   NULL, NULL},
+	{cpat_elem_y,   NULL, NULL},
+	{cpat_sym_w,    NULL, NULL},
+	{cpat_sym_h,    NULL, NULL},
+	{cpat_sym_d,    NULL, NULL},
+	{cpat_font_w,   NULL, NULL},
+	{cpat_font_h,   NULL, NULL},
+	{cpat_styl_th,  NULL, NULL},
+	{cpat_styl_cl,  NULL, NULL},
+	{cpat_styl_hl,  NULL, NULL},
+	{cpat_styl_da,  NULL, NULL},
+	{NULL, NULL, NULL}
 };
 
diff --git a/src_plugins/io_pcb/attribs.c b/src_plugins/io_pcb/attribs.c
index 52d6625..c648627 100644
--- a/src_plugins/io_pcb/attribs.c
+++ b/src_plugins/io_pcb/attribs.c
@@ -81,6 +81,8 @@ static void c2a(pcb_board_t *pcb, lht_node_t *tree, const char *path1)
 				gds_t conc;
 				gds_init(&conc);
 				for(i = n->data.list.first; i != NULL; i = i->next) {
+					if (i->data.text.value == NULL)
+						continue;
 					if (i != n->data.list.first)
 						gds_append_str(&conc, LISTSEP);
 					gds_append_str(&conc, i->data.text.value);
diff --git a/src_plugins/io_pcb/file.c b/src_plugins/io_pcb/file.c
index 5b3ac12..4a7e4c4 100644
--- a/src_plugins/io_pcb/file.c
+++ b/src_plugins/io_pcb/file.c
@@ -143,7 +143,7 @@ static const char *c_dtostr(double d)
 }
 
 /* Returns pointer to private buffer */
-static char *LayerGroupsToString(pcb_layer_group_t *lg)
+static char *LayerGroupsToString(pcb_layer_stack_t *lg)
 {
 #if PCB_MAX_LAYER < 9998
 	/* Allows for layer numbers 0..9999 */
@@ -152,26 +152,37 @@ static char *LayerGroupsToString(pcb_layer_group_t *lg)
 	char *cp = buf;
 	char sep = 0;
 	int group, entry;
+#warning layer TODO: revise this loop to save only what the original code saved
 	for (group = 0; group < pcb_max_group; group++)
-		if (PCB->LayerGroups.Number[group]) {
+		if (PCB->LayerGroups.grp[group].len) {
+			unsigned int gflg = pcb_layergrp_flags(group);
+
+			if (gflg & PCB_LYT_SILK) /* silk is hacked in asusming there's a top and bottom copper */
+				continue;
+
 			if (sep)
 				*cp++ = ':';
 			sep = 1;
-			for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) {
-				int layer = PCB->LayerGroups.Entries[group][entry];
-				if (layer == pcb_component_silk_layer) {
-					*cp++ = 'c';
-				}
-				else if (layer == pcb_solder_silk_layer) {
-					*cp++ = 's';
-				}
-				else {
-					sprintf(cp, "%d", layer + 1);
-					while (*++cp);
-				}
-				if (entry != PCB->LayerGroups.Number[group] - 1)
+			for (entry = 0; entry < PCB->LayerGroups.grp[group].len; entry++) {
+				pcb_layer_id_t layer = PCB->LayerGroups.grp[group].lid[entry];
+				unsigned int lflg = pcb_layer_flags(layer);
+
+
+				sprintf(cp, "%ld", layer + 1);
+				while (*++cp);
+
+				if (entry != PCB->LayerGroups.grp[group].len - 1)
 					*cp++ = ',';
 			}
+
+			if ((gflg & PCB_LYT_COPPER) && (gflg & PCB_LYT_TOP)) {
+				*cp++ = ',';
+				*cp++ = 'c';
+			}
+			else if ((gflg & PCB_LYT_COPPER) && (gflg & PCB_LYT_BOTTOM)) {
+				*cp++ = ',';
+				*cp++ = 's';
+			}
 		}
 	*cp++ = 0;
 	return buf;
@@ -540,7 +551,7 @@ int io_pcb_WriteBuffer(pcb_plug_io_t *ctx, FILE * FP, pcb_buffer_t *buff)
 	pcb_printf_slot[0] = ((io_pcb_ctx_t *)(ctx->plugin_data))->write_coord_fmt;
 	WriteViaData(FP, buff->Data);
 	io_pcb_WriteElementData(ctx, FP, buff->Data);
-	for (i = 0; i < pcb_max_copper_layer + 2; i++)
+	for (i = 0; i < pcb_max_layer; i++)
 		WriteLayerData(FP, i, &(buff->Data->Layer[i]));
 	return (0);
 }
@@ -562,7 +573,7 @@ int io_pcb_WritePCB(pcb_plug_io_t *ctx, FILE * FP, const char *old_filename, con
 	WriteViaData(FP, PCB->Data);
 	io_pcb_WriteElementData(ctx, FP, PCB->Data);
 	WritePCBRatData(FP);
-	for (i = 0; i < pcb_max_copper_layer + 2; i++)
+	for (i = 0; i < pcb_max_layer; i++)
 		WriteLayerData(FP, i, &(PCB->Data->Layer[i]));
 	WritePCBNetlistData(FP);
 	WritePCBNetlistPatchData(FP);
diff --git a/src_plugins/io_pcb/parse_y.c b/src_plugins/io_pcb/parse_y.c
index 2e3fbd5..67ec3ce 100644
--- a/src_plugins/io_pcb/parse_y.c
+++ b/src_plugins/io_pcb/parse_y.c
@@ -2216,7 +2216,7 @@ yyreduce:
   case 73:
 #line 869 "parse_y.y" /* yacc.c:1646  */
     {
-				if ((yyvsp[-4].integer) <= 0 || (yyvsp[-4].integer) > PCB_MAX_LAYER + 2)
+				if ((yyvsp[-4].integer) <= 0 || (yyvsp[-4].integer) > PCB_MAX_LAYER)
 				{
 					yyerror("Layernumber out of range");
 					YYABORT;
@@ -2233,8 +2233,8 @@ yyreduce:
 					free((char*)Layer->Name);
 				Layer->Name = (yyvsp[-3].string);   /* shouldn't this be strdup()'ed ? */
 				LayerFlag[(yyvsp[-4].integer)-1] = pcb_true;
-				if (yyData->LayerN + 2 < (yyvsp[-4].integer))
-				  yyData->LayerN = (yyvsp[-4].integer) - 2;
+				if (yyData->LayerN < (yyvsp[-4].integer))
+				  yyData->LayerN = (yyvsp[-4].integer);
 				if ((yyvsp[-2].string) != NULL)
 					free((yyvsp[-2].string));
 			}
@@ -2328,7 +2328,7 @@ yyreduce:
 				if ((yyvsp[-1].integer) & PCB_FLAG_ONSILK)
 				{
 					pcb_layer_t *lay = &yyData->Layer[yyData->LayerN +
-						(((yyvsp[-1].integer) & PCB_FLAG_ONSOLDER) ? PCB_SOLDER_SIDE : PCB_COMPONENT_SIDE)];
+						(((yyvsp[-1].integer) & PCB_FLAG_ONSOLDER) ? PCB_SOLDER_SIDE : PCB_COMPONENT_SIDE) - 2];
 
 					pcb_text_new(lay ,yyFont, OU ((yyvsp[-6].measure)), OU ((yyvsp[-5].measure)), (yyvsp[-4].number), (yyvsp[-3].number), (yyvsp[-2].string),
 						      pcb_flag_old((yyvsp[-1].integer)));
@@ -2354,7 +2354,7 @@ yyreduce:
 				if ((yyvsp[-1].flagtype).f & PCB_FLAG_ONSILK)
 				{
 					pcb_layer_t *lay = &yyData->Layer[yyData->LayerN +
-						(((yyvsp[-1].flagtype).f & PCB_FLAG_ONSOLDER) ? PCB_SOLDER_SIDE : PCB_COMPONENT_SIDE)];
+						(((yyvsp[-1].flagtype).f & PCB_FLAG_ONSOLDER) ? PCB_SOLDER_SIDE : PCB_COMPONENT_SIDE) - 2];
 
 					pcb_text_new(lay, yyFont, NU ((yyvsp[-6].measure)), NU ((yyvsp[-5].measure)), (yyvsp[-4].number), (yyvsp[-3].number), (yyvsp[-2].string), (yyvsp[-1].flagtype));
 				}
diff --git a/src_plugins/io_pcb/parse_y.y b/src_plugins/io_pcb/parse_y.y
index 393163b..ac3f80a 100644
--- a/src_plugins/io_pcb/parse_y.y
+++ b/src_plugins/io_pcb/parse_y.y
@@ -867,7 +867,7 @@ layer
 			/* name */
 		: T_LAYER '(' INTEGER STRING opt_string ')' '('
 			{
-				if ($3 <= 0 || $3 > PCB_MAX_LAYER + 2)
+				if ($3 <= 0 || $3 > PCB_MAX_LAYER)
 				{
 					yyerror("Layernumber out of range");
 					YYABORT;
@@ -884,8 +884,8 @@ layer
 					free((char*)Layer->Name);
 				Layer->Name = $4;   /* shouldn't this be strdup()'ed ? */
 				LayerFlag[$3-1] = pcb_true;
-				if (yyData->LayerN + 2 < $3)
-				  yyData->LayerN = $3 - 2;
+				if (yyData->LayerN < $3)
+				  yyData->LayerN = $3;
 				if ($5 != NULL)
 					free($5);
 			}
@@ -1085,7 +1085,7 @@ text_newformat
 				if ($8 & PCB_FLAG_ONSILK)
 				{
 					pcb_layer_t *lay = &yyData->Layer[yyData->LayerN +
-						(($8 & PCB_FLAG_ONSOLDER) ? PCB_SOLDER_SIDE : PCB_COMPONENT_SIDE)];
+						(($8 & PCB_FLAG_ONSOLDER) ? PCB_SOLDER_SIDE : PCB_COMPONENT_SIDE) - 2];
 
 					pcb_text_new(lay ,yyFont, OU ($3), OU ($4), $5, $6, $7,
 						      pcb_flag_old($8));
@@ -1110,7 +1110,7 @@ text_hi_format
 				if ($8.f & PCB_FLAG_ONSILK)
 				{
 					pcb_layer_t *lay = &yyData->Layer[yyData->LayerN +
-						(($8.f & PCB_FLAG_ONSOLDER) ? PCB_SOLDER_SIDE : PCB_COMPONENT_SIDE)];
+						(($8.f & PCB_FLAG_ONSOLDER) ? PCB_SOLDER_SIDE : PCB_COMPONENT_SIDE) - 2];
 
 					pcb_text_new(lay, yyFont, NU ($3), NU ($4), $5, $6, $7, $8);
 				}
diff --git a/src_plugins/lib_gtk_common/HACKING b/src_plugins/lib_gtk_common/HACKING
new file mode 100644
index 0000000..7863104
--- /dev/null
+++ b/src_plugins/lib_gtk_common/HACKING
@@ -0,0 +1,11 @@
+act_*: actions
+util_*: generic, non-UI related utilities
+ui_*: ui logic related, but gtk-free utilities
+wt_*: custom widgets, cell renderers for gtk - must work in both gtk2 and gtk3
+dlg_*: dialog boxes, preferrably one per file
+bu_*: builders, building a part of a bigger gui portion
+in_*: input handling (gtk-specific)
+win_*: windowing related utils
+
+Any of these may depend on glib.
+
diff --git a/src_plugins/lib_gtk_common/Makefile b/src_plugins/lib_gtk_common/Makefile
new file mode 100644
index 0000000..ead9343
--- /dev/null
+++ b/src_plugins/lib_gtk_common/Makefile
@@ -0,0 +1,5 @@
+all:
+	cd ../../src && $(MAKE) mod_lib_gtk_common
+
+clean:
+	rm *.o *.so 2>/dev/null ; true
diff --git a/src_plugins/lib_gtk_common/Plug.tmpasm b/src_plugins/lib_gtk_common/Plug.tmpasm
new file mode 100644
index 0000000..e67e002
--- /dev/null
+++ b/src_plugins/lib_gtk_common/Plug.tmpasm
@@ -0,0 +1,67 @@
+put /local/pcb/mod {lib_gtk_common}
+put /local/pcb/mod/OBJS [@
+  $(PLUGDIR)/lib_gtk_common/lib_gtk_common.o
+@]
+
+put /local/pcb/mod/OBJS_C99 [@
+  $(PLUGDIR)/lib_gtk_common/act_fileio.o
+  $(PLUGDIR)/lib_gtk_common/act_print.o
+  $(PLUGDIR)/lib_gtk_common/bu_box.o
+  $(PLUGDIR)/lib_gtk_common/bu_check_button.o
+  $(PLUGDIR)/lib_gtk_common/bu_cursor_pos.o
+  $(PLUGDIR)/lib_gtk_common/bu_dwg_tooltip.o
+  $(PLUGDIR)/lib_gtk_common/bu_entry.o
+  $(PLUGDIR)/lib_gtk_common/bu_notebook.o
+  $(PLUGDIR)/lib_gtk_common/bu_spin_button.o
+  $(PLUGDIR)/lib_gtk_common/bu_status_line.o
+  $(PLUGDIR)/lib_gtk_common/bu_text_view.o
+  $(PLUGDIR)/lib_gtk_common/dlg_about.o
+  $(PLUGDIR)/lib_gtk_common/dlg_attribute.o
+  $(PLUGDIR)/lib_gtk_common/dlg_confirm.o
+  $(PLUGDIR)/lib_gtk_common/dlg_export.o
+  $(PLUGDIR)/lib_gtk_common/dlg_file_chooser.o
+  $(PLUGDIR)/lib_gtk_common/dlg_input.o
+  $(PLUGDIR)/lib_gtk_common/dlg_message.o
+  $(PLUGDIR)/lib_gtk_common/dlg_pinout.o
+  $(PLUGDIR)/lib_gtk_common/dlg_print.o
+  $(PLUGDIR)/lib_gtk_common/dlg_progress.o
+  $(PLUGDIR)/lib_gtk_common/dlg_propedit.o
+  $(PLUGDIR)/lib_gtk_common/dlg_report.o
+  $(PLUGDIR)/lib_gtk_common/dlg_route_style.o
+  $(PLUGDIR)/lib_gtk_common/dlg_search.o
+  $(PLUGDIR)/lib_gtk_common/in_keyboard.o
+  $(PLUGDIR)/lib_gtk_common/in_mouse.o
+  $(PLUGDIR)/lib_gtk_common/menu_lht.o
+  $(PLUGDIR)/lib_gtk_common/ui_zoompan.o
+  $(PLUGDIR)/lib_gtk_common/util_block_hook.o
+  $(PLUGDIR)/lib_gtk_common/util_str.o
+  $(PLUGDIR)/lib_gtk_common/util_timer.o
+  $(PLUGDIR)/lib_gtk_common/util_watch.o
+  $(PLUGDIR)/lib_gtk_common/win_place.o
+  $(PLUGDIR)/lib_gtk_common/wt_coord_entry.o
+  $(PLUGDIR)/lib_gtk_common/wt_layer_selector.o
+  $(PLUGDIR)/lib_gtk_common/wt_layer_selector_cr.o
+  $(PLUGDIR)/lib_gtk_common/wt_preview.o
+  $(PLUGDIR)/lib_gtk_common/wt_route_style.o
+@]
+
+
+switch /local/pcb/lib_gtk_common/controls
+	case {buildin}   include /local/pcb/tmpasm/buildin; end;
+	case {plugin}    include /local/pcb/tmpasm/plugin; end;
+	case {disable}   include /local/pcb/tmpasm/disable; end;
+end
+
+switch /local/pcb/lib_gtk_common/controls
+	case {disable} end;
+	default
+		put /local/pcb/mod/CLEANFILES { $(PLUGDIR)/lib_gtk_common/menu_lht.c }
+		append /local/pcb/RULES [@
+### gtk menu embed
+$(PLUGDIR)/lib_gtk_common/menu_lht.c: pcb-menu-gtk.lht
+	$(CQUOTE) -n hid_gtk_menu_default <pcb-menu-gtk.lht >$(PLUGDIR)/lib_gtk_common/menu_lht.c
+@]
+	end
+end
+
+
diff --git a/src_plugins/lib_gtk_common/README b/src_plugins/lib_gtk_common/README
new file mode 100644
index 0000000..4f480ae
--- /dev/null
+++ b/src_plugins/lib_gtk_common/README
@@ -0,0 +1,6 @@
+hid_gtk* common code (regardless of gtk version or drawing mechanism: for 
+both gtk2 and gtk3 and for both sw rendering and gl)
+
+#state: works
+#default: disabled
+#implements: (lib)
diff --git a/src_plugins/lib_gtk_common/act_fileio.c b/src_plugins/lib_gtk_common/act_fileio.c
new file mode 100644
index 0000000..a06dd58
--- /dev/null
+++ b/src_plugins/lib_gtk_common/act_fileio.c
@@ -0,0 +1,258 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <glib.h>
+#include <unistd.h>
+
+#include "act_fileio.h"
+
+#include "hid_actions.h"
+#include "conf_core.h"
+#include "compat_nls.h"
+#include "plug_footprint.h"
+#include "compat_misc.h"
+#include "conf_core.h"
+#include "board.h"
+#include "data.h"
+
+#include "dlg_file_chooser.h"
+
+
+
+
+static char *dup_cwd()
+{
+#if defined (PATH_MAX)
+	char tmp[PATH_MAX + 1];
+#else
+	char tmp[8193];
+#endif
+	return pcb_strdup(getcwd(tmp, sizeof(tmp)));
+}
+
+int pcb_gtk_act_load(GtkWidget *top_window, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	const char *function;
+	char *name = NULL;
+
+	static gchar *current_element_dir = NULL;
+	static gchar *current_layout_dir = NULL;
+	static gchar *current_netlist_dir = NULL;
+
+	if (!current_element_dir)
+		current_element_dir = dup_cwd();
+	if (!current_layout_dir)
+		current_layout_dir = dup_cwd();
+	if (!current_netlist_dir)
+		current_netlist_dir = dup_cwd();
+
+	/* we've been given the file name */
+	if (argc > 1)
+		return pcb_hid_actionv("LoadFrom", argc, argv);
+
+	function = argc ? argv[0] : "Layout";
+
+	if (pcb_strcasecmp(function, "Netlist") == 0) {
+		name = ghid_dialog_file_select_open(top_window, _("Load netlist file"), &current_netlist_dir, conf_core.rc.file_path);
+	}
+	else if (pcb_strcasecmp(function, "ElementToBuffer") == 0) {
+		gchar *path = (gchar *) pcb_fp_default_search_path();
+		name = ghid_dialog_file_select_open(top_window, _("Load element to buffer"), &current_element_dir, path);
+	}
+	else if (pcb_strcasecmp(function, "LayoutToBuffer") == 0) {
+		name = ghid_dialog_file_select_open(top_window, _("Load layout file to buffer"), &current_layout_dir, conf_core.rc.file_path);
+	}
+	else if (pcb_strcasecmp(function, "Layout") == 0) {
+		name = ghid_dialog_file_select_open(top_window, _("Load layout file"), &current_layout_dir, conf_core.rc.file_path);
+	}
+
+	if (name) {
+		if (conf_core.rc.verbose)
+			fprintf(stderr, "Load:  Calling LoadFrom(%s, %s)\n", function, name);
+		pcb_hid_actionl("LoadFrom", function, name, NULL);
+		g_free(name);
+	}
+
+	return 0;
+}
+
+const char pcb_gtk_acts_save[] = "Save()\n" "Save(Layout|LayoutAs)\n" "Save(AllConnections|AllUnusedPins|ElementConnections)\n" "Save(PasteBuffer)";
+const char pcb_gtk_acth_save[] = N_("Save layout and/or element data to a user-selected file.");
+
+/* %start-doc actions Save
+
+This action is a GUI front-end to the core's @code{SaveTo} action
+(@pxref{SaveTo Action}).  If you happen to pass a filename, like
+ at code{SaveTo}, then @code{SaveTo} is called directly.  Else, the
+user is prompted for a filename to save, and then @code{SaveTo} is
+called with that filename.
+
+%end-doc */
+
+int pcb_gtk_act_save(GtkWidget *top_window, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	const char *function;
+	char *name, *name_in = NULL;
+	const char *prompt;
+	pcb_io_formats_t avail;
+	const char **formats_param = NULL, **extensions_param = NULL;
+	int fmt, *fmt_param = NULL;
+
+	static gchar *current_dir = NULL;
+
+	if (!current_dir)
+		current_dir = dup_cwd();
+
+	if (argc > 1)
+		return pcb_hid_actionv("SaveTo", argc, argv);
+
+	function = argc ? argv[0] : "Layout";
+
+	if (pcb_strcasecmp(function, "Layout") == 0)
+		if (PCB->Filename)
+			return pcb_hid_actionl("SaveTo", "Layout", PCB->Filename, NULL);
+
+	if (pcb_strcasecmp(function, "PasteBuffer") == 0) {
+		int num_fmts, n;
+		prompt = _("Save element as");
+		num_fmts = pcb_io_list(&avail, PCB_IOT_BUFFER, 1, 1, PCB_IOL_EXT_FP);
+		if (num_fmts > 0) {
+			formats_param = (const char **) avail.digest;
+			extensions_param = (const char **) avail.extension;
+			fmt_param = &fmt;
+			fmt = 0;
+			for (n = 0; n < num_fmts; n++) {
+				if (strstr(avail.plug[n]->description, "mainline") != NULL) {
+					fmt = n;
+					name_in = pcb_concat("unnamed.fp", NULL);
+				}
+			}
+		}
+		else {
+			pcb_message(PCB_MSG_ERROR, "Error: no IO plugin avaialble for saving a buffer.");
+			return -1;
+		}
+	}
+	else {
+		int num_fmts, n;
+		prompt = _("Save layout as");
+		num_fmts = pcb_io_list(&avail, PCB_IOT_PCB, 1, 1, PCB_IOL_EXT_BOARD);
+		if (num_fmts > 0) {
+			formats_param = (const char **) avail.digest;
+			extensions_param = (const char **) avail.extension;
+			fmt_param = &fmt;
+			fmt = 0;
+			if (PCB->Data->loader != NULL) {
+				for (n = 0; n < num_fmts; n++) {
+					if (avail.plug[n] == PCB->Data->loader) {
+						fmt = n;
+						break;
+					}
+				}
+			}
+		}
+		else {
+			pcb_message(PCB_MSG_ERROR, "Error: no IO plugin avaialble for saving a buffer.");
+			return -1;
+		}
+	}
+
+	{															/* invent an input file name if needed and run the save dialog to get an output file name */
+		if (name_in == NULL) {
+			if (PCB->Filename == NULL)
+				name_in = pcb_concat("unnamed", extensions_param[fmt], NULL);
+			else
+				name_in = pcb_strdup(PCB->Filename);
+		}
+		name = ghid_dialog_file_select_save(top_window, prompt, &current_dir, name_in, conf_core.rc.file_path, formats_param, extensions_param, fmt_param);
+		free(name_in);
+	}
+
+	if (name) {
+		if (conf_core.rc.verbose)
+			fprintf(stderr, "Save:  Calling SaveTo(%s, %s)\n", function, name);
+
+		if (pcb_strcasecmp(function, "PasteBuffer") == 0) {
+			pcb_hid_actionl("PasteBuffer", "Save", name, avail.plug[fmt]->description, "1", NULL);
+
+		}
+		else {
+			const char *sfmt = NULL;
+			/*
+			 * if we got this far and the function is Layout, then
+			 * we really needed it to be a LayoutAs.  Otherwise
+			 * ActionSaveTo() will ignore the new file name we
+			 * just obtained.
+			 */
+			if (fmt_param != NULL)
+				sfmt = avail.plug[fmt]->description;
+			if (pcb_strcasecmp(function, "Layout") == 0)
+				pcb_hid_actionl("SaveTo", "LayoutAs", name, sfmt, NULL);
+			else
+				pcb_hid_actionl("SaveTo", function, name, sfmt, NULL);
+		}
+		g_free(name);
+		pcb_io_list_free(&avail);
+	}
+	else {
+		pcb_io_list_free(&avail);
+		return 1;
+	}
+
+	return 0;
+}
+
+const char pcb_gtk_acts_importgui[] = "ImportGUI()";
+const char pcb_gtk_acth_importgui[] = N_("Asks user which schematics to import into PCB.\n");
+int pcb_gtk_act_importgui(GtkWidget *top_window, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	char *name = NULL;
+	static gchar *current_layout_dir = NULL;
+	static int I_am_recursing = 0;
+	int rv;
+
+	if (!current_layout_dir)
+		current_layout_dir = dup_cwd();
+
+	if (I_am_recursing)
+		return 1;
+
+
+	name = ghid_dialog_file_select_open(top_window, _("Load schematics"), &current_layout_dir, conf_core.rc.file_path);
+
+#ifdef DEBUG
+	printf("File selected = %s\n", name);
+#endif
+
+	pcb_attrib_put(PCB, "import::src0", name);
+	free(name);
+
+	I_am_recursing = 1;
+	rv = pcb_hid_action("Import");
+	I_am_recursing = 0;
+
+	return rv;
+}
diff --git a/src_plugins/lib_gtk_common/act_fileio.h b/src_plugins/lib_gtk_common/act_fileio.h
new file mode 100644
index 0000000..fcd77b0
--- /dev/null
+++ b/src_plugins/lib_gtk_common/act_fileio.h
@@ -0,0 +1,12 @@
+#include <gtk/gtk.h>
+#include "unit.h"
+
+int pcb_gtk_act_load(GtkWidget *top_window, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
+
+extern const char pcb_gtk_acts_save[];
+extern const char pcb_gtk_acth_save[];
+int pcb_gtk_act_save(GtkWidget *top_window, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
+
+extern const char pcb_gtk_acts_importgui[];
+extern const char pcb_gtk_acth_importgui[];
+int pcb_gtk_act_importgui(GtkWidget *top_window, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
diff --git a/src_plugins/lib_gtk_common/act_print.c b/src_plugins/lib_gtk_common/act_print.c
new file mode 100644
index 0000000..b4f2104
--- /dev/null
+++ b/src_plugins/lib_gtk_common/act_print.c
@@ -0,0 +1,99 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include "act_print.h"
+
+#include "board.h"
+#include "hid.h"
+#include "hid_init.h"
+#include "hid_attrib.h"
+#include "data.h"
+#include "compat_nls.h"
+
+#include "dlg_print.h"
+
+const char pcb_gtk_acts_print[] = "Print()";
+const char pcb_gtk_acth_print[] = N_("Print the layout.");
+int pcb_gtk_act_print(GtkWidget *top_window, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	pcb_hid_t **hids;
+	int i;
+	pcb_hid_t *printer = NULL;
+
+	hids = pcb_hid_enumerate();
+	for (i = 0; hids[i]; i++) {
+		if (hids[i]->printer)
+			printer = hids[i];
+	}
+
+	if (printer == NULL) {
+		pcb_gui->log(_("Can't find a suitable printer HID"));
+		return -1;
+	}
+
+	/* check if layout is empty */
+	if (!pcb_data_is_empty(PCB->Data)) {
+		ghid_dialog_print(printer, NULL, top_window);
+	}
+	else
+		pcb_gui->log(_("Can't print empty layout"));
+
+	return 0;
+}
+
+static pcb_hid_attribute_t printer_calibrate_attrs[] = {
+	{N_("Enter Values here:"), "",
+	 HID_Label, 0, 0, {0, 0, 0}, 0, 0},
+	{N_("x-calibration"), N_("X scale for calibrating your printer"),
+	 HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0},
+	{N_("y-calibration"), N_("Y scale for calibrating your printer"),
+	 HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0}
+};
+
+static pcb_hid_attr_val_t printer_calibrate_values[3];
+
+const char pcb_gtk_acts_printcalibrate[] = "PrintCalibrate()";
+const char pcb_gtk_acth_printcalibrate[] = N_("Calibrate the printer.");
+
+/* %start-doc actions PrintCalibrate
+
+This will print a calibration page, which you would measure and type
+the measurements in, so that future printouts will be more precise.
+
+%end-doc */
+
+int pcb_gtk_act_printcalibrate(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	pcb_hid_t *printer = pcb_hid_find_printer();
+	printer->calibrate(0.0, 0.0);
+
+	if (pcb_gui->attribute_dialog(printer_calibrate_attrs, 3,
+																printer_calibrate_values,
+																_("Printer Calibration Values"), _("Enter calibration values for your printer")))
+		return 1;
+	printer->calibrate(printer_calibrate_values[1].real_value, printer_calibrate_values[2].real_value);
+	return 0;
+}
diff --git a/src_plugins/lib_gtk_common/act_print.h b/src_plugins/lib_gtk_common/act_print.h
new file mode 100644
index 0000000..1b37ca2
--- /dev/null
+++ b/src_plugins/lib_gtk_common/act_print.h
@@ -0,0 +1,9 @@
+#include <gtk/gtk.h>
+extern const char pcb_gtk_acts_print[];
+extern const char pcb_gtk_acth_print[];
+int pcb_gtk_act_print(GtkWidget *top_window, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
+
+extern const char pcb_gtk_acts_printcalibrate[];
+extern const char pcb_gtk_acth_printcalibrate[];
+int pcb_gtk_act_printcalibrate(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
+
diff --git a/src_plugins/lib_gtk_common/bu_box.c b/src_plugins/lib_gtk_common/bu_box.c
new file mode 100644
index 0000000..2ad373d
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_box.c
@@ -0,0 +1,140 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* Originally from gui-utils.c, was written by Bill Wilson and the functions
+ * here are Copyright (C) 2004 by Bill Wilson.  Those functions were utility
+ * functions which are taken from my other GPL'd projects gkrellm and
+ * gstocks and are copied here for the Gtk PCB port.
+ */
+
+#include "config.h"
+
+#include "bu_box.h"
+#include "compat.h"
+
+/*TODO: The 2 following functions could be merged if an additional 
+ *  gboolean pack_start   parameter is added */
+GtkWidget *ghid_framed_vbox(GtkWidget * box, gchar * label, gint frame_border_width,
+														gboolean frame_expand, gint vbox_pad, gint vbox_border_width)
+{
+	GtkWidget *frame;
+	GtkWidget *vbox;
+
+	frame = gtk_frame_new(label);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), frame_border_width);
+	gtk_box_pack_start(GTK_BOX(box), frame, frame_expand, frame_expand, 0);
+	vbox = gtkc_vbox_new(FALSE, vbox_pad);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), vbox_border_width);
+	gtk_container_add(GTK_CONTAINER(frame), vbox);
+	return vbox;
+}
+
+GtkWidget *ghid_framed_vbox_end(GtkWidget * box, gchar * label, gint frame_border_width,
+																gboolean frame_expand, gint vbox_pad, gint vbox_border_width)
+{
+	GtkWidget *frame;
+	GtkWidget *vbox;
+
+	frame = gtk_frame_new(label);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), frame_border_width);
+	gtk_box_pack_end(GTK_BOX(box), frame, frame_expand, frame_expand, 0);
+	vbox = gtkc_vbox_new(FALSE, vbox_pad);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), vbox_border_width);
+	gtk_container_add(GTK_CONTAINER(frame), vbox);
+	return vbox;
+}
+
+GtkWidget *ghid_category_vbox(GtkWidget * box, const gchar * category_header,
+															gint header_pad, gint box_pad, gboolean pack_start, gboolean bottom_pad)
+{
+	GtkWidget *vbox, *vbox1, *hbox, *label;
+	gchar *s;
+
+	vbox = gtkc_vbox_new(FALSE, 0);
+	if (pack_start)
+		gtk_box_pack_start(GTK_BOX(box), vbox, FALSE, FALSE, 0);
+	else
+		gtk_box_pack_end(GTK_BOX(box), vbox, FALSE, FALSE, 0);
+
+	if (category_header) {
+		label = gtk_label_new(NULL);
+		s = g_strconcat("<span weight=\"bold\">", category_header, "</span>", NULL);
+		gtk_label_set_markup(GTK_LABEL(label), s);
+		/*TODO: Deprecated in GTK3. Use gtk_widget_set_[h|v]align () functions ? */
+		gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, header_pad);
+		g_free(s);
+	}
+
+	hbox = gtkc_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	label = gtk_label_new("     ");
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	vbox1 = gtkc_vbox_new(FALSE, box_pad);
+	gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0);
+
+	if (bottom_pad) {
+		label = gtk_label_new("");
+		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+	}
+	return vbox1;
+}
+
+GtkWidget *ghid_scrolled_vbox(GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy)
+{
+	GtkWidget *scrolled, *vbox;
+
+	scrolled = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), h_policy, v_policy);
+	gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0);
+	vbox = gtkc_vbox_new(FALSE, 0);
+	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), vbox);
+	if (scr)
+		*scr = scrolled;
+	return vbox;
+}
+
+GtkTreeSelection *ghid_scrolled_selection(GtkTreeView * treeview, GtkWidget * box,
+																					GtkSelectionMode s_mode,
+																					GtkPolicyType h_policy, GtkPolicyType v_policy,
+																					void (*func_cb) (GtkTreeSelection *, gpointer), gpointer data)
+{
+	GtkTreeSelection *selection;
+	GtkWidget *scrolled;
+
+	if (!box || !treeview)
+		return NULL;
+
+	scrolled = gtk_scrolled_window_new(NULL, NULL);
+	gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0);
+	gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(treeview));
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), h_policy, v_policy);
+	selection = gtk_tree_view_get_selection(treeview);
+	gtk_tree_selection_set_mode(selection, s_mode);
+	if (func_cb)
+		g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(func_cb), data);
+	return selection;
+}
diff --git a/src_plugins/lib_gtk_common/bu_box.h b/src_plugins/lib_gtk_common/bu_box.h
new file mode 100644
index 0000000..862b799
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_box.h
@@ -0,0 +1,23 @@
+#include <gtk/gtk.h>
+
+/** Builds a vertical box, surrounded by a labeled frame
+    @param frame_border_width: border around outside of frame.
+    @param vbox_pad: pad between widgets to be packed in returned vbox.
+    @param vbox_border_width: border between returned vbox and frame.
+*/
+GtkWidget *ghid_framed_vbox(GtkWidget * box, gchar * label, gint frame_border_width,
+														gboolean frame_expand, gint vbox_pad, gint vbox_border_width);
+
+/** Same as ghid_framed_vbox(), but packing at the end */
+GtkWidget *ghid_framed_vbox_end(GtkWidget * box, gchar * label, gint frame_border_width,
+																gboolean frame_expand, gint vbox_pad, gint vbox_border_width);
+
+GtkWidget *ghid_category_vbox(GtkWidget * box, const gchar * category_header,
+															gint header_pad, gint box_pad, gboolean pack_start, gboolean bottom_pad);
+
+GtkWidget *ghid_scrolled_vbox(GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy);
+
+GtkTreeSelection *ghid_scrolled_selection(GtkTreeView * treeview, GtkWidget * box,
+																					GtkSelectionMode s_mode,
+																					GtkPolicyType h_policy, GtkPolicyType v_policy,
+																					void (*func_cb) (GtkTreeSelection *, gpointer), gpointer data);
diff --git a/src_plugins/lib_gtk_common/bu_check_button.c b/src_plugins/lib_gtk_common/bu_check_button.c
new file mode 100644
index 0000000..856d8b2
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_check_button.c
@@ -0,0 +1,57 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This code was originally written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+
+#include "bu_check_button.h"
+
+void ghid_check_button_connected(GtkWidget * box,
+																 GtkWidget ** button,
+																 gboolean active,
+																 gboolean pack_start,
+																 gboolean expand,
+																 gboolean fill,
+																 gint pad, void (*cb_func) (GtkToggleButton *, gpointer), gpointer data, const gchar * string)
+{
+	GtkWidget *b;
+
+	if (string != NULL)
+		b = gtk_check_button_new_with_label(string);
+	else
+		b = gtk_check_button_new();
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b), active);
+	if (box && pack_start)
+		gtk_box_pack_start(GTK_BOX(box), b, expand, fill, pad);
+	else if (box && !pack_start)
+		gtk_box_pack_end(GTK_BOX(box), b, expand, fill, pad);
+
+	if (cb_func)
+		g_signal_connect(b, "clicked", G_CALLBACK(cb_func), data);
+	if (button)
+		*button = b;
+}
diff --git a/src_plugins/lib_gtk_common/bu_check_button.h b/src_plugins/lib_gtk_common/bu_check_button.h
new file mode 100644
index 0000000..86024bb
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_check_button.h
@@ -0,0 +1,10 @@
+#include <gtk/gtk.h>
+
+/** Builds a new gtk_check_button */
+void ghid_check_button_connected(GtkWidget * box,
+																 GtkWidget ** button,
+																 gboolean active,
+																 gboolean pack_start,
+																 gboolean expand,
+																 gboolean fill,
+																 gint pad, void (*cb_func) (GtkToggleButton *, gpointer), gpointer data, const gchar * string);
diff --git a/src_plugins/lib_gtk_common/bu_cursor_pos.c b/src_plugins/lib_gtk_common/bu_cursor_pos.c
new file mode 100644
index 0000000..ade9b92
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_cursor_pos.c
@@ -0,0 +1,147 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "config.h"
+#include "bu_cursor_pos.h"
+#include "conf_core.h"
+#include "hid_actions.h"
+#include "crosshair.h"
+#include "misc_util.h"
+#include "compat_nls.h"
+#include "math_helper.h"
+
+static void grid_units_button_cb(GtkWidget * widget, gpointer data)
+{
+	/* Button only toggles between mm and mil */
+	if (conf_core.editor.grid_unit == get_unit_struct("mm"))
+		pcb_hid_actionl("SetUnits", "mil", NULL);
+	else
+		pcb_hid_actionl("SetUnits", "mm", NULL);
+}
+
+/*
+ * The two following callbacks are used to keep the absolute
+ * and relative cursor labels from growing and shrinking as you
+ * move the cursor around.
+ */
+static void absolute_label_size_req_cb(GtkWidget * widget, GtkRequisition * req, gpointer data)
+{
+
+	static gint w = 0;
+	if (req->width > w)
+		w = req->width;
+	else
+		req->width = w;
+}
+
+static void relative_label_size_req_cb(GtkWidget * widget, GtkRequisition * req, gpointer data)
+{
+
+	static gint w = 0;
+	if (req->width > w)
+		w = req->width;
+	else
+		req->width = w;
+}
+
+
+void make_cursor_position_labels(GtkWidget *hbox, pcb_gtk_cursor_pos_t *cps)
+{
+	GtkWidget *frame, *label;
+
+	/* The grid units button next to the cursor position labels.
+	 */
+	cps->grid_units_button = gtk_button_new();
+	label = gtk_label_new("");
+	gtk_label_set_markup(GTK_LABEL(label), conf_core.editor.grid_unit->in_suffix);
+	cps->grid_units_label = label;
+	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+	gtk_container_add(GTK_CONTAINER(cps->grid_units_button), label);
+	gtk_box_pack_end(GTK_BOX(hbox), cps->grid_units_button, FALSE, TRUE, 0);
+	g_signal_connect(cps->grid_units_button, "clicked", G_CALLBACK(grid_units_button_cb), NULL);
+
+	/* The absolute cursor position label
+	 */
+	frame = gtk_frame_new(NULL);
+	gtk_box_pack_end(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
+	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
+
+	label = gtk_label_new("");
+	gtk_container_add(GTK_CONTAINER(frame), label);
+	cps->cursor_position_absolute_label = label;
+	g_signal_connect(G_OBJECT(label), "size-request", G_CALLBACK(absolute_label_size_req_cb), NULL);
+
+
+	/* The relative cursor position label
+	 */
+	frame = gtk_frame_new(NULL);
+	gtk_box_pack_end(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
+	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
+	label = gtk_label_new(" __.__  __.__ ");
+	gtk_container_add(GTK_CONTAINER(frame), label);
+	cps->cursor_position_relative_label = label;
+	g_signal_connect(G_OBJECT(label), "size-request", G_CALLBACK(relative_label_size_req_cb), NULL);
+}
+
+void ghid_cursor_position_label_set_text(pcb_gtk_cursor_pos_t *cps, gchar * text)
+{
+	if (cps->cursor_position_absolute_label != NULL)
+		gtk_label_set_markup(GTK_LABEL(cps->cursor_position_absolute_label), text ? text : "");
+}
+
+void ghid_cursor_position_relative_label_set_text(pcb_gtk_cursor_pos_t *cps, gchar * text)
+{
+	if (cps->cursor_position_relative_label != NULL)
+		gtk_label_set_markup(GTK_LABEL(cps->cursor_position_relative_label), text ? text : "");
+}
+
+void ghid_set_cursor_position_labels(pcb_gtk_cursor_pos_t *cps, int compact_vertical)
+{
+	char *text, sep = ' ';
+	if (compact_vertical)
+		sep = '\n';
+
+	if (pcb_marked.status) {
+		pcb_coord_t dx = pcb_crosshair.X - pcb_marked.X;
+		pcb_coord_t dy = pcb_crosshair.Y - pcb_marked.Y;
+		pcb_coord_t r = pcb_distance(pcb_crosshair.X, pcb_crosshair.Y, pcb_marked.X, pcb_marked.Y);
+		double a = atan2(dy, dx) * PCB_RAD_TO_DEG;
+
+
+		text = pcb_strdup_printf(_("%m+r %-mS;%cphi %-.1f;%c%-mS %-mS"), conf_core.editor.grid_unit->allow, r, sep, a, sep, dx, dy);
+		ghid_cursor_position_relative_label_set_text(cps, text);
+		free(text);
+	}
+	else {
+		char text[64];
+		sprintf(text, _("r __.__;%cphi __._;%c__.__ __.__"), sep, sep);
+		ghid_cursor_position_relative_label_set_text(cps, text);
+	}
+
+	text = pcb_strdup_printf("%m+%-mS%c%-mS", conf_core.editor.grid_unit->allow, pcb_crosshair.X, sep, pcb_crosshair.Y);
+	ghid_cursor_position_label_set_text(cps, text);
+	free(text);
+}
+
diff --git a/src_plugins/lib_gtk_common/bu_cursor_pos.h b/src_plugins/lib_gtk_common/bu_cursor_pos.h
new file mode 100644
index 0000000..b345318
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_cursor_pos.h
@@ -0,0 +1,14 @@
+#include <gtk/gtk.h>
+
+typedef struct pcb_gtk_cursor_pos_s {
+	GtkWidget *cursor_position_relative_label;
+	GtkWidget *cursor_position_absolute_label;
+	GtkWidget *grid_units_label;
+	GtkWidget *grid_units_button;
+} pcb_gtk_cursor_pos_t;
+
+/* Create cps's widgets in the hbox */
+void make_cursor_position_labels(GtkWidget *hbox, pcb_gtk_cursor_pos_t *cps);
+
+/* update the content of the cursor pos labels */
+void ghid_set_cursor_position_labels(pcb_gtk_cursor_pos_t *cps, int compact_vertical);
diff --git a/src_plugins/lib_gtk_common/bu_dwg_tooltip.c b/src_plugins/lib_gtk_common/bu_dwg_tooltip.c
new file mode 100644
index 0000000..0b19788
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_dwg_tooltip.c
@@ -0,0 +1,149 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996,1997,1998,1999 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This file was originally written by Bill Wilson for the PCB Gtk port
+   and refactored by Tibor 'Igor2' Palinkas for pcb-rnd */
+
+/* Drawing area tooltips */
+
+#include "config.h"
+#include "bu_dwg_tooltip.h"
+
+#include "layer.h"
+#include "library.h"
+#include "search.h"
+#include "const.h"
+#include "find.h"
+#include "board.h"
+
+#define TOOLTIP_UPDATE_DELAY 200
+
+static char *describe_location(pcb_coord_t X, pcb_coord_t Y)
+{
+	void *ptr1, *ptr2, *ptr3;
+	int type;
+	int Range = 0;
+	const char *elename = "";
+	char *pinname;
+	char *netname = NULL;
+	char *description;
+
+	/* check if there are any pins or pads at that position */
+
+	type = pcb_search_obj_by_location(PCB_TYPE_PIN | PCB_TYPE_PAD, &ptr1, &ptr2, &ptr3, X, Y, Range);
+	if (type == PCB_TYPE_NONE)
+		return NULL;
+
+	/* don't mess with silk objects! */
+	if ((type & PCB_SILK_TYPE) && (pcb_layer_flags(pcb_layer_id(PCB->Data, (pcb_layer_t *) ptr1)) & PCB_LYT_SILK))
+		return NULL;
+
+	if (type == PCB_TYPE_PIN || type == PCB_TYPE_PAD)
+		elename = (char *) PCB_UNKNOWN(PCB_ELEM_NAME_REFDES((pcb_element_t *) ptr1));
+
+	pinname = pcb_connection_name(type, ptr1, ptr2);
+
+	if (pinname == NULL)
+		return NULL;
+
+	/* Find netlist entry */
+	PCB_MENU_LOOP(&PCB->NetlistLib[PCB_NETLIST_EDITED]);
+	{
+		if (!menu->Name)
+			continue;
+
+		PCB_ENTRY_LOOP(menu);
+		{
+			if (!entry->ListEntry)
+				continue;
+
+			if (strcmp(entry->ListEntry, pinname) == 0) {
+				netname = g_strdup(menu->Name);
+				/* For some reason, the netname has spaces in front of it, strip them */
+				g_strstrip(netname);
+				break;
+			}
+		}
+		PCB_END_LOOP;
+
+		if (netname != NULL)
+			break;
+	}
+	PCB_END_LOOP;
+
+	description = g_strdup_printf("Element name: %s\n"
+																"Pinname : %s\n"
+																"Netname : %s",
+																elename, (pinname != NULL) ? pinname : "--", (netname != NULL) ? netname : "--");
+
+	g_free(netname);
+
+	return description;
+}
+
+static int tooltip_update_timeout_id = 0;
+gboolean pcb_gtk_dwg_tooltip_check_object(GtkWidget *drawing_area, pcb_coord_t crosshairx, pcb_coord_t crosshairy)
+{
+	char *description;
+
+	/* Make sure the timer is not removed - we are called by the timer and it is
+	   automatically removed because we are returning false */
+	tooltip_update_timeout_id = 0;
+
+	/* check if there are any pins or pads at that position */
+	description = describe_location(crosshairx, crosshairy);
+
+	if (description == NULL)
+		return FALSE;
+
+	gtk_widget_set_tooltip_text(drawing_area, description);
+	g_free(description);
+
+	return FALSE;
+}
+
+void pcb_gtk_dwg_tooltip_cancel_update(void)
+{
+	if (tooltip_update_timeout_id)
+		g_source_remove(tooltip_update_timeout_id);
+	tooltip_update_timeout_id = 0;
+}
+
+/* FIXME: If the GHidPort is ever destroyed, we must call
+ * pcb_gtk_dwg_tooltip_cancel_update()
+ * fire after the data it utilises has been free'd.
+ */
+void pcb_gtk_dwg_tooltip_queue(GtkWidget *drawing_area, GSourceFunc cb, void *ctx)
+{
+	/* Zap the old tool-tip text and force it to be removed from the screen */
+	gtk_widget_set_tooltip_text(drawing_area, NULL);
+	gtk_widget_trigger_tooltip_query(drawing_area);
+
+	pcb_gtk_dwg_tooltip_cancel_update();
+
+	tooltip_update_timeout_id = g_timeout_add(TOOLTIP_UPDATE_DELAY, cb, ctx);
+}
diff --git a/src_plugins/lib_gtk_common/bu_dwg_tooltip.h b/src_plugins/lib_gtk_common/bu_dwg_tooltip.h
new file mode 100644
index 0000000..c91fc1a
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_dwg_tooltip.h
@@ -0,0 +1,5 @@
+#include <gtk/gtk.h>
+gboolean pcb_gtk_dwg_tooltip_check_object(GtkWidget *drawing_area, pcb_coord_t crosshairx, pcb_coord_t crosshairy);
+void pcb_gtk_dwg_tooltip_cancel_update(void);
+void pcb_gtk_dwg_tooltip_queue(GtkWidget *drawing_area, GSourceFunc cb, void *ctx);
+
diff --git a/src_plugins/lib_gtk_common/bu_entry.c b/src_plugins/lib_gtk_common/bu_entry.c
new file mode 100644
index 0000000..8c3b803
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_entry.c
@@ -0,0 +1,115 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This code was originally written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+
+#include "bu_entry.h"
+#include "conf_core.h"
+
+void ghid_coord_entry(GtkWidget * box, GtkWidget ** coord_entry, pcb_coord_t value,
+											pcb_coord_t low, pcb_coord_t high, enum ce_step_size step_size,
+											const pcb_unit_t * u, gint width,
+											void (*cb_func) (pcb_gtk_coord_entry_t *, gpointer),
+											gpointer data, const gchar * string_pre, const gchar * string_post)
+{
+	GtkWidget *hbox = NULL, *label, *entry_widget;
+	pcb_gtk_coord_entry_t *entry;
+
+	if (u == NULL)
+		u = conf_core.editor.grid_unit;
+
+	if ((string_pre || string_post) && box) {
+		hbox = gtk_hbox_new(FALSE, 0);
+		gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 2);
+		box = hbox;
+	}
+
+	entry_widget = pcb_gtk_coord_entry_new(low, high, value, u, step_size);
+	if (coord_entry)
+		*coord_entry = entry_widget;
+	if (width > 0)
+		gtk_widget_set_size_request(entry_widget, width, -1);
+	entry = GHID_COORD_ENTRY(entry_widget);
+	if (data == NULL)
+		data = (gpointer) entry;
+	if (cb_func)
+		g_signal_connect(G_OBJECT(entry_widget), "value_changed", G_CALLBACK(cb_func), data);
+	if (box) {
+		if (string_pre) {
+			label = gtk_label_new(string_pre);
+			gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 2);
+		}
+		gtk_box_pack_start(GTK_BOX(box), entry_widget, FALSE, FALSE, 2);
+		if (string_post) {
+			label = gtk_label_new(string_post);
+			gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+			gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 2);
+		}
+	}
+}
+
+void ghid_table_coord_entry(GtkWidget * table, gint row, gint column,
+														GtkWidget ** coord_entry, pcb_coord_t value,
+														pcb_coord_t low, pcb_coord_t high, enum ce_step_size step_size,
+														gint width, void (*cb_func) (pcb_gtk_coord_entry_t *, gpointer),
+														gpointer data, gboolean right_align, const gchar * string)
+{
+	GtkWidget *label, *entry_widget;
+	pcb_gtk_coord_entry_t *entry;
+
+	if (!table)
+		return;
+
+	entry_widget = pcb_gtk_coord_entry_new(low, high, value, conf_core.editor.grid_unit, step_size);
+	if (coord_entry)
+		*coord_entry = entry_widget;
+	if (width > 0)
+		gtk_widget_set_size_request(entry_widget, width, -1);
+	entry = GHID_COORD_ENTRY(entry_widget);
+	if (data == NULL)
+		data = (gpointer) entry;
+	if (cb_func)
+		g_signal_connect(G_OBJECT(entry), "value_changed", G_CALLBACK(cb_func), data);
+
+	if (right_align) {
+		gtk_table_attach_defaults(GTK_TABLE(table), entry_widget, column + 1, column + 2, row, row + 1);
+		if (string) {
+			label = gtk_label_new(string);
+			gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+			gtk_table_attach_defaults(GTK_TABLE(table), label, column, column + 1, row, row + 1);
+		}
+	}
+	else {
+		gtk_table_attach_defaults(GTK_TABLE(table), entry_widget, column, column + 1, row, row + 1);
+		if (string) {
+			label = gtk_label_new(string);
+			gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+			gtk_table_attach_defaults(GTK_TABLE(table), label, column + 1, column + 2, row, row + 1);
+		}
+	}
+}
diff --git a/src_plugins/lib_gtk_common/bu_entry.h b/src_plugins/lib_gtk_common/bu_entry.h
new file mode 100644
index 0000000..b27c140
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_entry.h
@@ -0,0 +1,16 @@
+#include <gtk/gtk.h>
+
+#include "wt_coord_entry.h"
+
+/** TODO: Rename these API ?  */
+void ghid_coord_entry(GtkWidget * box, GtkWidget ** coord_entry, pcb_coord_t value,
+											pcb_coord_t low, pcb_coord_t high, enum ce_step_size step_size,
+											const pcb_unit_t * u, gint width,
+											void (*cb_func) (pcb_gtk_coord_entry_t *, gpointer),
+											gpointer data, const gchar * string_pre, const gchar * string_post);
+
+void ghid_table_coord_entry(GtkWidget * table, gint row, gint column,
+														GtkWidget ** coord_entry, pcb_coord_t value,
+														pcb_coord_t low, pcb_coord_t high, enum ce_step_size step_size,
+														gint width, void (*cb_func) (pcb_gtk_coord_entry_t *, gpointer),
+														gpointer data, gboolean right_align, const gchar * string);
diff --git a/src_plugins/lib_gtk_common/bu_notebook.c b/src_plugins/lib_gtk_common/bu_notebook.c
new file mode 100644
index 0000000..f035be6
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_notebook.c
@@ -0,0 +1,56 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This code was originally written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+
+#include "bu_notebook.h"
+#include "bu_box.h"
+
+GtkWidget *ghid_notebook_page(GtkWidget * tabs, const char *name, gint pad, gint border)
+{
+	GtkWidget *label;
+	GtkWidget *vbox;
+
+	vbox = gtk_vbox_new(FALSE, pad);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), border);
+
+	label = gtk_label_new(name);
+	gtk_notebook_append_page(GTK_NOTEBOOK(tabs), vbox, label);
+
+	return vbox;
+}
+
+GtkWidget *ghid_framed_notebook_page(GtkWidget * tabs, const char *name, gint border,
+																		 gint frame_border, gint vbox_pad, gint vbox_border)
+{
+	GtkWidget *vbox;
+
+	vbox = ghid_notebook_page(tabs, name, 0, border);
+	vbox = ghid_framed_vbox(vbox, NULL, frame_border, TRUE, vbox_pad, vbox_border);
+	return vbox;
+}
diff --git a/src_plugins/lib_gtk_common/bu_notebook.h b/src_plugins/lib_gtk_common/bu_notebook.h
new file mode 100644
index 0000000..224c0d7
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_notebook.h
@@ -0,0 +1,8 @@
+#include <gtk/gtk.h>
+
+/**  Appends a page to notebook */
+GtkWidget *ghid_notebook_page(GtkWidget * tabs, const char *name, gint pad, gint border);
+
+/**  */
+GtkWidget *ghid_framed_notebook_page(GtkWidget * tabs, const char *name, gint border,
+																		 gint frame_border, gint vbox_pad, gint vbox_border);
diff --git a/src_plugins/lib_gtk_common/bu_spin_button.c b/src_plugins/lib_gtk_common/bu_spin_button.c
new file mode 100644
index 0000000..29941c5
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_spin_button.c
@@ -0,0 +1,123 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* Originally from gui-utils.c, was written by Bill Wilson and the functions
+ * here are Copyright (C) 2004 by Bill Wilson.  Those functions were utility
+ * functions which are taken from my other GPL'd projects gkrellm and
+ * gstocks and are copied here for the Gtk PCB port.
+ */
+
+#include "config.h"
+
+#include "bu_spin_button.h"
+
+void
+ghid_spin_button(GtkWidget * box, GtkWidget ** spin_button, gfloat value,
+								 gfloat low, gfloat high, gfloat step0, gfloat step1,
+								 gint digits, gint width,
+								 void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, const gchar * string)
+{
+	GtkWidget *hbox = NULL, *label, *spin_but;
+	GtkSpinButton *spin;
+	GtkAdjustment *adj;
+
+	if (string && box) {
+		hbox = gtk_hbox_new(FALSE, 0);
+		gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 2);
+		box = hbox;
+	}
+	adj = (GtkAdjustment *) gtk_adjustment_new(value, low, high, step0, step1, 0.0);
+	spin_but = gtk_spin_button_new(adj, 0.5, digits);
+	if (spin_button)
+		*spin_button = spin_but;
+	if (width > 0)
+		gtk_widget_set_size_request(spin_but, width, -1);
+	spin = GTK_SPIN_BUTTON(spin_but);
+	gtk_spin_button_set_numeric(spin, TRUE);
+	if (data == NULL)
+		data = (gpointer) spin;
+	if (cb_func)
+		g_signal_connect(G_OBJECT(spin_but), "value_changed", G_CALLBACK(cb_func), data);
+	if (box) {
+		if (right_align && string) {
+			label = gtk_label_new(string);
+			gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+			gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 2);
+		}
+		gtk_box_pack_start(GTK_BOX(box), spin_but, FALSE, FALSE, 2);
+		if (!right_align && string) {
+			label = gtk_label_new(string);
+			gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+			gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 2);
+		}
+	}
+}
+
+void
+ghid_table_spin_button(GtkWidget * table, gint row, gint column,
+											 GtkWidget ** spin_button, gfloat value,
+											 gfloat low, gfloat high, gfloat step0, gfloat step1,
+											 gint digits, gint width,
+											 void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, const gchar * string)
+{
+	GtkWidget *label, *spin_but;
+	GtkSpinButton *spin;
+	GtkAdjustment *adj;
+
+	if (!table)
+		return;
+
+	adj = (GtkAdjustment *) gtk_adjustment_new(value, low, high, step0, step1, 0.0);
+	spin_but = gtk_spin_button_new(adj, 0.5, digits);
+
+	if (spin_button)
+		*spin_button = spin_but;
+	if (width > 0)
+		gtk_widget_set_size_request(spin_but, width, -1);
+	spin = GTK_SPIN_BUTTON(spin_but);
+	gtk_spin_button_set_numeric(spin, TRUE);
+	if (data == NULL)
+		data = (gpointer) spin;
+	if (cb_func)
+		g_signal_connect(G_OBJECT(spin_but), "value_changed", G_CALLBACK(cb_func), data);
+
+	if (right_align) {
+		gtk_table_attach_defaults(GTK_TABLE(table), spin_but, column + 1, column + 2, row, row + 1);
+		if (string) {
+			label = gtk_label_new(string);
+			gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+			gtk_table_attach_defaults(GTK_TABLE(table), label, column, column + 1, row, row + 1);
+		}
+	}
+	else {
+		gtk_table_attach_defaults(GTK_TABLE(table), spin_but, column, column + 1, row, row + 1);
+		if (string) {
+			label = gtk_label_new(string);
+			gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+			gtk_table_attach_defaults(GTK_TABLE(table), label, column + 1, column + 2, row, row + 1);
+		}
+	}
+}
diff --git a/src_plugins/lib_gtk_common/bu_spin_button.h b/src_plugins/lib_gtk_common/bu_spin_button.h
new file mode 100644
index 0000000..46d7c89
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_spin_button.h
@@ -0,0 +1,14 @@
+#include <gtk/gtk.h>
+
+void
+ghid_spin_button(GtkWidget * box, GtkWidget ** spin_button, gfloat value,
+								 gfloat low, gfloat high, gfloat step0, gfloat step1,
+								 gint digits, gint width,
+								 void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, const gchar * string);
+
+void
+ghid_table_spin_button(GtkWidget * table, gint row, gint column,
+											 GtkWidget ** spin_button, gfloat value,
+											 gfloat low, gfloat high, gfloat step0, gfloat step1,
+											 gint digits, gint width,
+											 void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, const gchar * string);
diff --git a/src_plugins/lib_gtk_common/bu_status_line.c b/src_plugins/lib_gtk_common/bu_status_line.c
new file mode 100644
index 0000000..1fad7fe
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_status_line.c
@@ -0,0 +1,69 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "config.h"
+#include "bu_status_line.h"
+#include "conf_core.h"
+#include "compat_misc.h"
+#include "compat_nls.h"
+#include "board.h"
+
+GtkWidget *pcb_gtk_build_status_line_label(void)
+{
+	GtkWidget *label = gtk_label_new("");
+	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+
+	return label;
+}
+
+void ghid_status_line_set_text_(GtkWidget *status_line_label, const gchar * text)
+{
+	if (status_line_label != NULL)
+		gtk_label_set_markup(GTK_LABEL(status_line_label), text ? text : "");
+}
+
+void ghid_set_status_line_label_(GtkWidget *status_line_label, int compat_horiz)
+{
+	const gchar *flag = conf_core.editor.all_direction_lines
+		? "*" : (conf_core.editor.line_refraction == 0 ? "X" : (conf_core.editor.line_refraction == 1 ? "_/" : "\\_"));
+	char *text = pcb_strdup_printf(_("%m+<b>view</b>=%s  "
+																	 "<b>grid</b>=%$mS  "
+																	 "%s%s  "
+																	 "<b>line</b>=%mS  "
+																	 "<b>via</b>=%mS (%mS)  %s"
+																	 "<b>clearance</b>=%mS  " "<b>text</b>=%i%%  " "<b>buffer</b>=#%i"),
+																 conf_core.editor.grid_unit->allow,
+																 conf_core.editor.show_solder_side ? _("solder") : _("component"),
+																 PCB->Grid,
+																 flag, conf_core.editor.rubber_band_mode ? ",R  " : "  ",
+																 conf_core.design.line_thickness,
+																 conf_core.design.via_thickness,
+																 conf_core.design.via_drilling_hole,
+																 compat_horiz ? "\n" : "",
+																 conf_core.design.clearance,
+																 conf_core.design.text_scale, conf_core.editor.buffer_number + 1);
+
+	ghid_status_line_set_text_(status_line_label, text);
+	free(text);
+}
+
diff --git a/src_plugins/lib_gtk_common/bu_status_line.h b/src_plugins/lib_gtk_common/bu_status_line.h
new file mode 100644
index 0000000..27b608f
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_status_line.h
@@ -0,0 +1,11 @@
+#include <gtk/gtk.h>
+
+GtkWidget *pcb_gtk_build_status_line_label(void);
+void ghid_status_line_set_text_(GtkWidget *status_line_label, const gchar * text);
+
+void ghid_set_status_line_label_(GtkWidget *status_line_label, int compat_horiz);
+
+/* implemented in hid_gtk* glue layer: */
+
+extern void ghid_status_line_set_text(const gchar *text);
+extern void ghid_set_status_line_label(void);
diff --git a/src_plugins/lib_gtk_common/bu_text_view.c b/src_plugins/lib_gtk_common/bu_text_view.c
new file mode 100644
index 0000000..2e8b1a3
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_text_view.c
@@ -0,0 +1,121 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* Originally from gui-utils.c, was written by Bill Wilson and the functions
+ * here are Copyright (C) 2004 by Bill Wilson.  Those functions were utility
+ * functions which are taken from my other GPL'd projects gkrellm and
+ * gstocks and are copied here for the Gtk PCB port.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include "bu_text_view.h"
+//#include "compat.h"
+
+GtkWidget *ghid_scrolled_text_view(GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy)
+{
+	GtkWidget *scrolled, *view;
+	GtkTextBuffer *buffer;
+
+	scrolled = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), h_policy, v_policy);
+	gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0);
+
+	view = gtk_text_view_new();
+	gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE);
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
+	gtk_text_buffer_create_tag(buffer, "heading", "weight", PANGO_WEIGHT_BOLD, "size", 14 * PANGO_SCALE, NULL);
+	gtk_text_buffer_create_tag(buffer, "italic", "style", PANGO_STYLE_ITALIC, NULL);
+	gtk_text_buffer_create_tag(buffer, "bold", "weight", PANGO_WEIGHT_BOLD, NULL);
+	gtk_text_buffer_create_tag(buffer, "center", "justification", GTK_JUSTIFY_CENTER, NULL);
+	gtk_text_buffer_create_tag(buffer, "underline", "underline", PANGO_UNDERLINE_SINGLE, NULL);
+	gtk_text_buffer_create_tag(buffer, "red", "foreground", "#aa0000", NULL);
+	gtk_text_buffer_create_tag(buffer, "green", "foreground", "#00aa00", NULL);
+	gtk_text_buffer_create_tag(buffer, "blue", "foreground", "#0000aa", NULL);
+
+	gtk_container_add(GTK_CONTAINER(scrolled), view);
+	if (scr)
+		*scr = scrolled;
+	return view;
+}
+
+static void text_view_append(GtkWidget * view, const gchar * s)
+{
+	GtkTextIter iter;
+	GtkTextBuffer *buffer;
+	GtkTextMark *mark;
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
+	gtk_text_buffer_get_end_iter(buffer, &iter);
+	/* gtk_text_iter_forward_to_end(&iter); */
+
+	if (strncmp(s, "<b>", 3) == 0)
+		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "bold", NULL);
+	else if (strncmp(s, "<i>", 3) == 0)
+		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "italic", NULL);
+	else if (strncmp(s, "<h>", 3) == 0)
+		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "heading", NULL);
+	else if (strncmp(s, "<c>", 3) == 0)
+		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "center", NULL);
+	else if (strncmp(s, "<R>", 3) == 0)
+		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "red", NULL);
+	else if (strncmp(s, "<G>", 3) == 0)
+		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "green", NULL);
+	else if (strncmp(s, "<B>", 3) == 0)
+		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 3, -1, "blue", NULL);
+	else if (strncmp(s, "<ul>", 4) == 0)
+		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, s + 4, -1, "underline", NULL);
+	else
+		gtk_text_buffer_insert(buffer, &iter, s, -1);
+
+	mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, FALSE);
+	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(view), mark, 0, TRUE, 0.0, 1.0);
+	gtk_text_buffer_delete_mark(buffer, mark);
+}
+
+void ghid_text_view_append(GtkWidget * view, const gchar * string)
+{
+	static gchar *tag;
+	const gchar *s;
+
+	s = string;
+	if (*s == '<' && ((*(s + 2) == '>' && !*(s + 3)) || (*(s + 3) == '>' && !*(s + 4)))) {
+		tag = g_strdup(s);
+		return;
+	}
+
+	if (tag) {
+		char *concatenation;
+		concatenation = g_strconcat(tag, string, NULL);
+		text_view_append(view, concatenation);
+		g_free(concatenation);
+		g_free(tag);
+		tag = NULL;
+	}
+	else
+		text_view_append(view, string);
+}
diff --git a/src_plugins/lib_gtk_common/bu_text_view.h b/src_plugins/lib_gtk_common/bu_text_view.h
new file mode 100644
index 0000000..4e7bf8f
--- /dev/null
+++ b/src_plugins/lib_gtk_common/bu_text_view.h
@@ -0,0 +1,5 @@
+#include <gtk/gtk.h>
+
+GtkWidget *ghid_scrolled_text_view(GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy);
+
+void ghid_text_view_append(GtkWidget * view, const gchar * string);
diff --git a/src_plugins/lib_gtk_common/compat.h b/src_plugins/lib_gtk_common/compat.h
new file mode 100644
index 0000000..ba9109a
--- /dev/null
+++ b/src_plugins/lib_gtk_common/compat.h
@@ -0,0 +1,53 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2017 Tibor Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/* hbox/vbox creation, similar to gtk2's */
+#ifdef PCB_GTK3
+static inline GtkWidget *gtkc_hbox_new(gboolean homogenous, gint spacing)
+{
+	GtkBox *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, spacing);
+	gtk_box_set_homogenous(box, homogenous);
+	return GTK_WIDGET(box);
+}
+
+static inline GtkWidget *gtkc_vbox_new(gboolean homogenous, gint spacing)
+{
+	GtkBox *box = gtk_box_new(TK_ORIENTATION_VERTICAL, spacing);
+	gtk_box_set_homogenous(box, homogenous);
+	return GTK_WIDGET(box);
+}
+
+#else
+/* gtk2 */
+
+static inline GtkWidget *gtkc_hbox_new(gboolean homogenous, gint spacing)
+{
+	return gtk_hbox_new(homogenous, spacing);
+}
+
+static inline GtkWidget *gtkc_vbox_new(gboolean homogenous, gint spacing)
+{
+	return gtk_vbox_new(homogenous, spacing);
+}
+
+#endif
+
diff --git a/src_plugins/lib_gtk_common/dlg_about.c b/src_plugins/lib_gtk_common/dlg_about.c
new file mode 100644
index 0000000..5b1258b
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_about.c
@@ -0,0 +1,90 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+#include "config.h"
+
+#include "dlg_about.h"
+#include "compat_nls.h"
+#include "build_run.h"
+
+#include "dlg_report.h"
+
+static void display_options_dialog(GtkWidget * button, gpointer data)
+{
+	const gchar *text = pcb_get_info_compile_options();
+	GtkWidget *about = (GtkWidget *) data;
+
+	pcb_gtk_dlg_report(about, "Compile time Options", text, TRUE);
+}
+
+void pcb_gtk_dlg_about(GtkWidget * top_window)
+{
+	GtkWidget *button;
+	GtkWidget *w = gtk_about_dialog_new();
+	GtkAboutDialog *about = GTK_ABOUT_DIALOG(w);
+
+	/* Add the compile options button */
+	button = gtk_button_new_from_stock(_("_Options"));
+	/*gtk_widget_set_can_default(button, TRUE);*/
+	gtk_widget_show(button);
+	gtk_box_pack_end(GTK_BOX(GTK_DIALOG(about)->action_area), button, FALSE, TRUE, 0);
+	gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(GTK_DIALOG(about)->action_area), button, TRUE);
+	g_signal_connect(button, "clicked", G_CALLBACK(display_options_dialog), about);
+
+	/* We don't want to maintain a list of authors... So, this is the minimum info */
+	const gchar *authors[] = { "For authors, see the (C) in the main dialog",
+		"GTK HID:", "  Bill Wilson", NULL
+	};
+
+	gtk_about_dialog_set_program_name(about, "pcb-rnd");
+	gtk_about_dialog_set_version(about, VERSION);
+	gtk_about_dialog_set_authors(about, authors);
+
+	gtk_about_dialog_set_copyright(about, pcb_get_info_copyright());
+
+	/*TODO: Find a proper way to include the COPYING file and/or display this info :
+	   gds_append_str(&info, "It is licensed under the terms of the GNU\n");
+	   gds_append_str(&info, "General Public License version 2\n");
+	   gds_append_str(&info, "See the LICENSE file for more information\n\n");
+	 */
+
+	gtk_about_dialog_set_license(about,
+															 "It is licensed under the terms of the GNU\n" "General Public License version 2\n"
+															 "See the COPYING file for more information\n\n");
+	/* in GTK3:
+	   gtk_about_dialog_set_license_type(about, GTK_LICENSE_GPL_2_0); */
+	/*FIXME: Refactor the string w.r.t. the dialog */
+
+	gtk_about_dialog_set_comments(about, pcb_get_info_comments());
+
+	gtk_about_dialog_set_website(about, "http://repo.hu/projects/pcb-rnd/");
+	gtk_about_dialog_set_website_label(about, "Visit the PCB-rnd website");
+	gtk_about_dialog_set_documenters(about, NULL);
+	gtk_about_dialog_set_translator_credits(about, _("translator-credits"));
+
+	gtk_dialog_run(GTK_DIALOG(w));
+	gtk_widget_destroy(w);
+}
diff --git a/src_plugins/lib_gtk_common/dlg_about.h b/src_plugins/lib_gtk_common/dlg_about.h
new file mode 100644
index 0000000..536f049
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_about.h
@@ -0,0 +1,4 @@
+#include <gtk/gtk.h>
+
+/** Displays and runs the modal About dialog */
+void pcb_gtk_dlg_about(GtkWidget * top_window);
diff --git a/src_plugins/lib_gtk_common/dlg_attribute.c b/src_plugins/lib_gtk_common/dlg_attribute.c
new file mode 100644
index 0000000..67b381a
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_attribute.c
@@ -0,0 +1,497 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This file written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+#include "conf_core.h"
+#include "dlg_attribute.h"
+#include <stdlib.h>
+
+#include "pcb-printf.h"
+#include "hid_attrib.h"
+#include "hid_init.h"
+#include "misc_util.h"
+#include "compat_misc.h"
+#include "compat_nls.h"
+
+#include "wt_coord_entry.h"
+
+GtkWidget *ghid_category_vbox(GtkWidget * box, const gchar * category_header, gint header_pad, gint box_pad,
+															gboolean pack_start, gboolean bottom_pad);
+void ghid_spin_button(GtkWidget * box, GtkWidget ** spin_button, gfloat value, gfloat low, gfloat high, gfloat step0,
+											gfloat step1, gint digits, gint width, void (*cb_func) (GtkSpinButton *, gpointer), gpointer data,
+											gboolean right_align, const gchar * string);
+void ghid_check_button_connected(GtkWidget * box, GtkWidget ** button, gboolean active, gboolean pack_start, gboolean expand,
+																 gboolean fill, gint pad, void (*cb_func) (GtkToggleButton *, gpointer), gpointer data,
+																 const gchar * string);
+
+
+
+static void set_flag_cb(GtkToggleButton * button, void *flag)
+{
+	*(gboolean *) flag = gtk_toggle_button_get_active(button);
+}
+
+
+static void intspinner_changed_cb(GtkSpinButton * spin_button, gpointer data)
+{
+	int *ival = (int *) data;
+
+	*ival = gtk_spin_button_get_value(GTK_SPIN_BUTTON((GtkWidget *) spin_button));
+}
+
+static void coordentry_changed_cb(GtkEntry * entry, pcb_coord_t * res)
+{
+	const gchar *s = gtk_entry_get_text(entry);
+	*res = pcb_get_value(s, NULL, NULL, NULL);
+}
+
+static void dblspinner_changed_cb(GtkSpinButton * spin_button, gpointer data)
+{
+	double *dval = (double *) data;
+
+	*dval = gtk_spin_button_get_value(GTK_SPIN_BUTTON((GtkWidget *) spin_button));
+}
+
+
+static void entry_changed_cb(GtkEntry * entry, char **str)
+{
+	const gchar *s;
+
+	s = gtk_entry_get_text(entry);
+
+	if (*str)
+		free(*str);
+	*str = pcb_strdup(s);
+}
+
+static void enum_changed_cb(GtkWidget * combo_box, int *val)
+{
+	gint active;
+
+	active = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
+	*val = active;
+}
+
+
+int ghid_attribute_dialog(GtkWidget * top_window, pcb_hid_attribute_t * attrs, int n_attrs, pcb_hid_attr_val_t * results,
+													const char *title, const char *descr)
+{
+	GtkWidget *dialog;
+	GtkWidget *content_area;
+	GtkWidget *main_vbox, *vbox, *vbox1, *hbox, *entry;
+	GtkWidget *combo;
+	GtkWidget *widget;
+	int i, j, n;
+	int rc = 0;
+
+	dialog = gtk_dialog_new_with_buttons(_(title),
+																			 GTK_WINDOW(top_window),
+																			 (GtkDialogFlags) (GTK_DIALOG_MODAL
+																												 | GTK_DIALOG_DESTROY_WITH_PARENT),
+																			 GTK_STOCK_CANCEL, GTK_RESPONSE_NONE, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+	gtk_window_set_wmclass(GTK_WINDOW(dialog), "PCB_attribute_editor", "PCB");
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+	main_vbox = gtk_vbox_new(FALSE, 6);
+	gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 6);
+	gtk_container_add(GTK_CONTAINER(content_area), main_vbox);
+
+	vbox = ghid_category_vbox(main_vbox, descr != NULL ? descr : "", 4, 2, TRUE, TRUE);
+
+	/*
+	 * Iterate over all the export options and build up a dialog box
+	 * that lets us control all of the options.  By doing things this
+	 * way, any changes to the exporter HID's automatically are
+	 * reflected in this dialog box.
+	 */
+	for (j = 0; j < n_attrs; j++) {
+		const pcb_unit_t *unit_list;
+		if (attrs[j].help_text == ATTR_UNDOCUMENTED)
+			continue;
+		switch (attrs[j].type) {
+		case HID_Label:
+			widget = gtk_label_new(attrs[j].name);
+			gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
+			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
+			break;
+
+		case HID_Integer:
+			hbox = gtk_hbox_new(FALSE, 4);
+			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+			/*
+			 * FIXME
+			 * need to pick the "digits" argument based on min/max
+			 * values
+			 */
+			ghid_spin_button(hbox, &widget, attrs[j].default_val.int_value,
+											 attrs[j].min_val, attrs[j].max_val, 1.0, 1.0, 0, 0,
+											 intspinner_changed_cb, &(attrs[j].default_val.int_value), FALSE, NULL);
+			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
+
+			widget = gtk_label_new(attrs[j].name);
+			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
+			break;
+
+		case HID_Coord:
+			hbox = gtk_hbox_new(FALSE, 4);
+			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+			entry = pcb_gtk_coord_entry_new(attrs[j].min_val, attrs[j].max_val,
+																			attrs[j].default_val.coord_value, conf_core.editor.grid_unit, CE_SMALL);
+			gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
+			if (attrs[j].default_val.str_value != NULL)
+				gtk_entry_set_text(GTK_ENTRY(entry), attrs[j].default_val.str_value);
+			gtk_widget_set_tooltip_text(entry, attrs[j].help_text);
+			g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(coordentry_changed_cb), &(attrs[j].default_val.coord_value));
+
+			widget = gtk_label_new(attrs[j].name);
+			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
+			break;
+
+		case HID_Real:
+			hbox = gtk_hbox_new(FALSE, 4);
+			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+			/*
+			 * FIXME
+			 * need to pick the "digits" and step size argument more
+			 * intelligently
+			 */
+			ghid_spin_button(hbox, &widget, attrs[j].default_val.real_value,
+											 attrs[j].min_val, attrs[j].max_val, 0.01, 0.01, 3,
+											 0, dblspinner_changed_cb, &(attrs[j].default_val.real_value), FALSE, NULL);
+
+			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
+
+			widget = gtk_label_new(attrs[j].name);
+			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
+			break;
+
+		case HID_String:
+			hbox = gtk_hbox_new(FALSE, 4);
+			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+			entry = gtk_entry_new();
+			gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
+			if (attrs[j].default_val.str_value != NULL)
+				gtk_entry_set_text(GTK_ENTRY(entry), attrs[j].default_val.str_value);
+			gtk_widget_set_tooltip_text(entry, attrs[j].help_text);
+			g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_changed_cb), &(attrs[j].default_val.str_value));
+
+			widget = gtk_label_new(attrs[j].name);
+			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
+			break;
+
+		case HID_Boolean:
+			/* put this in a check button */
+			ghid_check_button_connected(vbox, &widget,
+																	attrs[j].default_val.int_value,
+																	TRUE, FALSE, FALSE, 0, set_flag_cb, &(attrs[j].default_val.int_value), attrs[j].name);
+			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
+			break;
+
+		case HID_Enum:
+			hbox = gtk_hbox_new(FALSE, 4);
+			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+		do_enum:
+			combo = gtk_combo_box_new_text();
+			gtk_widget_set_tooltip_text(combo, attrs[j].help_text);
+			gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
+			g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(enum_changed_cb), &(attrs[j].default_val.int_value));
+
+
+			/*
+			 * Iterate through each value and add them to the
+			 * combo box
+			 */
+			i = 0;
+			while (attrs[j].enumerations[i]) {
+				gtk_combo_box_append_text(GTK_COMBO_BOX(combo), attrs[j].enumerations[i]);
+				i++;
+			}
+			gtk_combo_box_set_active(GTK_COMBO_BOX(combo), attrs[j].default_val.int_value);
+			widget = gtk_label_new(attrs[j].name);
+			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
+			break;
+
+		case HID_Mixed:
+			hbox = gtk_hbox_new(FALSE, 4);
+			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+			/*
+			 * FIXME
+			 * need to pick the "digits" and step size argument more
+			 * intelligently
+			 */
+			ghid_spin_button(hbox, &widget, attrs[j].default_val.real_value,
+											 attrs[j].min_val, attrs[j].max_val, 0.01, 0.01, 3,
+											 0, dblspinner_changed_cb, &(attrs[j].default_val.real_value), FALSE, NULL);
+			gtk_widget_set_tooltip_text(widget, attrs[j].help_text);
+
+			goto do_enum;
+			break;
+
+		case HID_Path:
+			vbox1 = ghid_category_vbox(vbox, attrs[j].name, 4, 2, TRUE, TRUE);
+			entry = gtk_entry_new();
+			gtk_box_pack_start(GTK_BOX(vbox1), entry, FALSE, FALSE, 0);
+			gtk_entry_set_text(GTK_ENTRY(entry), attrs[j].default_val.str_value);
+			g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_changed_cb), &(attrs[j].default_val.str_value));
+
+			gtk_widget_set_tooltip_text(entry, attrs[j].help_text);
+			break;
+
+		case HID_Unit:
+			unit_list = get_unit_list();
+			n = pcb_get_n_units();
+
+			hbox = gtk_hbox_new(FALSE, 4);
+			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+			combo = gtk_combo_box_new_text();
+			gtk_widget_set_tooltip_text(combo, attrs[j].help_text);
+			gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
+			g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(enum_changed_cb), &(attrs[j].default_val.int_value));
+
+			/*
+			 * Iterate through each value and add them to the
+			 * combo box
+			 */
+			for (i = 0; i < n; ++i)
+				gtk_combo_box_append_text(GTK_COMBO_BOX(combo), unit_list[i].in_suffix);
+			gtk_combo_box_set_active(GTK_COMBO_BOX(combo), attrs[j].default_val.int_value);
+			widget = gtk_label_new(attrs[j].name);
+			gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
+			break;
+		default:
+			printf("ghid_attribute_dialog: unknown type of HID attribute\n");
+			break;
+		}
+	}
+
+
+	gtk_widget_show_all(dialog);
+
+	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
+		/* copy over the results */
+		for (i = 0; i < n_attrs; i++) {
+			results[i] = attrs[i].default_val;
+			if (results[i].str_value)
+				results[i].str_value = pcb_strdup(results[i].str_value);
+		}
+		rc = 0;
+	}
+	else
+		rc = 1;
+
+	gtk_widget_destroy(dialog);
+
+	return rc;
+}
+
+typedef struct {
+	GtkWidget *del;
+	GtkWidget *w_name;
+	GtkWidget *w_value;
+} AttrRow;
+
+static AttrRow *attr_row = 0;
+static int attr_num_rows = 0;
+static int attr_max_rows = 0;
+static pcb_attribute_list_t *attributes_list;
+static GtkWidget *attributes_dialog, *attr_table;
+
+static void attributes_delete_callback(GtkWidget * w, void *v);
+
+#define GA_RESPONSE_REVERT	1
+#define GA_RESPONSE_NEW		2
+
+static void ghid_attr_set_table_size()
+{
+	gtk_table_resize(GTK_TABLE(attr_table), attr_num_rows > 0 ? attr_num_rows : 1, 3);
+}
+
+static void ghid_attributes_need_rows(int new_max)
+{
+	if (attr_max_rows < new_max) {
+		if (attr_row)
+			attr_row = (AttrRow *) realloc(attr_row, new_max * sizeof(AttrRow));
+		else
+			attr_row = (AttrRow *) malloc(new_max * sizeof(AttrRow));
+	}
+	while (attr_max_rows < new_max) {
+		/* add [attr_max_rows] */
+		attr_row[attr_max_rows].del = gtk_button_new_with_label("del");
+		gtk_table_attach(GTK_TABLE(attr_table), attr_row[attr_max_rows].del,
+										 0, 1, attr_max_rows, attr_max_rows + 1, (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), GTK_FILL, 0, 0);
+		g_signal_connect(G_OBJECT(attr_row[attr_max_rows].del), "clicked",
+										 G_CALLBACK(attributes_delete_callback), GINT_TO_POINTER(attr_max_rows));
+
+		attr_row[attr_max_rows].w_name = gtk_entry_new();
+		gtk_table_attach(GTK_TABLE(attr_table), attr_row[attr_max_rows].w_name,
+										 1, 2, attr_max_rows, attr_max_rows + 1, (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), GTK_FILL, 0, 0);
+
+		attr_row[attr_max_rows].w_value = gtk_entry_new();
+		gtk_table_attach(GTK_TABLE(attr_table), attr_row[attr_max_rows].w_value,
+										 2, 3, attr_max_rows, attr_max_rows + 1, (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), GTK_FILL, 0, 0);
+
+		attr_max_rows++;
+	}
+
+	/* Manage any previously unused rows we now need to show.  */
+	while (attr_num_rows < new_max) {
+		/* manage attr_num_rows */
+		gtk_widget_show(attr_row[attr_num_rows].del);
+		gtk_widget_show(attr_row[attr_num_rows].w_name);
+		gtk_widget_show(attr_row[attr_num_rows].w_value);
+		attr_num_rows++;
+	}
+}
+
+static void ghid_attributes_revert()
+{
+	int i;
+
+	ghid_attributes_need_rows(attributes_list->Number);
+
+	/* Unmanage any previously used rows we don't need.  */
+	while (attr_num_rows > attributes_list->Number) {
+		attr_num_rows--;
+		gtk_widget_hide(attr_row[attr_num_rows].del);
+		gtk_widget_hide(attr_row[attr_num_rows].w_name);
+		gtk_widget_hide(attr_row[attr_num_rows].w_value);
+	}
+
+	/* Fill in values */
+	for (i = 0; i < attributes_list->Number; i++) {
+		/* create row [i] */
+		gtk_entry_set_text(GTK_ENTRY(attr_row[i].w_name), attributes_list->List[i].name);
+		gtk_entry_set_text(GTK_ENTRY(attr_row[i].w_value), attributes_list->List[i].value);
+	}
+	ghid_attr_set_table_size();
+}
+
+static void attributes_delete_callback(GtkWidget * w, void *v)
+{
+	int i, n;
+
+	n = GPOINTER_TO_INT(v);
+
+	for (i = n; i < attr_num_rows - 1; i++) {
+		gtk_entry_set_text(GTK_ENTRY(attr_row[i].w_name), gtk_entry_get_text(GTK_ENTRY(attr_row[i + 1].w_name)));
+		gtk_entry_set_text(GTK_ENTRY(attr_row[i].w_value), gtk_entry_get_text(GTK_ENTRY(attr_row[i + 1].w_value)));
+	}
+	attr_num_rows--;
+
+	gtk_widget_hide(attr_row[attr_num_rows].del);
+	gtk_widget_hide(attr_row[attr_num_rows].w_name);
+	gtk_widget_hide(attr_row[attr_num_rows].w_value);
+
+	ghid_attr_set_table_size();
+}
+
+void pcb_gtk_dlg_attributes(GtkWidget *top_window, const char *owner, pcb_attribute_list_t * attrs)
+{
+	GtkWidget *content_area;
+	int response;
+
+	attributes_list = attrs;
+
+	attr_max_rows = 0;
+	attr_num_rows = 0;
+
+	attributes_dialog = gtk_dialog_new_with_buttons(owner,
+																									GTK_WINDOW(top_window),
+																									GTK_DIALOG_MODAL,
+																									GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+																									"Revert", GA_RESPONSE_REVERT,
+																									"New", GA_RESPONSE_NEW, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	attr_table = gtk_table_new(attrs->Number, 3, 0);
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(attributes_dialog));
+	gtk_box_pack_start(GTK_BOX(content_area), attr_table, FALSE, FALSE, 0);
+
+	gtk_widget_show(attr_table);
+
+	ghid_attributes_revert();
+
+	while (1) {
+		response = gtk_dialog_run(GTK_DIALOG(attributes_dialog));
+
+		if (response == GTK_RESPONSE_CANCEL)
+			break;
+
+		if (response == GTK_RESPONSE_OK) {
+			int i;
+			/* Copy the values back */
+			for (i = 0; i < attributes_list->Number; i++) {
+				if (attributes_list->List[i].name)
+					free(attributes_list->List[i].name);
+				if (attributes_list->List[i].value)
+					free(attributes_list->List[i].value);
+			}
+			if (attributes_list->Max < attr_num_rows) {
+				int sz = attr_num_rows * sizeof(pcb_attribute_t);
+				if (attributes_list->List == NULL)
+					attributes_list->List = (pcb_attribute_t *) malloc(sz);
+				else
+					attributes_list->List = (pcb_attribute_t *) realloc(attributes_list->List, sz);
+				attributes_list->Max = attr_num_rows;
+			}
+			for (i = 0; i < attr_num_rows; i++) {
+				attributes_list->List[i].name = pcb_strdup(gtk_entry_get_text(GTK_ENTRY(attr_row[i].w_name)));
+				attributes_list->List[i].value = pcb_strdup(gtk_entry_get_text(GTK_ENTRY(attr_row[i].w_value)));
+				attributes_list->Number = attr_num_rows;
+			}
+
+			break;
+		}
+
+		if (response == GA_RESPONSE_REVERT) {
+			/* Revert */
+			ghid_attributes_revert();
+		}
+
+		if (response == GA_RESPONSE_NEW) {
+			ghid_attributes_need_rows(attr_num_rows + 1);	/* also bumps attr_num_rows */
+
+			gtk_entry_set_text(GTK_ENTRY(attr_row[attr_num_rows - 1].w_name), "");
+			gtk_entry_set_text(GTK_ENTRY(attr_row[attr_num_rows - 1].w_value), "");
+
+			ghid_attr_set_table_size();
+		}
+	}
+
+	gtk_widget_destroy(attributes_dialog);
+	free(attr_row);
+	attr_row = NULL;
+}
diff --git a/src_plugins/lib_gtk_common/dlg_attribute.h b/src_plugins/lib_gtk_common/dlg_attribute.h
new file mode 100644
index 0000000..861056e
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_attribute.h
@@ -0,0 +1,10 @@
+#include <gtk/gtk.h>
+#include "hid.h"
+
+int ghid_attribute_dialog(GtkWidget *top_window, pcb_hid_attribute_t * attrs, int n_attrs, pcb_hid_attr_val_t * results, const char *title, const char *descr);
+
+void pcb_gtk_dlg_attributes(GtkWidget *top_window, const char *owner, pcb_attribute_list_t * attrs);
+
+
+
+
diff --git a/src_plugins/lib_gtk_common/dlg_confirm.c b/src_plugins/lib_gtk_common/dlg_confirm.c
new file mode 100644
index 0000000..ba68107
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_confirm.c
@@ -0,0 +1,107 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+#include "dlg_confirm.h"
+#include "compat_nls.h"
+#include "board.h"
+#include "hid_actions.h"
+
+#include "dlg_message.h"
+
+int pcb_gtk_dlg_confirm_open(GtkWidget *top_window, const char *msg, va_list ap)
+{
+	int rv = 0;
+	const char *cancelmsg = NULL, *okmsg = NULL;
+	static gint x = -1, y = -1;
+	GtkWidget *dialog;
+
+	cancelmsg = va_arg(ap, char *);
+	okmsg = va_arg(ap, char *);
+
+	if (!cancelmsg) {
+		cancelmsg = _("_Cancel");
+		okmsg = _("_OK");
+	}
+
+	dialog = gtk_message_dialog_new(GTK_WINDOW(top_window),
+																	(GtkDialogFlags) (GTK_DIALOG_MODAL |
+																										GTK_DIALOG_DESTROY_WITH_PARENT),
+																	GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", msg);
+	gtk_dialog_add_button(GTK_DIALOG(dialog), cancelmsg, GTK_RESPONSE_CANCEL);
+	if (okmsg) {
+		gtk_dialog_add_button(GTK_DIALOG(dialog), okmsg, GTK_RESPONSE_OK);
+	}
+
+	if (x != -1) {
+		gtk_window_move(GTK_WINDOW(dialog), x, y);
+	}
+
+	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
+		rv = 1;
+
+	gtk_window_get_position(GTK_WINDOW(dialog), &x, &y);
+
+	gtk_widget_destroy(dialog);
+	return rv;
+}
+
+int pcb_gtk_dlg_confirm_close(GtkWidget *top_window)
+{
+	gchar *bold_text;
+	gchar *str;
+	const char *msg;
+
+	if (PCB->Filename == NULL) {
+		bold_text = g_strdup_printf(_("Save the changes to layout before closing?"));
+	}
+	else {
+		bold_text = g_strdup_printf(_("Save the changes to layout \"%s\" before closing?"), PCB->Filename);
+	}
+	str = g_strconcat("<big><b>", bold_text, "</b></big>", NULL);
+	g_free(bold_text);
+	msg = _("If you don't save, all your changes will be permanently lost.");
+	str = g_strconcat(str, "\n\n", msg, NULL);
+
+	switch (pcb_gtk_dlg_message(str, GTK_WINDOW(top_window))) {
+		case GTK_RESPONSE_YES:
+		{
+			if (pcb_hid_actionl("Save", NULL)) {	/* Save failed */
+				return 0;								/* Cancel */
+			}
+			else {
+				return 1;								/* Close */
+			}
+		}
+		case GTK_RESPONSE_NO:
+		{
+			return 1;									/* Close */
+		}
+		case GTK_RESPONSE_CANCEL:
+		default:
+		{
+			return 0;									/* Cancel */
+		}
+	}
+	g_free(str);
+}
diff --git a/src_plugins/lib_gtk_common/dlg_confirm.h b/src_plugins/lib_gtk_common/dlg_confirm.h
new file mode 100644
index 0000000..89a113b
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_confirm.h
@@ -0,0 +1,6 @@
+#include <stdarg.h>
+#include <gtk/gtk.h>
+
+int pcb_gtk_dlg_confirm_open(GtkWidget *top_window, const char *msg, va_list ap);
+int pcb_gtk_dlg_confirm_close(GtkWidget *top_window);
+
diff --git a/src_plugins/lib_gtk_common/dlg_export.c b/src_plugins/lib_gtk_common/dlg_export.c
new file mode 100644
index 0000000..a787c73
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_export.c
@@ -0,0 +1,105 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This file written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+#include "conf_core.h"
+#include "dlg_export.h"
+#include "dlg_print.h"
+#include <stdlib.h>
+
+#include "pcb-printf.h"
+#include "hid_attrib.h"
+#include "hid_init.h"
+#include "misc_util.h"
+#include "compat_misc.h"
+#include "compat_nls.h"
+
+static GtkWidget *export_dialog = NULL;
+static GtkWidget *export_top_win = NULL;
+
+
+static void exporter_clicked_cb(GtkButton * button, pcb_hid_t * exporter)
+{
+	ghid_dialog_print(exporter, export_dialog, export_top_win);
+}
+
+void ghid_dialog_export(GtkWidget *top_window)
+{
+	GtkWidget *content_area;
+	GtkWidget *vbox, *button;
+	int i;
+	pcb_hid_t **hids;
+	gboolean no_exporter = TRUE;
+
+	export_top_win = top_window;
+
+	export_dialog = gtk_dialog_new_with_buttons(_("PCB Export Layout"),
+																							GTK_WINDOW(top_window),
+																							(GtkDialogFlags) (GTK_DIALOG_MODAL
+																																|
+																																GTK_DIALOG_DESTROY_WITH_PARENT),
+																							GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+	gtk_window_set_wmclass(GTK_WINDOW(export_dialog), "PCB_Export", "PCB");
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(export_dialog));
+
+	vbox = gtk_vbox_new(FALSE, 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_add(GTK_CONTAINER(content_area), vbox);
+
+	/*
+	 * Iterate over all the export HID's and build up a dialog box that
+	 * lets us choose which one we want to use.
+	 * This way, any additions to the exporter HID's automatically are
+	 * reflected in this dialog box.
+	 */
+
+	hids = pcb_hid_enumerate();
+	for (i = 0; hids[i]; i++) {
+		if (hids[i]->exporter) {
+			no_exporter = FALSE;
+			button = gtk_button_new_with_label(hids[i]->name);
+			gtk_widget_set_tooltip_text(button, hids[i]->description);
+			gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+			g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(exporter_clicked_cb), hids[i]);
+		}
+	}
+
+	if (no_exporter) {
+		GtkWidget *label;
+		label = gtk_label_new("No exporter found. Check your plugins!");
+			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+	}
+
+	gtk_widget_show_all(export_dialog);
+	gtk_dialog_run(GTK_DIALOG(export_dialog));
+
+	if (export_dialog != NULL)
+		gtk_widget_destroy(export_dialog);
+	export_dialog = NULL;
+}
diff --git a/src_plugins/lib_gtk_common/dlg_export.h b/src_plugins/lib_gtk_common/dlg_export.h
new file mode 100644
index 0000000..d34d631
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_export.h
@@ -0,0 +1,7 @@
+#include <gtk/gtk.h>
+#include "hid.h"
+
+void ghid_dialog_export(GtkWidget *top_window);
+
+
+
diff --git a/src_plugins/lib_gtk_common/dlg_file_chooser.c b/src_plugins/lib_gtk_common/dlg_file_chooser.c
new file mode 100644
index 0000000..81732a2
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_file_chooser.c
@@ -0,0 +1,453 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This code was originally written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+
+#include "board.h"
+#include "hid.h"
+#include "compat_misc.h"
+
+#include "dlg_file_chooser.h"
+
+/* ---------------------------------------------- */
+/* Caller must g_free() the returned filename.*/
+gchar *ghid_dialog_file_select_open(GtkWidget *top_window, const gchar *title, gchar **path, const gchar *shortcuts)
+{
+	GtkWidget *dialog;
+	gchar *result = NULL, *folder, *seed;
+	GtkFileFilter *no_filter, *any_filter;
+
+	dialog = gtk_file_chooser_dialog_new(title,
+																			 GTK_WINDOW(top_window),
+																			 GTK_FILE_CHOOSER_ACTION_OPEN,
+																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+
+	/* add a default filter for not filtering files */
+	no_filter = gtk_file_filter_new();
+	gtk_file_filter_set_name(no_filter, "all");
+	gtk_file_filter_add_pattern(no_filter, "*.*");
+	gtk_file_filter_add_pattern(no_filter, "*");
+	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), no_filter);
+
+	any_filter = gtk_file_filter_new();
+	gtk_file_filter_set_name(any_filter, "any known format");
+	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), any_filter);
+
+
+	/* in case we have a dialog for loading a footprint file */
+	if (strcmp(title, _("Load element to buffer")) == 0) {
+		/* add a filter for footprint files */
+		GtkFileFilter *fp_filter;
+		fp_filter = gtk_file_filter_new();
+		gtk_file_filter_set_name(fp_filter, "fp");
+		gtk_file_filter_add_mime_type(fp_filter, "application/x-pcb-footprint");
+		gtk_file_filter_add_pattern(fp_filter, "*.fp");
+		gtk_file_filter_add_pattern(fp_filter, "*.FP");
+		gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), fp_filter);
+	}
+
+	/* in case we have a dialog for loading a layout file */
+	if ((strcmp(title, _("Load layout file")) == 0)
+			|| (strcmp(title, _("Load layout file to buffer")) == 0)) {
+		/* add a filter for layout files */
+		pcb_io_formats_t fmts;
+		int n, num_fmts = pcb_io_list(&fmts, PCB_IOT_PCB, 0, 0, PCB_IOL_EXT_BOARD);
+		for (n = 0; n < num_fmts; n++) {
+			int i;
+			char *ext;
+			GtkFileFilter *filter;
+
+			/* register each short name only once - slow O(N^2), but we don't have too many formats anyway */
+			for (i = 0; i < n; i++)
+				if (strcmp(fmts.plug[n]->default_fmt, fmts.plug[i]->default_fmt) == 0)
+					goto next_fmt;
+
+			filter = gtk_file_filter_new();
+			gtk_file_filter_set_name(filter, fmts.plug[n]->default_fmt);
+			if (fmts.plug[n]->mime_type != NULL) {
+				gtk_file_filter_add_mime_type(filter, fmts.plug[n]->mime_type);
+				gtk_file_filter_add_mime_type(any_filter, fmts.plug[n]->mime_type);
+			}
+			if (fmts.plug[n]->default_extension != NULL) {
+				char *s;
+				ext = pcb_concat("*", fmts.plug[n]->default_extension, NULL);
+				gtk_file_filter_add_pattern(filter, ext);
+				gtk_file_filter_add_pattern(any_filter, ext);
+				for (s = ext; *s != '\0'; s++)
+					*s = toupper(*s);
+				gtk_file_filter_add_pattern(filter, ext);
+				gtk_file_filter_add_pattern(any_filter, ext);
+				free(ext);
+			}
+			gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
+		next_fmt:;
+		}
+		pcb_io_list_free(&fmts);
+	}
+
+	/* in case we have a dialog for loading a netlist file */
+	if (strcmp(title, _("Load netlist file")) == 0) {
+		/* add a filter for netlist files */
+		GtkFileFilter *net_filter;
+		net_filter = gtk_file_filter_new();
+		gtk_file_filter_set_name(net_filter, "netlist");
+		gtk_file_filter_add_mime_type(net_filter, "application/x-pcb-netlist");
+		gtk_file_filter_add_pattern(net_filter, "*.net");
+		gtk_file_filter_add_pattern(net_filter, "*.NET");
+		gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), net_filter);
+	}
+
+	if (path && *path)
+		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), *path);
+
+	if (shortcuts && *shortcuts) {
+		folder = g_strdup(shortcuts);
+		seed = folder;
+		while ((folder = strtok(seed, ":")) != NULL) {
+			gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(dialog), folder, NULL);
+			seed = NULL;
+		}
+		g_free(folder);
+	}
+
+	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
+		result = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+		folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
+		if (folder && path) {
+			pcb_gtk_g_strdup(path, folder);
+			g_free(folder);
+		}
+	}
+	gtk_widget_destroy(dialog);
+
+
+	return result;
+}
+
+
+/* Callback to change the file name in the "save as" dialog according to
+   format selection */
+typedef struct {
+	GtkWidget *dialog;
+	const char **formats, **extensions;
+} ghid_save_ctx_t;
+
+static void fmt_changed_cb(GtkWidget * combo_box, ghid_save_ctx_t * ctx)
+{
+	char *fn, *s, *bn;
+	const char *ext;
+	gint active;
+
+	if (ctx->extensions == NULL)
+		return;
+
+	active = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
+	if (active < 0)
+		return;
+
+	fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ctx->dialog));
+	if (fn == NULL)
+		return;
+
+	/* find and truncate extension */
+	for (s = fn + strlen(fn) - 1; *s != '.'; s--) {
+		if ((s <= fn) || (*s == '/') || (*s == '\\')) {
+			g_free(fn);
+			return;
+		}
+	}
+	*s = '\0';
+
+	/* calculate basename in bn */
+	bn = strrchr(fn, '/');
+	if (bn == NULL) {
+		bn = strrchr(fn, '\\');
+		if (bn == NULL)
+			bn = fn;
+		else
+			bn++;
+	}
+	else
+		bn++;
+
+	/* fetch the desired extension */
+	ext = ctx->extensions[active];
+	if (ext == NULL)
+		ext = ".";
+
+	/* build a new file name with the right extension */
+	s = pcb_concat(bn, ext, NULL);
+	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ctx->dialog), s);
+
+	free(s);
+	g_free(fn);
+}
+
+/* ---------------------------------------------- */
+/* Caller must g_free() the returned filename. */
+gchar *ghid_dialog_file_select_save(GtkWidget *top_window, const gchar *title, gchar **path, const gchar *file, const gchar *shortcuts, const char **formats, const char **extensions, int *format)
+{
+	GtkWidget *fmt, *tmp, *fmt_combo;
+	gchar *result = NULL, *folder, *seed;
+	ghid_save_ctx_t ctx;
+
+	ctx.formats = formats;
+	ctx.extensions = extensions;
+	ctx.dialog = gtk_file_chooser_dialog_new(title,
+																					 GTK_WINDOW(top_window),
+																					 GTK_FILE_CHOOSER_ACTION_SAVE,
+																					 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(ctx.dialog), TRUE);
+	gtk_dialog_set_default_response(GTK_DIALOG(ctx.dialog), GTK_RESPONSE_OK);
+
+	/* Create and add the file format widget */
+	if (format != NULL) {
+		const char **s;
+		fmt = gtk_hbox_new(FALSE, 0);
+
+		tmp = gtk_vbox_new(FALSE, 0);
+		gtk_box_pack_start(GTK_BOX(fmt), tmp, TRUE, TRUE, 0);
+
+		tmp = gtk_label_new("File format: ");
+		gtk_box_pack_start(GTK_BOX(fmt), tmp, FALSE, FALSE, 0);
+
+		fmt_combo = gtk_combo_box_new_text();
+		gtk_box_pack_start(GTK_BOX(fmt), fmt_combo, FALSE, FALSE, 0);
+
+		for (s = formats; *s != NULL; s++)
+			gtk_combo_box_append_text(GTK_COMBO_BOX(fmt_combo), *s);
+
+		gtk_combo_box_set_active(GTK_COMBO_BOX(fmt_combo), *format);
+		g_signal_connect(G_OBJECT(fmt_combo), "changed", G_CALLBACK(fmt_changed_cb), &ctx);
+
+		gtk_widget_show_all(fmt);
+		gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(ctx.dialog), fmt);
+	}
+
+	if (path && *path && **path)
+		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ctx.dialog), *path);
+
+	if (file && *file) {
+		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ctx.dialog), g_path_get_basename(file));
+		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ctx.dialog), g_path_get_dirname(file));
+	}
+
+	if (shortcuts && *shortcuts) {
+		folder = g_strdup(shortcuts);
+		seed = folder;
+		while ((folder = strtok(seed, ":")) != NULL) {
+			gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(ctx.dialog), folder, NULL);
+			seed = NULL;
+		}
+		g_free(folder);
+	}
+	if (gtk_dialog_run(GTK_DIALOG(ctx.dialog)) == GTK_RESPONSE_OK) {
+		result = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ctx.dialog));
+		folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(ctx.dialog));
+		if (folder && path) {
+			pcb_gtk_g_strdup(path, folder);
+			g_free(folder);
+		}
+	}
+
+	if (format != NULL)
+		*format = gtk_combo_box_get_active(GTK_COMBO_BOX(fmt_combo));
+
+	gtk_widget_destroy(ctx.dialog);
+
+	return result;
+}
+
+
+/* ---------------------------------------------- */
+/* how many files and directories to keep for the shortcuts */
+#define NHIST 8
+typedef struct ghid_file_history_struct {
+	/*
+	 * an identifier as to which recent files pool this is.  For example
+	 * "boards", "eco", "netlists", etc.
+	 */
+	char *id;
+
+	/*
+	 * the array of files or directories
+	 */
+	char *history[NHIST];
+} ghid_file_history;
+
+static int n_recent_dirs = 0;
+static ghid_file_history *recent_dirs = NULL;
+
+/* ---------------------------------------------- */
+/* Caller must g_free() the returned filename. */
+gchar *pcb_gtk_fileselect(GtkWidget *top_window, const char *title, const char *descr, const char *default_file, const char *default_ext, const char *history_tag, int flags)
+{
+	GtkWidget *dialog;
+	gchar *result = NULL;
+	gchar *path = NULL, *base = NULL;
+	int history_pool = -1;
+	int i;
+
+	if (history_tag && *history_tag) {
+		/*
+		 * I used a simple linear search here because the number of
+		 * entries in the array is likely to be quite small (5, maybe 10 at
+		 * the absolute most) and this function is used when pulling up
+		 * a file dialog box instead of something called over and over
+		 * again as part of moving elements or autorouting.  So, keep it
+		 * simple....
+		 */
+		history_pool = 0;
+		while (history_pool < n_recent_dirs && strcmp(recent_dirs[history_pool].id, history_tag) != 0) {
+			history_pool++;
+		}
+
+		/*
+		 * If we counted all the way to n_recent_dirs, that means we
+		 * didn't find our entry
+		 */
+		if (history_pool >= n_recent_dirs) {
+			n_recent_dirs++;
+
+			recent_dirs = (ghid_file_history *) realloc(recent_dirs, n_recent_dirs * sizeof(ghid_file_history));
+
+			if (recent_dirs == NULL) {
+				fprintf(stderr, "ghid_fileselect():  realloc failed\n");
+				exit(1);
+			}
+
+			recent_dirs[history_pool].id = pcb_strdup(history_tag);
+
+			/* Initialize the entries in our history list to all be NULL */
+			for (i = 0; i < NHIST; i++) {
+				recent_dirs[history_pool].history[i] = NULL;
+			}
+		}
+	}
+
+	if (default_file && *default_file) {
+		path = g_path_get_dirname(default_file);
+		base = g_path_get_basename(default_file);
+	}
+
+	dialog = gtk_file_chooser_dialog_new(title,
+																			 GTK_WINDOW(top_window),
+																			 (flags & HID_FILESELECT_READ) ?
+																			 GTK_FILE_CHOOSER_ACTION_OPEN :
+																			 GTK_FILE_CHOOSER_ACTION_SAVE,
+																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+
+	if (path && *path) {
+		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
+		g_free(path);
+	}
+
+	if (base && *base) {
+		/* default file is only supposed to be for writing, not reading */
+		if (!(flags & HID_FILESELECT_READ)) {
+			gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), base);
+		}
+		g_free(base);
+	}
+
+	for (i = 0; i < NHIST && recent_dirs[history_pool].history[i] != NULL; i++) {
+		gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(dialog), recent_dirs[history_pool].history[i], NULL);
+	}
+
+	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
+		result = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+		if (result != NULL)
+			path = g_path_get_dirname(result);
+		else
+			path = NULL;
+
+		/* update the history list */
+		if (path != NULL) {
+			char *tmps, *tmps2;
+			int k = 0;
+
+			/*
+			 * Put this at the top of the list and bump everything else
+			 * down but skip any old entry of this directory
+			 *
+			 */
+			while (k < NHIST &&
+						 recent_dirs[history_pool].history[k] != NULL && strcmp(recent_dirs[history_pool].history[k], path) == 0) {
+				k++;
+			}
+			tmps = recent_dirs[history_pool].history[k];
+			recent_dirs[history_pool].history[0] = path;
+			for (i = 1; i < NHIST; i++) {
+				/* store our current entry, but skip duplicates */
+				while (i + k < NHIST &&
+							 recent_dirs[history_pool].history[i + k] != NULL &&
+							 strcmp(recent_dirs[history_pool].history[i + k], path) == 0) {
+					k++;
+				}
+
+				if (i + k < NHIST)
+					tmps2 = recent_dirs[history_pool].history[i + k];
+				else
+					tmps2 = NULL;
+
+				/* move down the one we stored last time */
+				recent_dirs[history_pool].history[i] = tmps;
+
+				/* and remember the displace entry */
+				tmps = tmps2;
+			}
+
+			/*
+			 * the last one has fallen off the end of the history list
+			 * so we need to free() it.
+			 */
+			if (tmps) {
+				free(tmps);
+			}
+		}
+
+#ifdef DEBUG
+		printf("\n\n-----\n\n");
+		for (i = 0; i < NHIST; i++) {
+			printf("After update recent_dirs[%d].history[%d] = \"%s\"\n",
+						 history_pool, i, recent_dirs[history_pool].history[i] != NULL ? recent_dirs[history_pool].history[i] : "NULL");
+		}
+#endif
+
+	}
+	gtk_widget_destroy(dialog);
+
+
+	return result;
+}
diff --git a/src_plugins/lib_gtk_common/dlg_file_chooser.h b/src_plugins/lib_gtk_common/dlg_file_chooser.h
new file mode 100644
index 0000000..47ed445
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_file_chooser.h
@@ -0,0 +1,12 @@
+#include <gtk/gtk.h>
+
+#include "compat_nls.h"
+#include "plug_io.h"
+
+#include "util_str.h"
+
+gchar *ghid_dialog_file_select_open(GtkWidget *top_window, const gchar *title, gchar **path, const gchar *shortcuts);
+
+gchar *ghid_dialog_file_select_save(GtkWidget *top_window, const gchar *title, gchar **path, const gchar *file, const gchar *shortcuts, const char **formats, const char **extensions, int *format);
+
+gchar *pcb_gtk_fileselect(GtkWidget *top_window, const char *title, const char *descr, const char *default_file, const char *default_ext, const char *history_tag, int flags);
diff --git a/src_plugins/lib_gtk_common/dlg_input.c b/src_plugins/lib_gtk_common/dlg_input.c
new file mode 100644
index 0000000..f605021
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_input.c
@@ -0,0 +1,81 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This code was originally written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+
+#include "dlg_input.h"
+
+/** ghid_dialog_input:
+ *  Display a new GtkDialog to let user enter some data.
+ */
+gchar *pcb_gtk_dlg_input(const char *prompt, const char *initial, GtkWindow * parent)
+{
+	GtkWidget *dialog;
+	GtkWidget *content_area;
+	GtkWidget *vbox, *label, *entry;
+	gchar *string;
+	gboolean response;
+	/*GHidPort *out = &ghid_port; */
+
+	dialog = gtk_dialog_new_with_buttons("PCB User Input",
+																			 /*GTK_WINDOW(out->top_window), */
+																			 parent,
+																			 GTK_DIALOG_MODAL,
+																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+	/* Change to gtkc_vbox_new here */
+	vbox = gtk_vbox_new(FALSE, 4);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
+	label = gtk_label_new("");
+	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
+
+	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+	gtk_label_set_markup(GTK_LABEL(label), prompt ? prompt : "Enter something");
+
+	entry = gtk_entry_new();
+	if (initial)
+		gtk_entry_set_text(GTK_ENTRY(entry), initial);
+
+	gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+	gtk_box_pack_start(GTK_BOX(vbox), entry, TRUE, TRUE, 0);
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+	gtk_container_add(GTK_CONTAINER(content_area), vbox);
+	gtk_widget_show_all(dialog);
+
+	response = gtk_dialog_run(GTK_DIALOG(dialog));
+	if (response != GTK_RESPONSE_OK)
+		string = g_strdup(initial ? initial : "");
+	else
+		string = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
+
+	gtk_widget_destroy(dialog);
+	return string;
+}
diff --git a/src_plugins/lib_gtk_common/dlg_input.h b/src_plugins/lib_gtk_common/dlg_input.h
new file mode 100644
index 0000000..e957dc5
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_input.h
@@ -0,0 +1,3 @@
+#include <gtk/gtk.h>
+
+gchar *pcb_gtk_dlg_input(const char *prompt, const char *initial, GtkWindow *parent);
diff --git a/src_plugins/lib_gtk_common/dlg_message.c b/src_plugins/lib_gtk_common/dlg_message.c
new file mode 100644
index 0000000..eb70b76
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_message.c
@@ -0,0 +1,58 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+#include "config.h"
+
+#include "dlg_message.h"
+#include "compat_nls.h"
+
+/** pcb_gtk_dlg_message:
+ *  Display a new GtkMessageDialog ...
+ *  FIXME. : A generic dialog + a specific to "confirm close, save, ..."
+ *  FIXME: find a way to get rid of _("Close _without saving")
+ */
+gint pcb_gtk_dlg_message(const char *message, GtkWindow * parent)
+{
+	GtkWidget *dialog;
+	gint rv;
+
+	dialog = gtk_message_dialog_new(parent,
+																	(GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
+																	GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, NULL);
+	gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), message);
+	gtk_dialog_add_buttons(GTK_DIALOG(dialog),
+												 _("Close _without saving"), GTK_RESPONSE_NO,
+												 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_YES, NULL);
+
+	/* Set the alternative button order (ok, cancel, help) for other systems */
+	gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_YES, GTK_RESPONSE_NO, GTK_RESPONSE_CANCEL, -1);
+
+	rv = gtk_dialog_run(GTK_DIALOG(dialog));
+
+	gtk_widget_destroy(dialog);
+	return rv;
+}
diff --git a/src_plugins/lib_gtk_common/dlg_message.h b/src_plugins/lib_gtk_common/dlg_message.h
new file mode 100644
index 0000000..531ae9d
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_message.h
@@ -0,0 +1,3 @@
+#include <gtk/gtk.h>
+
+gint pcb_gtk_dlg_message(const char *message, GtkWindow * parent);
diff --git a/src_plugins/lib_gtk_common/dlg_pinout.c b/src_plugins/lib_gtk_common/dlg_pinout.c
new file mode 100644
index 0000000..a59f4ad
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_pinout.c
@@ -0,0 +1,88 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This file written by Bill Wilson for the PCB Gtk port */
+
+#include "config.h"
+#include "dlg_pinout.h"
+
+#include "conf_core.h"
+#include "copy.h"
+#include "data.h"
+#include "draw.h"
+#include "move.h"
+#include "rotate.h"
+#include "macro.h"
+
+#include "wt_preview.h"
+#include "win_place.h"
+
+static void pinout_close_cb(GtkWidget * widget, GtkWidget * top_window)
+{
+	gtk_widget_destroy(top_window);
+}
+
+
+void ghid_pinout_window_show(void *gport, pcb_element_t *element)
+{
+	GtkWidget *button, *vbox, *hbox, *preview, *top_window;
+	gchar *title;
+	int width, height;
+
+	if (!element)
+		return;
+	title = g_strdup_printf("%s [%s,%s]",
+													PCB_UNKNOWN(PCB_ELEM_NAME_DESCRIPTION(element)), PCB_UNKNOWN(PCB_ELEM_NAME_REFDES(element)), PCB_UNKNOWN(PCB_ELEM_NAME_VALUE(element)));
+
+	top_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_title(GTK_WINDOW(top_window), title);
+	g_free(title);
+	gtk_window_set_wmclass(GTK_WINDOW(top_window), "PCB_Pinout", "PCB");
+	gtk_container_set_border_width(GTK_CONTAINER(top_window), 4);
+
+	vbox = gtk_vbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(top_window), vbox);
+
+
+	preview = pcb_gtk_preview_pinout_new(gport, ghid_init_drawing_widget, ghid_preview_expose, element);
+
+	gtk_box_pack_start(GTK_BOX(vbox), preview, TRUE, TRUE, 0);
+
+	pcb_gtk_preview_get_natsize(GHID_PINOUT_PREVIEW(preview), &width, &height);
+
+	gtk_window_set_default_size(GTK_WINDOW(top_window), width + 50, height + 50);
+
+	hbox = gtk_hbutton_box_new();
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pinout_close_cb), top_window);
+	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
+
+	gtk_widget_realize(top_window);
+	wplc_place(WPLC_PINOUT, top_window);
+	gtk_widget_show_all(top_window);
+}
diff --git a/src_plugins/lib_gtk_common/dlg_pinout.h b/src_plugins/lib_gtk_common/dlg_pinout.h
new file mode 100644
index 0000000..17ce485
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_pinout.h
@@ -0,0 +1,10 @@
+#include <gtk/gtk.h>
+#include "obj_elem.h"
+#include "hid.h"
+
+void ghid_pinout_window_show(void *gport, pcb_element_t *element);
+
+/* glue from hid_gtk: */
+extern void ghid_init_drawing_widget(GtkWidget *widget, void *gport);
+extern gboolean ghid_preview_expose(GtkWidget * widget, GdkEventExpose * ev, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx);
+
diff --git a/src_plugins/lib_gtk_common/dlg_print.c b/src_plugins/lib_gtk_common/dlg_print.c
new file mode 100644
index 0000000..617cf46
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_print.c
@@ -0,0 +1,81 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This file written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+#include "conf_core.h"
+#include "dlg_print.h"
+#include <stdlib.h>
+
+#include "pcb-printf.h"
+#include "hid_attrib.h"
+#include "hid_init.h"
+#include "misc_util.h"
+#include "compat_misc.h"
+#include "compat_nls.h"
+#include "dlg_attribute.h"
+
+void ghid_dialog_print(pcb_hid_t * hid, GtkWidget *export_dialog, GtkWidget *top_window)
+{
+	pcb_hid_attribute_t *attr;
+	int n = 0;
+	int i;
+	pcb_hid_attr_val_t *results = NULL;
+
+	/* signal the initial export select dialog that it should close */
+	if (export_dialog)
+		gtk_dialog_response(GTK_DIALOG(export_dialog), GTK_RESPONSE_CANCEL);
+
+	pcb_exporter = hid;
+
+	attr = pcb_exporter->get_export_options(&n);
+	if (n > 0) {
+		results = (pcb_hid_attr_val_t *) malloc(n * sizeof(pcb_hid_attr_val_t));
+		if (results == NULL) {
+			fprintf(stderr, "ghid_dialog_print() -- malloc failed\n");
+			exit(1);
+		}
+
+		/* non-zero means cancel was picked */
+		if (ghid_attribute_dialog(top_window, attr, n, results, _("PCB Print Layout"), pcb_exporter->description))
+			return;
+
+	}
+
+	pcb_exporter->do_export(results);
+
+	for (i = 0; i < n; i++) {
+		if (results[i].str_value)
+			free((void *) results[i].str_value);
+	}
+
+	if (results)
+		free(results);
+
+	pcb_exporter = NULL;
+}
+
diff --git a/src_plugins/lib_gtk_common/dlg_print.h b/src_plugins/lib_gtk_common/dlg_print.h
new file mode 100644
index 0000000..7a5baff
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_print.h
@@ -0,0 +1,5 @@
+#include <gtk/gtk.h>
+#include "hid.h"
+
+void ghid_dialog_print(pcb_hid_t * hid, GtkWidget *export_dialog, GtkWidget *top_window);
+
diff --git a/src_plugins/lib_gtk_common/dlg_progress.c b/src_plugins/lib_gtk_common/dlg_progress.c
new file mode 100644
index 0000000..4fc22b3
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_progress.c
@@ -0,0 +1,187 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+#include "dlg_progress.h"
+
+#include "pcb_bool.h"
+#include "compat_nls.h"
+
+struct progress_dialog {
+	GtkWidget *dialog;
+	GtkWidget *message;
+	GtkWidget *progress;
+	gint response_id;
+	GMainLoop *loop;
+	gboolean destroyed;
+	gboolean started;
+	GTimer *timer;
+
+	gulong response_handler;
+	gulong destroy_handler;
+	gulong delete_handler;
+};
+
+static void run_response_handler(GtkDialog * dialog, gint response_id, gpointer data)
+{
+	struct progress_dialog *pd = data;
+
+	pd->response_id = response_id;
+}
+
+static gint run_delete_handler(GtkDialog * dialog, GdkEventAny * event, gpointer data)
+{
+	struct progress_dialog *pd = data;
+
+	pd->response_id = GTK_RESPONSE_DELETE_EVENT;
+
+	return TRUE;									/* Do not destroy */
+}
+
+static void run_destroy_handler(GtkDialog * dialog, gpointer data)
+{
+	struct progress_dialog *pd = data;
+
+	pd->destroyed = TRUE;
+}
+
+static struct progress_dialog *make_progress_dialog(GtkWidget *top_window)
+{
+	struct progress_dialog *pd;
+	GtkWidget *content_area;
+	GtkWidget *alignment;
+	GtkWidget *vbox;
+
+	pd = g_new0(struct progress_dialog, 1);
+	pd->response_id = GTK_RESPONSE_NONE;
+
+	pd->dialog = gtk_dialog_new_with_buttons(_("Progress"), GTK_WINDOW(top_window),
+																					 /* Modal so nothing else can get events whilst
+																					    the main mainloop isn't running */
+																					 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+																					 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+
+	gtk_window_set_deletable(GTK_WINDOW(pd->dialog), FALSE);
+	gtk_window_set_skip_pager_hint(GTK_WINDOW(pd->dialog), TRUE);
+	gtk_window_set_skip_taskbar_hint(GTK_WINDOW(pd->dialog), TRUE);
+	gtk_widget_set_size_request(pd->dialog, 300, -1);
+
+	pd->message = gtk_label_new(NULL);
+	gtk_misc_set_alignment(GTK_MISC(pd->message), 0., 0.);
+
+	pd->progress = gtk_progress_bar_new();
+	gtk_widget_set_size_request(pd->progress, -1, 26);
+
+	vbox = gtk_vbox_new(pcb_false, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), pd->message, pcb_true, pcb_true, 8);
+	gtk_box_pack_start(GTK_BOX(vbox), pd->progress, pcb_false, pcb_true, 8);
+
+	alignment = gtk_alignment_new(0., 0., 1., 1.);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 8, 8, 8, 8);
+	gtk_container_add(GTK_CONTAINER(alignment), vbox);
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(pd->dialog));
+	gtk_box_pack_start(GTK_BOX(content_area), alignment, pcb_true, pcb_true, 0);
+
+	gtk_widget_show_all(alignment);
+
+	g_object_ref(pd->dialog);
+	gtk_window_present(GTK_WINDOW(pd->dialog));
+
+	pd->response_handler = g_signal_connect(pd->dialog, "response", G_CALLBACK(run_response_handler), pd);
+	pd->delete_handler = g_signal_connect(pd->dialog, "delete-event", G_CALLBACK(run_delete_handler), pd);
+	pd->destroy_handler = g_signal_connect(pd->dialog, "destroy", G_CALLBACK(run_destroy_handler), pd);
+
+	pd->loop = g_main_loop_new(NULL, FALSE);
+	pd->timer = g_timer_new();
+
+	return pd;
+}
+
+static void destroy_progress_dialog(struct progress_dialog *pd)
+{
+	if (pd == NULL)
+		return;
+
+	if (!pd->destroyed) {
+		g_signal_handler_disconnect(pd->dialog, pd->response_handler);
+		g_signal_handler_disconnect(pd->dialog, pd->delete_handler);
+		g_signal_handler_disconnect(pd->dialog, pd->destroy_handler);
+	}
+
+	g_timer_destroy(pd->timer);
+	g_object_unref(pd->dialog);
+	g_main_loop_unref(pd->loop);
+
+	gtk_widget_destroy(pd->dialog);
+
+	pd->loop = NULL;
+	g_free(pd);
+}
+
+static void handle_progress_dialog_events(struct progress_dialog *pd)
+{
+	GMainContext *context = g_main_loop_get_context(pd->loop);
+
+	/* Process events */
+	while (g_main_context_pending(context)) {
+		g_main_context_iteration(context, FALSE);
+	}
+}
+
+#define MIN_TIME_SEPARATION (50./1000.)	/* 50ms */
+int pcb_gtk_dlg_progress(GtkWidget *top_window, int so_far, int total, const char *message)
+{
+	static struct progress_dialog *pd = NULL;
+
+	/* If we are finished, destroy any dialog */
+	if (so_far == 0 && total == 0 && message == NULL) {
+		destroy_progress_dialog(pd);
+		pd = NULL;
+		return 0;
+	}
+
+	if (pd == NULL)
+		pd = make_progress_dialog(top_window);
+
+	/* We don't want to keep the underlying process too busy whilst we
+	 * process events. If we get called quickly after the last progress
+	 * update, wait a little bit before we respond - perhaps the next
+	 * time progress is reported.
+
+	 * The exception here is that we always want to process the first
+	 * batch of events after having shown the dialog for the first time
+	 */
+	if (pd->started && g_timer_elapsed(pd->timer, NULL) < MIN_TIME_SEPARATION)
+		return 0;
+
+	gtk_label_set_text(GTK_LABEL(pd->message), message);
+	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pd->progress), (double) so_far / (double) total);
+
+	handle_progress_dialog_events(pd);
+	g_timer_start(pd->timer);
+
+	pd->started = TRUE;
+
+	return (pd->response_id == GTK_RESPONSE_CANCEL || pd->response_id == GTK_RESPONSE_DELETE_EVENT) ? 1 : 0;
+}
diff --git a/src_plugins/lib_gtk_common/dlg_progress.h b/src_plugins/lib_gtk_common/dlg_progress.h
new file mode 100644
index 0000000..6b0c646
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_progress.h
@@ -0,0 +1,3 @@
+#include <gtk/gtk.h>
+
+int pcb_gtk_dlg_progress(GtkWidget *top_window, int so_far, int total, const char *message);
diff --git a/src_plugins/lib_gtk_common/dlg_propedit.c b/src_plugins/lib_gtk_common/dlg_propedit.c
new file mode 100644
index 0000000..03960bf
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_propedit.c
@@ -0,0 +1,564 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
+ *  Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* object property edit dialog */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "config.h"
+
+#include "dlg_propedit.h"
+
+#include "compat_misc.h"
+#include "compat_nls.h"
+#include "polygon.h"
+#include "obj_all.h"
+#include "board.h"
+#include "data.h"
+#include "conf_core.h"
+#include "buffer.h"
+
+#include "bu_box.h"
+#include "compat.h"
+
+static char *str_sub(const char *val, char sepi, char sepo)
+{
+	char *tmp, *sep;
+	tmp = pcb_strdup(val);
+	sep = strchr(tmp, sepi);
+	if (sep != NULL)
+		*sep = sepo;
+	return tmp;
+}
+
+static void val_combo_changed_cb(GtkComboBox * combo, pcb_gtk_dlg_propedit_t * dlg)
+{
+	char *cval, *tmp;
+	GtkTreeIter iter;
+	if (gtk_combo_box_get_active_iter(combo, &iter)) {
+		gtk_tree_model_get(GTK_TREE_MODEL(dlg->vals), &iter, 0, &cval, -1);
+		dlg->stock_val = 1;
+		tmp = str_sub(cval, '=', '\0');
+		gtk_entry_set_text(GTK_ENTRY(dlg->entry_val), tmp);
+		free(tmp);
+	}
+}
+
+static void val_entry_changed_cb(GtkWidget * entry, pcb_gtk_dlg_propedit_t * dlg)
+{
+	if (dlg->stock_val == 0)
+		gtk_combo_box_set_active(GTK_COMBO_BOX(dlg->val_box), -1);
+	else
+		dlg->stock_val = 0;
+}
+
+static void val_combo_reset(pcb_gtk_dlg_propedit_t * dlg)
+{
+	gtk_list_store_clear(dlg->vals);
+}
+
+static void val_combo_add(pcb_gtk_dlg_propedit_t * dlg, const char *val)
+{
+	gtk_list_store_insert_with_values(dlg->vals, NULL, -1, 0, val, -1);
+}
+
+#define NO0(s) pcb_strdup((s) == NULL ? "" : (s))
+void pcb_gtk_dlg_propedit_prop_add(pcb_gtk_dlg_propedit_t * dlg, const char *name, const char *common,
+																	 const char *min, const char *max, const char *avg)
+{
+	gtk_list_store_insert_with_values(dlg->props, &dlg->last_add_iter, -1, 0,
+																		pcb_strdup(name), 1, NO0(common), 2, NO0(min), 3, NO0(max), 4, NO0(avg), -1);
+	dlg->last_add_iter_valid = 1;
+}
+
+static void hdr_add(pcb_gtk_dlg_propedit_t * dlg, const char *name, int col)
+{
+	GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dlg->tree), -1, name, renderer, "text", col, NULL);
+}
+
+static void list_cursor_changed_cb(GtkWidget * tree, pcb_gtk_dlg_propedit_t * dlg)
+{
+	GtkTreeSelection *tsel;
+	GtkTreeModel *tm;
+	GtkTreeIter iter;
+	const char *prop, *comm, *val;
+	char *tmp;
+
+	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->tree));
+	if (tsel == NULL)
+		return;
+
+	gtk_tree_selection_get_selected(tsel, &tm, &iter);
+	if (iter.stamp == 0)
+		return;
+
+	gtk_tree_model_get(tm, &iter, 0, &prop, 1, &comm, -1);
+
+	printf("prop: %s!\n", prop);
+
+	val_combo_reset(dlg);
+
+	val = dlg->propedit_query(dlg->propedit_pe, "v1st", prop, NULL, 0);
+	while (val != NULL) {
+		tmp = str_sub(val, '\n', '=');
+		val_combo_add(dlg, tmp);
+		free(tmp);
+		val = dlg->propedit_query(dlg->propedit_pe, "vnxt", prop, NULL, 0);
+	}
+
+	tmp = str_sub(comm, '\n', '\0');
+	gtk_entry_set_text(GTK_ENTRY(dlg->entry_val), tmp);
+	free(tmp);
+}
+
+static void do_remove_cb(GtkWidget * tree, pcb_gtk_dlg_propedit_t * dlg)
+{
+	GtkTreeSelection *tsel;
+	GtkTreeModel *tm;
+	GtkTreeIter iter;
+	char *prop;
+
+	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->tree));
+	if (tsel == NULL)
+		return;
+
+	gtk_tree_selection_get_selected(tsel, &tm, &iter);
+	if (iter.stamp == 0)
+		return;
+
+	gtk_tree_model_get(tm, &iter, 0, &prop, -1);
+
+	if (dlg->propedit_query(dlg->propedit_pe, "vdel", prop, NULL, 0) != NULL)
+		gtk_list_store_remove(GTK_LIST_STORE(tm), &iter);
+
+	free(prop);
+}
+
+static int keyval_input(char **key, char **val, pcb_gtk_dlg_propedit_t * dlg)
+{
+	GtkWidget *dialog;
+	GtkWidget *content_area;
+	GtkWidget *vbox, *label, *kentry, *ventry;
+	gboolean response;
+
+	dialog = gtk_dialog_new_with_buttons("New attribute",
+																			 GTK_WINDOW(dlg->top_window),
+																			 GTK_DIALOG_MODAL,
+																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+	vbox = gtkc_vbox_new(FALSE, 4);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
+
+	label = gtk_label_new("");
+	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
+	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+	gtk_label_set_markup(GTK_LABEL(label), "Attribute key:");
+
+	kentry = gtk_entry_new();
+	gtk_entry_set_activates_default(GTK_ENTRY(kentry), TRUE);
+	gtk_box_pack_start(GTK_BOX(vbox), kentry, TRUE, TRUE, 0);
+
+	label = gtk_label_new("");
+	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
+	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+	gtk_label_set_markup(GTK_LABEL(label), "Attribute value:");
+
+	ventry = gtk_entry_new();
+	gtk_entry_set_activates_default(GTK_ENTRY(ventry), TRUE);
+	gtk_box_pack_start(GTK_BOX(vbox), ventry, TRUE, TRUE, 0);
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+	gtk_container_add(GTK_CONTAINER(content_area), vbox);
+	gtk_widget_show_all(dialog);
+
+	response = gtk_dialog_run(GTK_DIALOG(dialog));
+	if (response == GTK_RESPONSE_OK) {
+		*key = gtk_editable_get_chars(GTK_EDITABLE(kentry), 0, -1);
+		*val = gtk_editable_get_chars(GTK_EDITABLE(ventry), 0, -1);
+		gtk_widget_destroy(dialog);
+		return 1;
+	}
+
+	gtk_widget_destroy(dialog);
+	return 0;
+}
+
+static void do_addattr_cb(GtkWidget * tree, pcb_gtk_dlg_propedit_t * dlg)
+{
+	char *name, *value;
+
+	if (keyval_input(&name, &value, dlg)) {
+		char *path;
+		if ((name[0] == 'a') && (name[1] == '/')) {
+			path = name;
+			name = NULL;
+		}
+		else {
+			int len = strlen(name);
+			path = malloc(len + 3);
+			path[0] = 'a';
+			path[1] = '/';
+			strcpy(path + 2, name);
+		}
+		dlg->propedit_query(dlg->propedit_pe, "vset", path, value, 0);
+		free(path);
+		free(name);
+	}
+}
+
+static void do_apply_cb(GtkWidget * tree, pcb_gtk_dlg_propedit_t * dlg)
+{
+	GtkTreeSelection *tsel;
+	GtkTreeModel *tm;
+	GtkTreeIter iter;
+	char *prop, *val;
+	const char *typ;
+
+	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->tree));
+	if (tsel == NULL)
+		return;
+
+	gtk_tree_selection_get_selected(tsel, &tm, &iter);
+	if (iter.stamp == 0)
+		return;
+
+	gtk_tree_model_get(tm, &iter, 0, &prop, -1);
+
+	val = pcb_strdup(gtk_entry_get_text(GTK_ENTRY(dlg->entry_val)));
+
+	typ = dlg->propedit_query(dlg->propedit_pe, "type", prop, NULL, 0);
+	if (typ != NULL) {
+		if (*typ == 'c') {					/* if type of the field if coords, we may need to fix missing units */
+			char *end;
+			strtod(val, &end);
+			while (isspace(*end))
+				end++;
+			if (*end == '\0') {				/* no unit - automatically append current default */
+				int len = strlen(val);
+				char *new_val;
+				new_val = malloc(len + 32);
+				strcpy(new_val, val);
+				sprintf(new_val + len, " %s", conf_core.editor.grid_unit->suffix);
+				free(val);
+				val = new_val;
+			}
+		}
+
+		if (dlg->propedit_query(dlg->propedit_pe, "vset", prop, val, 0) != NULL) {
+			/* could change values update the table - the new row is already added, remove the old */
+			gtk_list_store_remove(GTK_LIST_STORE(tm), &iter);
+			if (dlg->last_add_iter_valid) {
+				gtk_tree_selection_select_iter(tsel, &dlg->last_add_iter);
+				dlg->last_add_iter_valid = 0;
+			}
+			/* get the combo box updated */
+			list_cursor_changed_cb(dlg->tree, dlg);
+			if ((*val == '+') || (*val == '-'))
+				gtk_entry_set_text(GTK_ENTRY(dlg->entry_val), val);	/* keep relative values intact for a reapply */
+		}
+		else
+			pcb_message(PCB_MSG_WARNING, "Failed to change any object - %s is possibly invalid value for %s\n", val, prop);
+	}
+	else
+		pcb_message(PCB_MSG_ERROR, "Internal error: no type for proeprty %s\n", prop);
+
+	free(val);
+	g_free(prop);
+}
+
+/* FIXME: GTK3 incompatible */
+static GdkPixmap *pm;
+static gboolean preview_expose_event(GtkWidget * w, GdkEventExpose * event)
+{
+	gdk_draw_drawable(w->window, w->style->fg_gc[gtk_widget_get_state(w)],
+										pm, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height);
+	return FALSE;
+}
+
+static pcb_board_t preview_pcb;
+
+static GtkWidget *preview_init(pcb_gtk_dlg_propedit_t * dlg)
+{
+	GtkWidget *area = gtk_drawing_area_new();
+	pcb_board_t *old_pcb;
+	int n, zoom1, fx, fy;
+	pcb_coord_t cx, cy;
+
+/*
+	void *v;
+	v = pcb_poly_new_from_rectangle(PCB->Data->Layer+1,
+		PCB_MIL_TO_COORD(0), PCB_MIL_TO_COORD(0),
+		PCB_MIL_TO_COORD(1500), PCB_MIL_TO_COORD(1500),
+		pcb_flag_make(PCB_FLAG_CLEARPOLY | PCB_FLAG_FULLPOLY));
+	printf("poly2=%p -----------\n", (void *)v);
+	DrawPolygon(PCB->Data->Layer+1, v);
+	pcb_draw();
+	gtk_drawing_area_size(GTK_DRAWING_AREA(area), 300, 400);
+	return;
+*/
+
+	memset(&preview_pcb, 0, sizeof(preview_pcb));
+	preview_pcb.Data = pcb_buffer_new();
+	preview_pcb.MaxWidth = preview_pcb.MaxHeight = PCB_MIL_TO_COORD(2000);
+	pcb_colors_from_settings(&preview_pcb);
+	pcb_font_create_default(&preview_pcb);
+	preview_pcb.ViaOn = 1;
+
+	for (n = 0; n < pcb_max_layer; n++) {
+		preview_pcb.Data->Layer[n].On = 1;
+		preview_pcb.Data->Layer[n].Color = pcb_strdup(PCB->Data->Layer[n].Color);
+		preview_pcb.Data->Layer[n].Name = pcb_strdup("preview dummy");
+	}
+
+	memcpy(&preview_pcb.LayerGroups, &PCB->LayerGroups, sizeof(PCB->LayerGroups));
+	preview_pcb.Data->LayerN = pcb_max_layer;
+	preview_pcb.Data->pcb = &preview_pcb;
+
+#warning TODO: preview_pcb is never freed
+
+	pcb_via_new(preview_pcb.Data,
+							PCB_MIL_TO_COORD(1000), PCB_MIL_TO_COORD(1000),
+							PCB_MIL_TO_COORD(50), PCB_MIL_TO_COORD(10), 0, PCB_MIL_TO_COORD(20), "", pcb_no_flags());
+
+	pcb_line_new(preview_pcb.Data->Layer + 0,
+							 PCB_MIL_TO_COORD(1000), PCB_MIL_TO_COORD(1000),
+							 PCB_MIL_TO_COORD(1000), PCB_MIL_TO_COORD(1300),
+							 PCB_MIL_TO_COORD(20), PCB_MIL_TO_COORD(20), pcb_flag_make(PCB_FLAG_CLEARLINE));
+
+	pcb_arc_new(preview_pcb.Data->Layer + 0,
+							PCB_MIL_TO_COORD(1000), PCB_MIL_TO_COORD(1000),
+							PCB_MIL_TO_COORD(100), PCB_MIL_TO_COORD(100),
+							0.0, 90.0, PCB_MIL_TO_COORD(20), PCB_MIL_TO_COORD(20), pcb_flag_make(PCB_FLAG_CLEARLINE));
+
+	pcb_text_new(preview_pcb.Data->Layer + 0, &PCB->Font,
+							 PCB_MIL_TO_COORD(850), PCB_MIL_TO_COORD(1150), 0, 100, "Text", pcb_flag_make(PCB_FLAG_CLEARLINE));
+
+	{
+		pcb_polygon_t *v = pcb_poly_new_from_rectangle(preview_pcb.Data->Layer,
+																									 PCB_MIL_TO_COORD(10), PCB_MIL_TO_COORD(10),
+																									 PCB_MIL_TO_COORD(1200), PCB_MIL_TO_COORD(1200),
+																									 pcb_flag_make(PCB_FLAG_CLEARPOLY));
+		pcb_poly_init_clip(preview_pcb.Data, preview_pcb.Data->Layer, v);
+	}
+
+	old_pcb = PCB;
+	PCB = &preview_pcb;
+
+	zoom1 = 1;
+	cx = PCB_MIL_TO_COORD(1000 + 300 / 2 * zoom1);
+	cy = PCB_MIL_TO_COORD(1000 + 400 / 2 * zoom1);
+	fx = conf_core.editor.view.flip_x;
+	fy = conf_core.editor.view.flip_y;
+	conf_set(CFR_DESIGN, "editor/view/flip_x", -1, "0", POL_OVERWRITE);
+	conf_set(CFR_DESIGN, "editor/view/flip_y", -1, "0", POL_OVERWRITE);
+	pm = ghid_render_pixmap(cx, cy, 40000 * zoom1, 300, 400, gdk_drawable_get_depth(GDK_DRAWABLE(dlg->top_window->window)));
+	conf_setf(CFR_DESIGN, "editor/view/flip_x", -1, "%d", fx, POL_OVERWRITE);
+	conf_setf(CFR_DESIGN, "editor/view/flip_y", -1, "%d", fy, POL_OVERWRITE);
+
+/*
+	{
+		GdkGC *gc = gdk_gc_new(GDK_DRAWABLE(gport->top_window->window));
+		GdkColor clr = {0, 0, 0, 0};
+		int x, y;
+		double zm = 40000 * zoom1;
+
+		gdk_gc_set_rgb_fg_color(gc, &clr);
+
+		x = (PCB_MIL_TO_COORD(1000) - cx) / zm + 0.5 + 200;
+		y = (PCB_MIL_TO_COORD(1000) - cy) / zm + 0.5 + 150;
+		gdk_draw_line(pm, gc, x, y, 0, 0);
+		gdk_draw_line(pm, gc, x+1, y+1, 1, 1);
+		gdk_draw_line(pm, gc, x-1, y-1, -1, -1);
+	}
+*/
+
+	PCB = old_pcb;
+
+	g_signal_connect(G_OBJECT(area), "expose-event", G_CALLBACK(preview_expose_event), pm);
+	return area;
+}
+
+/*static void sort_by_name(GtkTreeModel *liststore)
+{
+	GtkTreeSortable *sortable = GTK_TREE_SORTABLE(liststore);
+	gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING);
+}*/
+
+static gint sort_name_cmp(GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer userdata)
+{
+	gint sortcol = GPOINTER_TO_INT(userdata);
+	gint ret = 0;
+	gchar *name1, *name2;
+
+	if (sortcol != 0)
+		return 0;
+
+	gtk_tree_model_get(model, a, 0, &name1, -1);
+	gtk_tree_model_get(model, b, 0, &name2, -1);
+
+	if ((name1 == NULL) && (name2 == NULL))
+		return 0;
+
+	if (name1 == NULL)
+		ret = -1;
+	else if (name2 == NULL)
+		ret = 1;
+	else if ((*name1 == 'a') && (*name2 == 'p'))	/* force attributes to the bottom */
+		return 1;
+	else if ((*name1 == 'p') && (*name2 == 'a'))
+		return -1;
+	else
+		ret = strcmp(name1, name2);
+
+	g_free(name1);
+	g_free(name2);
+
+	return ret;
+}
+
+static void make_sortable(GtkTreeModel * liststore)
+{
+	GtkTreeSortable *sortable;
+
+	sortable = GTK_TREE_SORTABLE(liststore);
+	gtk_tree_sortable_set_sort_func(sortable, 0, sort_name_cmp, GINT_TO_POINTER(0), NULL);
+
+	gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING);
+}
+
+GtkWidget *pcb_gtk_dlg_propedit_create(pcb_gtk_dlg_propedit_t * dlg, GtkWidget * top_window)
+{
+	GtkWidget *window, *vbox_tree, *vbox_edit, *hbox_win, *label;
+	GtkWidget *hbx, *dummy, *box_val_edit, *preview;
+	GtkCellRenderer *renderer;
+	GtkWidget *content_area;
+
+	dlg->last_add_iter_valid = 0;
+	dlg->top_window = top_window;
+
+	/*window = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
+	window = gtk_dialog_new_with_buttons(_("Edit Properties"),
+																			 GTK_WINDOW(top_window),
+																			 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL);
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(window));
+
+	hbox_win = gtkc_hbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(content_area), hbox_win);
+
+	vbox_tree = gtkc_vbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(hbox_win), vbox_tree, TRUE, TRUE, 4);
+	vbox_edit = gtkc_vbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(hbox_win), vbox_edit, TRUE, TRUE, 4);
+
+/***** LEFT *****/
+
+	label = gtk_label_new("Properties");
+	gtk_box_pack_start(GTK_BOX(vbox_tree), label, FALSE, FALSE, 4);
+
+	dlg->tree = gtk_tree_view_new();
+	gtk_box_pack_start(GTK_BOX(vbox_tree), dlg->tree, FALSE, TRUE, 4);
+
+	GType ty[5];
+
+	int n;
+	for (n = 0; n < 5; n++)
+		ty[n] = G_TYPE_STRING;
+	dlg->props = gtk_list_store_newv(5, ty);
+	make_sortable((GtkTreeModel *) dlg->props);
+	gtk_tree_view_set_model(GTK_TREE_VIEW(dlg->tree), GTK_TREE_MODEL(dlg->props));
+
+	hdr_add(dlg, "property", 0);
+	hdr_add(dlg, "common", 1);
+	hdr_add(dlg, "min", 2);
+	hdr_add(dlg, "max", 3);
+	hdr_add(dlg, "avg", 4);
+
+	/* dummy box to eat up vertical space */
+	hbx = gtkc_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_tree), hbx, TRUE, TRUE, 4);
+
+	/* list manipulation */
+	hbx = gtkc_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_tree), hbx, FALSE, TRUE, 4);
+
+	dlg->remove = gtk_button_new_with_label("Remove attribute");
+	gtk_box_pack_start(GTK_BOX(hbx), dlg->remove, FALSE, TRUE, 4);
+	g_signal_connect(G_OBJECT(dlg->remove), "clicked", G_CALLBACK(do_remove_cb), dlg);
+
+	dlg->addattr = gtk_button_new_with_label("Add attribute");
+	gtk_box_pack_start(GTK_BOX(hbx), dlg->addattr, FALSE, TRUE, 4);
+	g_signal_connect(G_OBJECT(dlg->addattr), "clicked", G_CALLBACK(do_addattr_cb), dlg);
+
+
+/***** RIGHT *****/
+/* preview */
+	preview = preview_init(dlg);
+	gtk_box_pack_start(GTK_BOX(vbox_edit), preview, TRUE, TRUE, 4);
+
+	label = gtk_label_new("Change property of all objects");
+	gtk_box_pack_start(GTK_BOX(vbox_edit), label, FALSE, TRUE, 4);
+
+	g_signal_connect(G_OBJECT(dlg->tree), "cursor-changed", G_CALLBACK(list_cursor_changed_cb), dlg);
+
+	/* value edit */
+	renderer = gtk_cell_renderer_text_new();
+
+	dlg->stock_val = 0;
+	dlg->vals = gtk_list_store_new(1, G_TYPE_STRING);
+	box_val_edit = gtkc_vbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_edit), box_val_edit, FALSE, TRUE, 4);
+
+	/* combo */
+	dlg->val_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(dlg->vals));
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dlg->val_box), renderer, TRUE);
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dlg->val_box), renderer, "text", 0, NULL);
+	gtk_box_pack_start(GTK_BOX(box_val_edit), dlg->val_box, FALSE, TRUE, 0);
+
+	g_signal_connect(G_OBJECT(dlg->val_box), "changed", G_CALLBACK(val_combo_changed_cb), dlg);
+
+	/* entry */
+	dlg->entry_val = gtk_entry_new();
+	gtk_box_pack_start(GTK_BOX(box_val_edit), dlg->entry_val, TRUE, TRUE, 0);
+
+	g_signal_connect(G_OBJECT(dlg->entry_val), "changed", G_CALLBACK(val_entry_changed_cb), dlg);
+
+	/* Apply button */
+	hbx = gtkc_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_edit), hbx, FALSE, TRUE, 4);
+
+	dummy = gtkc_vbox_new(FALSE, 0);	/* dummy box to eat up free space on the left */
+	gtk_box_pack_start(GTK_BOX(hbx), dummy, TRUE, TRUE, 4);
+
+	dlg->apply = gtk_button_new_with_label("Apply");
+	gtk_box_pack_start(GTK_BOX(hbx), dlg->apply, FALSE, TRUE, 4);
+	g_signal_connect(G_OBJECT(dlg->apply), "clicked", G_CALLBACK(do_apply_cb), dlg);
+
+	/* Runs the dialog */
+	gtk_widget_show_all(window);
+
+	return window;
+}
diff --git a/src_plugins/lib_gtk_common/dlg_propedit.h b/src_plugins/lib_gtk_common/dlg_propedit.h
new file mode 100644
index 0000000..776a12f
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_propedit.h
@@ -0,0 +1,58 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <gtk/gtk.h>
+
+/* object property edit dialog */
+
+typedef struct {
+	/* property list */
+	GtkWidget *tree;							/* property list widget               */
+	GtkListStore *props;					/* list model of properties           */
+
+	/* value entry */
+	GtkWidget *entry_val;					/* text entry                         */
+	GtkWidget *val_box;						/* combo box                          */
+	GtkListStore *vals;						/* model of the combo box             */
+	int stock_val;								/* 1 if the value in the entry box is being edited from the combo             */
+	GtkTreeIter last_add_iter;		/* the iterator of the last added row (sometimes it needs to be selected)     */
+	int last_add_iter_valid;
+
+	/* buttons */
+	GtkWidget *apply, *remove, *addattr;
+
+	/* glue to hid_gtk* */
+	const char *(*propedit_query)(void *pe, const char *cmd, const char *key, const char *val, int idx);
+	void *propedit_pe;
+	GtkWidget *top_window;
+} pcb_gtk_dlg_propedit_t;
+
+/** Creates and runs a dialog to edit selected object properties */
+GtkWidget *pcb_gtk_dlg_propedit_create(pcb_gtk_dlg_propedit_t * dlg, GtkWidget * top_window);
+
+/** */
+void pcb_gtk_dlg_propedit_prop_add(pcb_gtk_dlg_propedit_t * dlg, const char *name, const char *common,
+																	 const char *min, const char *max, const char *avg);
+
+
+/* Temporary: call back to hid_gtk, will be replaced by a preview call */
+extern GdkPixmap *ghid_render_pixmap(int cx, int cy, double zoom, int width, int height, int depth);
diff --git a/src_plugins/lib_gtk_common/dlg_report.c b/src_plugins/lib_gtk_common/dlg_report.c
new file mode 100644
index 0000000..c6adc12
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_report.c
@@ -0,0 +1,93 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* Originally from gui-utils.c, was written by Bill Wilson and the functions
+ * here are Copyright (C) 2004 by Bill Wilson.  Those functions were utility
+ * functions which are taken from my other GPL'd projects gkrellm and
+ * gstocks and are copied here for the Gtk PCB port.
+ */
+
+#include "config.h"
+
+#include "dlg_report.h"
+#include "compat.h"
+#include "bu_box.h"
+
+void pcb_gtk_dlg_report(GtkWidget * top_window, const gchar * title, const gchar * message, gboolean modal)
+{
+	GtkWidget *w;
+	GtkDialog *dialog;
+	GtkWidget *content_area;
+	GtkWidget *scrolled;
+	GtkWidget *vbox, *vbox1;
+	GtkWidget *label;
+	GtkTextView *text_view;
+	GtkTextBuffer *buffer;
+	const gchar *s;
+	gint nlines;
+
+	if (!message)
+		return;
+	w = gtk_dialog_new_with_buttons(title ? title : "PCB",
+																	GTK_WINDOW(top_window),
+																	GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_NONE, NULL);
+	dialog = GTK_DIALOG(w);
+	gtk_dialog_set_default_response(dialog, GTK_RESPONSE_CLOSE);
+
+	gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
+
+	g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog));
+	gtk_window_set_role(GTK_WINDOW(w), "PCB_Dialog");
+
+	content_area = gtk_dialog_get_content_area(dialog);
+
+	vbox = gtkc_vbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(content_area), vbox, TRUE, TRUE, 0);
+
+	label = gtk_text_view_new();
+	text_view = GTK_TEXT_VIEW(label);
+	buffer = gtk_text_view_get_buffer(text_view);
+	gtk_text_view_set_cursor_visible(text_view, FALSE);
+	gtk_text_view_set_editable(text_view, FALSE);
+	gtk_text_view_set_wrap_mode(text_view, GTK_WRAP_NONE);
+	/* The message should be NULL terminated */
+	gtk_text_buffer_set_text(buffer, message, -1);
+
+	for (nlines = 0, s = message; *s; ++s)
+		if (*s == '\n')
+			++nlines;
+	if (nlines > 20) {
+		vbox1 = ghid_scrolled_vbox(vbox, &scrolled, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+		gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
+		gtk_widget_set_size_request(scrolled, -1, 300);
+		gtk_box_pack_start(GTK_BOX(vbox1), label, FALSE, FALSE, 0);
+	}
+	else
+		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+
+	gtk_widget_show_all(w);
+	gtk_window_set_modal(GTK_WINDOW(dialog), modal);
+}
diff --git a/src_plugins/lib_gtk_common/dlg_report.h b/src_plugins/lib_gtk_common/dlg_report.h
new file mode 100644
index 0000000..6c4c93e
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_report.h
@@ -0,0 +1,4 @@
+#include <gtk/gtk.h>
+
+/** Opens a dialog window displaying the text to be reported */
+void pcb_gtk_dlg_report(GtkWidget * top_window, const gchar * title, const gchar * message, gboolean modal);
diff --git a/src_plugins/lib_gtk_common/dlg_route_style.c b/src_plugins/lib_gtk_common/dlg_route_style.c
new file mode 100644
index 0000000..284c41d
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_route_style.c
@@ -0,0 +1,468 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* route style edit dialog */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "config.h"
+
+#include "compat_misc.h"
+#include "compat_nls.h"
+#include "polygon.h"
+#include "obj_all.h"
+
+#include "bu_box.h"
+#include "compat.h"
+#include "board.h"
+#include "conf_core.h"
+#include "error.h"
+
+#include "dlg_route_style.h"
+#include "wt_coord_entry.h"
+
+/* SIGNAL HANDLERS */
+
+/* Rebuild the gtk table for attribute list from style */
+static void update_attrib(pcb_gtk_dlg_route_style_t * dialog, pcb_gtk_obj_route_style_t * style)
+{
+	GtkTreeIter iter;
+	int i;
+
+	gtk_list_store_clear(dialog->attr_model);
+
+	for (i = 0; i < style->rst->attr.Number; i++) {
+		gtk_list_store_append(dialog->attr_model, &iter);
+		gtk_list_store_set(dialog->attr_model, &iter, 0, style->rst->attr.List[i].name, -1);
+		gtk_list_store_set(dialog->attr_model, &iter, 1, style->rst->attr.List[i].value, -1);
+	}
+
+	gtk_list_store_append(dialog->attr_model, &iter);
+	gtk_list_store_set(dialog->attr_model, &iter, 0, "<new>", -1);
+	gtk_list_store_set(dialog->attr_model, &iter, 1, "<new>", -1);
+}
+
+/** attr table ? */
+static int get_sel(pcb_gtk_dlg_route_style_t * dlg)
+{
+	GtkTreeIter iter;
+	GtkTreeSelection *tsel;
+	GtkTreeModel *tm;
+	GtkTreePath *path;
+	int *i;
+
+	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->attr_table));
+	if (tsel == NULL)
+		return -1;
+
+	gtk_tree_selection_get_selected(tsel, &tm, &iter);
+	if (iter.stamp == 0)
+		return -1;
+
+	path = gtk_tree_model_get_path(tm, &iter);
+	if (path != NULL) {
+		i = gtk_tree_path_get_indices(path);
+		if (i != NULL) {
+/*			gtk_tree_model_get(GTK_TREE_MODEL(dlg->attr_model), &iter, 0, nkey, 1, nval, -1);*/
+			return i[0];
+		}
+	}
+	return -1;
+}
+
+/** Callback for dialog box's combobox being changed
+    \par Function Description
+    When a different layer is selected, this function loads
+    that layer's data into the dialog. Alternately, if the
+    "New layer" option is selected, this loads a new name
+    but no other data.
+
+    \param [in] combo   The combobox
+    \param [in] dialog  The rest of the widgets to be updated
+ */
+static void dialog_style_changed_cb(GtkComboBox * combo, pcb_gtk_dlg_route_style_t * dialog)
+{
+	pcb_gtk_route_style_t *rss;
+	pcb_gtk_obj_route_style_t *style;
+	GtkTreeIter iter;
+	GtkTreeModel *tree_model;
+
+	if (dialog->inhibit_style_change)
+		return;
+
+	rss = dialog->rss;
+	tree_model = GTK_TREE_MODEL(rss->model);
+	gtk_combo_box_get_active_iter(combo, &iter);
+	gtk_tree_model_get(tree_model, &iter, STYLE_DATA_COL, &style, -1);
+
+	if (style == NULL) {
+		gtk_entry_set_text(GTK_ENTRY(dialog->name_entry), _("New Style"));
+		rss->selected = -1;
+		return;
+	}
+
+	gtk_entry_set_text(GTK_ENTRY(dialog->name_entry), style->rst->name);
+	pcb_gtk_coord_entry_set_value(GHID_COORD_ENTRY(dialog->line_entry), style->rst->Thick);
+	pcb_gtk_coord_entry_set_value(GHID_COORD_ENTRY(dialog->via_hole_entry), style->rst->Hole);
+	pcb_gtk_coord_entry_set_value(GHID_COORD_ENTRY(dialog->via_size_entry), style->rst->Diameter);
+	pcb_gtk_coord_entry_set_value(GHID_COORD_ENTRY(dialog->clearance_entry), style->rst->Clearance);
+
+	if (style->hidden)
+		rss->selected = -1;
+	else
+		rss->selected = style->rst - PCB->RouteStyle.array;
+
+	update_attrib(dialog, style);
+}
+
+static void attr_edited(int col, GtkCellRendererText * cell, gchar * path, gchar * new_text, pcb_gtk_dlg_route_style_t * dlg)
+{
+	GtkTreeIter iter;
+	pcb_gtk_obj_route_style_t *style;
+	int idx = get_sel(dlg);
+
+	dlg->attr_editing = 0;
+
+	gtk_combo_box_get_active_iter(GTK_COMBO_BOX(dlg->select_box), &iter);
+	gtk_tree_model_get(GTK_TREE_MODEL(dlg->rss->model), &iter, STYLE_DATA_COL, &style, -1);
+
+	if (style == NULL)
+		return;
+
+	if (idx >= style->rst->attr.Number) {	/* add new */
+		if (col == 0)
+			pcb_attribute_put(&style->rst->attr, new_text, "n/a", 0);
+		else
+			pcb_attribute_put(&style->rst->attr, "n/a", new_text, 0);
+	}
+	else {												/* overwrite existing */
+		char **dest;
+		if (col == 0)
+			dest = &style->rst->attr.List[idx].name;
+		else
+			dest = &style->rst->attr.List[idx].value;
+		if (*dest != NULL)
+			free(*dest);
+		*dest = pcb_strdup(new_text);
+	}
+
+	/* rebuild the table to keep it in sync - expensive, but it happens rarely */
+	update_attrib(dlg, style);
+}
+
+static void attr_edited_key_cb(GtkCellRendererText * cell, gchar * path, gchar * new_text, pcb_gtk_dlg_route_style_t * dlg)
+{
+	attr_edited(0, cell, path, new_text, dlg);
+}
+
+static void attr_edited_val_cb(GtkCellRendererText * cell, gchar * path, gchar * new_text, pcb_gtk_dlg_route_style_t * dlg)
+{
+	attr_edited(1, cell, path, new_text, dlg);
+}
+
+static void attr_edit_started_cb(GtkCellRendererText * cell, GtkCellEditable * e, gchar * path, pcb_gtk_dlg_route_style_t * dlg)
+{
+	dlg->attr_editing = 1;
+}
+
+static void attr_edit_canceled_cb(GtkCellRendererText * cell, pcb_gtk_dlg_route_style_t * dlg)
+{
+	dlg->attr_editing = 0;
+}
+
+static gboolean attr_key_release_cb(GtkWidget * widget, GdkEventKey * event, pcb_gtk_dlg_route_style_t * dlg)
+{
+	unsigned short int kv = event->keyval;
+
+	if (dlg->attr_editing)
+		return FALSE;
+
+	switch (kv) {
+#ifdef GDK_KEY_KP_Delete
+	case GDK_KEY_KP_Delete:
+#endif
+#ifdef GDK_KEY_Delete
+	case GDK_KEY_Delete:
+#endif
+	case 'd':
+		{
+			int idx = get_sel(dlg);
+			GtkTreeIter iter;
+			pcb_gtk_obj_route_style_t *style;
+			gtk_combo_box_get_active_iter(GTK_COMBO_BOX(dlg->select_box), &iter);
+			gtk_tree_model_get(GTK_TREE_MODEL(dlg->rss->model), &iter, STYLE_DATA_COL, &style, -1);
+			if (style == NULL)
+				return FALSE;
+			if ((idx >= 0) && (idx < style->rst->attr.Number)) {
+				pcb_attribute_remove_idx(&style->rst->attr, idx);
+				update_attrib(dlg, style);
+			}
+		}
+		break;
+	}
+	return FALSE;
+}
+
+static void add_new_iter(pcb_gtk_route_style_t * rss)
+{
+	/* Add "new style" option to list */
+	gtk_list_store_append(rss->model, &rss->new_iter);
+	gtk_list_store_set(rss->model, &rss->new_iter, STYLE_TEXT_COL, _("<New>"), STYLE_DATA_COL, NULL, -1);
+}
+
+/*  Callback for Delete route style button */
+static void delete_button_cb(GtkButton * button, pcb_gtk_dlg_route_style_t * dialog)
+{
+	if (dialog->rss->selected < 0)
+		return;
+
+	dialog->inhibit_style_change = 1;
+	pcb_gtk_route_style_empty(dialog->rss);
+
+#warning TODO: some of these should be in core
+	pcb_gtk_route_style_copy(dialog->rss->selected);
+
+	vtroutestyle_remove(&PCB->RouteStyle, dialog->rss->selected, 1);
+	dialog->rss->active_style = NULL;
+	make_route_style_buttons(GHID_ROUTE_STYLE(dialog->rss));
+	pcb_trace("Style: %d deleted\n", dialog->rss->selected);
+	pcb_board_set_changed_flag(pcb_true);
+	ghid_window_set_name_label(PCB->Name);
+	add_new_iter(dialog->rss);
+	dialog->inhibit_style_change = 0;
+	pcb_gtk_route_style_select_style(dialog->rss, &pcb_custom_route_style);
+	gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->select_box), 0);
+}
+
+/** Helper for edit_button_cb */
+static void _table_attach_(GtkWidget * table, gint row, const gchar * label, GtkWidget * entry)
+{
+	GtkWidget *label_w = gtk_label_new(label);
+	gtk_misc_set_alignment(GTK_MISC(label_w), 1.0, 0.5);
+	gtk_table_attach(GTK_TABLE(table), label_w, 0, 1, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+}
+
+/** Helper for edit_button_cb */
+static void _table_attach(GtkWidget * table, gint row, const gchar * label, GtkWidget ** entry, pcb_coord_t min,
+													pcb_coord_t max)
+{
+	*entry = pcb_gtk_coord_entry_new(min, max, 0, conf_core.editor.grid_unit, CE_SMALL);
+	_table_attach_(table, row, label, *entry);
+}
+
+void pcb_gtk_route_style_edit_dialog(pcb_gtk_route_style_t * rss)
+{
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	pcb_gtk_dlg_route_style_t dialog_data;
+	GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+	GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(rss));
+	GtkWidget *dialog;
+	GtkWidget *content_area;
+	GtkWidget *vbox, *hbox, *sub_vbox, *table;
+	GtkWidget *label, *select_box, *check_box;
+	GtkWidget *button;
+	const char *new_name;
+
+	memset(&dialog_data, 0, sizeof(dialog_data));	/* make sure all flags are cleared */
+
+	/* Build dialog */
+	dialog = gtk_dialog_new_with_buttons(_("Edit Route Styles"),
+																			 GTK_WINDOW(window),
+																			 GTK_DIALOG_DESTROY_WITH_PARENT,
+																			 GTK_STOCK_CANCEL, GTK_RESPONSE_NONE, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	label = gtk_label_new(_("Edit Style:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+
+	select_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(rss->model));
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(select_box), renderer, TRUE);
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(select_box), renderer, "text", STYLE_TEXT_COL, NULL);
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+	hbox = gtkc_hbox_new(FALSE, 4);
+	gtk_box_pack_start(GTK_BOX(content_area), hbox, TRUE, TRUE, 4);
+	vbox = gtkc_vbox_new(FALSE, 4);
+	gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 4);
+
+	hbox = gtkc_hbox_new(FALSE, 4);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 4);
+	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(hbox), select_box, TRUE, TRUE, 0);
+
+	sub_vbox = ghid_category_vbox(vbox, _("Route Style Data"), 4, 2, TRUE, TRUE);
+	table = gtk_table_new(5, 2, FALSE);
+	gtk_box_pack_start(GTK_BOX(sub_vbox), table, TRUE, TRUE, 4);
+	label = gtk_label_new(_("Name:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+	dialog_data.name_entry = gtk_entry_new();
+	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+	gtk_table_attach(GTK_TABLE(table), dialog_data.name_entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+
+	_table_attach(table, 1, _("Line width:"), &dialog_data.line_entry, PCB_MIN_LINESIZE, PCB_MAX_LINESIZE);
+	_table_attach(table, 2, _("Via hole size:"),
+								&dialog_data.via_hole_entry, PCB_MIN_PINORVIAHOLE, PCB_MAX_PINORVIASIZE - PCB_MIN_PINORVIACOPPER);
+	_table_attach(table, 3, _("Via ring size:"),
+								&dialog_data.via_size_entry, PCB_MIN_PINORVIAHOLE + PCB_MIN_PINORVIACOPPER, PCB_MAX_PINORVIASIZE);
+	_table_attach(table, 4, _("Clearance:"), &dialog_data.clearance_entry, PCB_MIN_LINESIZE, PCB_MAX_LINESIZE);
+
+	_table_attach_(table, 5, "", gtk_label_new(""));
+
+	/* create attrib table */
+	{
+		GType *ty;
+		GtkCellRenderer *renderer;
+
+		dialog_data.attr_table = gtk_tree_view_new();
+
+		ty = malloc(sizeof(GType) * 2);
+		ty[0] = G_TYPE_STRING;
+		ty[1] = G_TYPE_STRING;
+		dialog_data.attr_model = gtk_list_store_newv(2, ty);
+		free(ty);
+
+		renderer = gtk_cell_renderer_text_new();
+		g_object_set(renderer, "editable", TRUE, NULL);
+		g_signal_connect(renderer, "edited", G_CALLBACK(attr_edited_key_cb), &dialog_data);
+		g_signal_connect(renderer, "editing-started", G_CALLBACK(attr_edit_started_cb), &dialog_data);
+		g_signal_connect(renderer, "editing-canceled", G_CALLBACK(attr_edit_canceled_cb), &dialog_data);
+		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dialog_data.attr_table), -1, "key", renderer, "text", 0, NULL);
+
+
+		renderer = gtk_cell_renderer_text_new();
+		g_object_set(renderer, "editable", TRUE, NULL);
+		g_signal_connect(renderer, "edited", G_CALLBACK(attr_edited_val_cb), &dialog_data);
+		g_signal_connect(renderer, "editing-started", G_CALLBACK(attr_edit_started_cb), &dialog_data);
+		g_signal_connect(renderer, "editing-canceled", G_CALLBACK(attr_edit_canceled_cb), &dialog_data);
+		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dialog_data.attr_table), -1, "value", renderer, "text", 1, NULL);
+
+		gtk_tree_view_set_model(GTK_TREE_VIEW(dialog_data.attr_table), GTK_TREE_MODEL(dialog_data.attr_model));
+		g_signal_connect(G_OBJECT(dialog_data.attr_table), "key-release-event", G_CALLBACK(attr_key_release_cb), &dialog_data);
+
+	}
+	_table_attach_(table, 6, _("Attributes:"), dialog_data.attr_table);
+
+
+	/* create delete button */
+	button = gtk_button_new_with_label(_("Delete Style"));
+	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(delete_button_cb), &dialog_data);
+	gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, FALSE, 0);
+
+	sub_vbox = ghid_category_vbox(vbox, _("Set as Default"), 4, 2, TRUE, TRUE);
+	check_box = gtk_check_button_new_with_label(_("Save route style settings as default"));
+	gtk_box_pack_start(GTK_BOX(sub_vbox), check_box, TRUE, TRUE, 0);
+
+	add_new_iter(rss);
+
+	/* Display dialog */
+	dialog_data.rss = rss;
+	dialog_data.select_box = select_box;
+	if (rss->active_style != NULL) {
+		path = gtk_tree_row_reference_get_path(rss->active_style->rref);
+		gtk_tree_model_get_iter(GTK_TREE_MODEL(rss->model), &iter, path);
+		g_signal_connect(G_OBJECT(select_box), "changed", G_CALLBACK(dialog_style_changed_cb), &dialog_data);
+		gtk_combo_box_set_active_iter(GTK_COMBO_BOX(select_box), &iter);
+	}
+	gtk_widget_show_all(dialog);
+	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
+		int changed = 0, need_rebuild = 0;
+		pcb_route_style_t *rst;
+		pcb_gtk_obj_route_style_t *style;
+		gboolean save;
+
+		if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(select_box), &iter))
+			goto cancel;
+		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, STYLE_DATA_COL, &style, -1);
+		if (style == NULL) {
+			int n = vtroutestyle_len(&PCB->RouteStyle);
+			rst = vtroutestyle_get(&PCB->RouteStyle, n, 1);
+			need_rebuild = 1;
+			changed = 1;
+		}
+		else {
+			rst = style->rst;
+			*rst->name = '\0';
+		}
+
+		new_name = gtk_entry_get_text(GTK_ENTRY(dialog_data.name_entry));
+
+		while (isspace(*new_name))
+			new_name++;
+		if (strcmp(rst->name, new_name) != 0) {
+			strncpy(rst->name, new_name, sizeof(rst->name) - 1);
+			rst->name[sizeof(rst->name) - 1] = '0';
+			changed = 1;
+		}
+
+/* Modify the route style only if there's significant difference (beyond rouding errors) */
+#define rst_modify(changed, dst, src) \
+	do { \
+		pcb_coord_t __tmp__ = src; \
+		if (abs(dst - __tmp__) > 10) { \
+			changed = 1; \
+			dst = __tmp__; \
+		} \
+	} while(0)
+		rst_modify(changed, rst->Thick, pcb_gtk_coord_entry_get_value(GHID_COORD_ENTRY(dialog_data.line_entry)));
+		rst_modify(changed, rst->Hole, pcb_gtk_coord_entry_get_value(GHID_COORD_ENTRY(dialog_data.via_hole_entry)));
+		rst_modify(changed, rst->Diameter, pcb_gtk_coord_entry_get_value(GHID_COORD_ENTRY(dialog_data.via_size_entry)));
+		rst_modify(changed, rst->Clearance, pcb_gtk_coord_entry_get_value(GHID_COORD_ENTRY(dialog_data.clearance_entry)));
+#undef rst_modify
+		save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_box));
+		if (style == NULL) {
+			style = pcb_gtk_route_style_add_route_style(rss, rst, 0);
+		}
+		else {
+			gtk_action_set_label(GTK_ACTION(style->action), rst->name);
+			gtk_list_store_set(rss->model, &iter, STYLE_TEXT_COL, rst->name, -1);
+		}
+
+		/* Cleanup */
+		gtk_widget_destroy(dialog);
+		gtk_list_store_remove(rss->model, &rss->new_iter);
+
+		/* if the style array in core might have been reallocated, we need to update
+		   all our pointers in the rss "cache" */
+		if (need_rebuild) {
+			pcb_gtk_route_style_empty(rss);
+			make_route_style_buttons(GHID_ROUTE_STYLE(rss));
+		}
+
+		/* Emit change signals */
+		pcb_gtk_route_style_select_style(rss, rst);
+		g_signal_emit(rss, pcb_gtk_route_style_signals_id[STYLE_EDITED_SIGNAL], 0, save);
+
+		if (changed) {
+			pcb_board_set_changed_flag(pcb_true);
+			ghid_window_set_name_label(PCB->Name);
+		}
+	}
+	else {
+	cancel:;
+		gtk_widget_destroy(dialog);
+		gtk_list_store_remove(rss->model, &rss->new_iter);
+	}
+}
diff --git a/src_plugins/lib_gtk_common/dlg_route_style.h b/src_plugins/lib_gtk_common/dlg_route_style.h
new file mode 100644
index 0000000..7217085
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_route_style.h
@@ -0,0 +1,27 @@
+/* Very linked to the widget ! */
+#include "wt_route_style.h"
+
+struct pcb_gtk_dlg_route_style_s {
+	pcb_gtk_route_style_t *rss;
+	GtkWidget *name_entry;
+	GtkWidget *line_entry;
+	GtkWidget *via_hole_entry;
+	GtkWidget *via_size_entry;
+	GtkWidget *clearance_entry;
+
+	GtkWidget *select_box;
+
+	GtkWidget *attr_table;				/* Attributes gtk_tree_view                     */
+	GtkListStore *attr_model;			/* Attributes gtk_tree_model                    */
+
+	int inhibit_style_change;			/* when 1, do not do anything when style changes                  */
+	int attr_editing;							/* set to 1 when an attribute key or value text is being edited   */
+};
+
+/** Builds and runs the "edit route style" dialog.
+    \param  rss the route style selector widget linked to this dialog.
+ */
+void pcb_gtk_route_style_edit_dialog(pcb_gtk_route_style_t * rss);
+
+/* Temporary: hid_gtk call back */
+extern void ghid_window_set_name_label(gchar * name);
diff --git a/src_plugins/lib_gtk_common/dlg_search.c b/src_plugins/lib_gtk_common/dlg_search.c
new file mode 100644
index 0000000..d337a1a
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_search.c
@@ -0,0 +1,881 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* advanced search dialog */
+
+#include "config.h"
+#include "dlg_search.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <genlist/gendlist.h>
+#include <genvector/gds_char.h>
+#include "compat_misc.h"
+#include "hid_actions.h"
+#include "compat_nls.h"
+#include "misc_util.h"
+#include "pcb-printf.h"
+#include "conf_core.h"
+
+#include "win_place.h"
+#include "wt_coord_entry.h"
+#include "bu_box.h"
+
+typedef struct expr1_s expr1_t;
+
+struct expr1_s {
+	GtkWidget *and;								/* only if not the first row */
+
+	GtkWidget *hbox;							/* only if first in row */
+	GtkWidget *remove_row;				/* only if first in row */
+	GtkWidget *append_col;				/* only if first in row */
+	GtkWidget *spc;								/* only if first in row */
+
+	GtkWidget *remove, *remove_button;
+	GtkWidget *content;						/* the actual expression */
+	GtkWidget *or;								/* only if not the first in the row */
+
+	gdl_elem_t next_or;						/* --> */
+	gdl_elem_t next_and;					/* v */
+	gdl_list_t ors;								/* only in the first; the row-first is not on this list, so it collects the subseqent siblings only */
+
+	expr1_t *row;									/* only if not the first */
+
+	gulong sig_remove_row;
+	gulong sig_append_col;
+
+	char *code;										/* ... to use in the query script */
+
+	GtkWidget *top_window;
+};
+
+typedef struct {
+	GtkWidget *window;
+	GtkWidget *expr;							/* manual expression entry */
+	GtkWidget *action;						/* what-to-do combo box */
+	GtkWidget *wizard_enable;			/* checkbox */
+	GtkWidget *wizard_vbox;
+	GtkWidget *new_row;
+
+	gdl_list_t wizard;						/* of expr1_t */
+} ghid_search_dialog_t;
+
+static ghid_search_dialog_t sdlg;
+
+static void new_col_cb(GtkWidget * button, void *data);
+static void remove_row_cb(GtkWidget * button, void *data);
+static void remove_expr_cb(GtkWidget * button, void *data);
+static void edit_expr_cb(GtkWidget * button, void *data);
+static void expr_wizard_dialog(GtkWidget *top_window, expr1_t * e);
+
+static void build_expr1(expr1_t * e, GtkWidget * parent_box)
+{
+	e->content = gtk_button_new_with_label("<expr>");
+	gtk_button_set_image(GTK_BUTTON(e->content), gtk_image_new_from_icon_name("gtk-new", GTK_ICON_SIZE_MENU));
+	gtk_box_pack_start(GTK_BOX(parent_box), e->content, FALSE, FALSE, 0);
+	gtk_widget_set_tooltip_text(e->content, "Edit search expression");
+	g_signal_connect(e->content, "clicked", G_CALLBACK(edit_expr_cb), e);
+
+	e->remove = gtk_vbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(parent_box), e->remove, FALSE, FALSE, 0);
+
+	e->remove_button = gtk_button_new_with_label("");
+	gtk_button_set_image(GTK_BUTTON(e->remove_button), gtk_image_new_from_icon_name("gtk-delete", GTK_ICON_SIZE_MENU));
+	gtk_box_pack_start(GTK_BOX(e->remove), e->remove_button, FALSE, FALSE, 0);
+	gtk_widget_set_tooltip_text(e->remove_button, "Remove this expression");
+	g_signal_connect(e->remove_button, "clicked", G_CALLBACK(remove_expr_cb), e);
+}
+
+/* e is not part of any list by the time of the call */
+static void destroy_expr1(expr1_t * e)
+{
+#	define destroy(w) if (w != NULL) gtk_widget_destroy(w)
+	destroy(e->and);
+	destroy(e->spc);
+	destroy(e->remove_row);
+	destroy(e->append_col);
+	destroy(e->remove);
+	destroy(e->content);
+	destroy(e->or);
+	destroy(e->hbox);
+	free(e);
+#	undef destroy
+}
+
+static expr1_t *append_row(GtkWidget *top_window)
+{
+	expr1_t *e = calloc(sizeof(expr1_t), 1);
+
+	e->top_window = top_window;
+
+	if (gdl_first(&sdlg.wizard) != NULL) {
+		e->and = gtk_label_new("AND");
+		gtk_misc_set_alignment(GTK_MISC(e->and), -1, 0.);
+		gtk_box_pack_start(GTK_BOX(sdlg.wizard_vbox), e->and, FALSE, FALSE, 0);
+	}
+
+	e->hbox = gtk_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(sdlg.wizard_vbox), e->hbox, FALSE, FALSE, 0);
+
+	e->remove_row = gtk_button_new_with_label("");
+	gtk_button_set_image(GTK_BUTTON(e->remove_row), gtk_image_new_from_icon_name("gtk-delete", GTK_ICON_SIZE_SMALL_TOOLBAR));
+	gtk_box_pack_start(GTK_BOX(e->hbox), e->remove_row, FALSE, FALSE, 0);
+	e->sig_remove_row = g_signal_connect(e->remove_row, "clicked", G_CALLBACK(remove_row_cb), e);
+	gtk_widget_set_tooltip_text(e->remove_row, "Remove this row of expressions");
+
+
+	e->append_col = gtk_button_new_with_label("");
+	gtk_button_set_image(GTK_BUTTON(e->append_col), gtk_image_new_from_icon_name("gtk-add", GTK_ICON_SIZE_SMALL_TOOLBAR));
+	gtk_box_pack_start(GTK_BOX(e->hbox), e->append_col, FALSE, FALSE, 0);
+	e->sig_append_col = g_signal_connect(e->append_col, "clicked", G_CALLBACK(new_col_cb), e);
+	gtk_widget_set_tooltip_text(e->append_col, "Append an expression to this row with OR");
+
+	e->spc = gtk_vbox_new(FALSE, 10);
+	gtk_box_pack_start(GTK_BOX(e->hbox), e->spc, FALSE, FALSE, 10);
+
+	build_expr1(e, e->hbox);
+
+	gdl_append(&sdlg.wizard, e, next_and);
+	return e;
+}
+
+static expr1_t *append_col(expr1_t * row)
+{
+	expr1_t *e = calloc(sizeof(expr1_t), 1);
+
+	e->top_window = row->top_window;
+
+	e->or = gtk_label_new(" OR ");
+	gtk_misc_set_alignment(GTK_MISC(e->or), -1, 1);
+	gtk_box_pack_start(GTK_BOX(row->hbox), e->or, FALSE, FALSE, 0);
+
+	build_expr1(e, row->hbox);
+
+	gdl_append(&row->ors, e, next_or);
+	e->row = row;
+	return e;
+}
+
+static void remove_row(expr1_t * row)
+{
+	expr1_t *o;
+	gdl_remove(&sdlg.wizard, row, next_and);
+	for (o = gdl_first(&row->ors); o != NULL; o = gdl_next(&row->ors, o))
+		destroy_expr1(o);
+	destroy_expr1(row);
+
+	/* the new first widget must not have an AND "preface" */
+	o = gdl_first(&sdlg.wizard);
+	if ((o != NULL) && (o->and != NULL)) {
+		gtk_widget_destroy(o->and);
+		o->and = NULL;
+	}
+}
+
+static void remove_expr(expr1_t * e)
+{
+	if (e->row == NULL) {
+		/* first item in a row */
+		expr1_t *o, *o2 = gdl_first(&e->ors);
+		if (o2 != NULL) {
+			/* there are subsequent items in the row - have to make the first of them the new head */
+			gdl_remove(&e->ors, o2, next_or);
+			gdl_insert_before(&sdlg.wizard, e, o2, next_and);
+			gdl_remove(&sdlg.wizard, e, next_and);
+#			define inherit(dst, src, fld)  dst->fld = src->fld; src->fld = NULL;
+			inherit(o2, e, and);
+			inherit(o2, e, hbox);
+			inherit(o2, e, remove_row);
+			inherit(o2, e, append_col);
+			inherit(o2, e, spc);
+#			undef inherit
+			/* move the list, reparenting it */
+			memcpy(&o2->ors, &e->ors, sizeof(e->ors));
+			for (o = gdl_first(&o2->ors); o != NULL; o = gdl_next(&o2->ors, o))
+				o->next_or.parent = &o2->ors;
+
+			o2->row = NULL;
+			memset(&e->ors, 0, sizeof(e->ors));
+			if (o2->or != NULL) {
+				gtk_widget_destroy(o2->or);
+				o2->or = NULL;
+			}
+
+			/* reconnect row signals to the new head */
+			g_signal_handler_disconnect(o2->remove_row, e->sig_remove_row);
+			g_signal_handler_disconnect(o2->append_col, e->sig_append_col);
+
+			o2->sig_remove_row = g_signal_connect(o2->remove_row, "clicked", G_CALLBACK(remove_row_cb), o2);
+			o2->sig_append_col = g_signal_connect(o2->append_col, "clicked", G_CALLBACK(new_col_cb), o2);
+		}
+		else {
+			/* only item of the row */
+			remove_row(e);
+			return;
+		}
+	}
+	else
+		gdl_remove(&e->row->ors, e, next_or);
+	destroy_expr1(e);
+}
+
+static int num_ors(expr1_t * head)
+{
+	int count = 0;
+	expr1_t *o;
+	if (head->code != NULL)
+		count++;
+	for (o = gdl_first(&head->ors); o != NULL; o = gdl_next(&head->ors, o))
+		if (o->code != NULL)
+			count++;
+	return count;
+}
+
+static void rebuild(void)
+{
+	int and_first = 1;
+	gds_t s;
+	expr1_t *a, *o;
+	gds_init(&s);
+
+	for (a = gdl_first(&sdlg.wizard); a != NULL; a = gdl_next(&sdlg.wizard, a)) {
+		int or_first = 1;
+		int ors = num_ors(a);
+		if (ors == 0)
+			continue;
+
+		/* add the && if needed */
+		if (!and_first)
+			gds_append_str(&s, " && ");
+		and_first = 0;
+
+		if (ors > 1)
+			gds_append_str(&s, "(");
+
+		if (a->code != NULL) {
+			gds_append_str(&s, a->code);
+			or_first = 0;
+		}
+
+		for (o = gdl_first(&a->ors); o != NULL; o = gdl_next(&a->ors, o)) {
+			if (o->code != NULL) {
+				if (!or_first)
+					gds_append_str(&s, " || ");
+				or_first = 0;
+				gds_append_str(&s, o->code);
+			}
+		}
+
+		if (ors > 1)
+			gds_append_str(&s, ")");
+	}
+	gtk_entry_set_text(GTK_ENTRY(sdlg.expr), s.array);
+	gds_uninit(&s);
+}
+
+/* button callbacks */
+static void new_row_cb(GtkWidget * button, void *data)
+{
+	append_row(data);
+	gtk_widget_show_all(sdlg.window);
+}
+
+static void remove_row_cb(GtkWidget * button, void *data)
+{
+	expr1_t *row = (expr1_t *) data;
+	remove_row(row);
+	rebuild();
+	gtk_widget_show_all(sdlg.window);
+}
+
+static void remove_expr_cb(GtkWidget * button, void *data)
+{
+	remove_expr((expr1_t *) data);
+	rebuild();
+	gtk_widget_show_all(sdlg.window);
+}
+
+static void edit_expr_cb(GtkWidget * button, void *data)
+{
+	expr1_t *e = (expr1_t *)data;
+	expr_wizard_dialog(e->top_window, e);
+}
+
+static void new_col_cb(GtkWidget * button, void *data)
+{
+	expr1_t *row = (expr1_t *) data;
+	append_col(row);
+	gtk_widget_show_all(sdlg.window);
+}
+
+static void wizard_toggle_cb(GtkCheckButton * button, void *data)
+{
+	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) {
+		gtk_widget_show(sdlg.wizard_vbox);
+		gtk_widget_set_sensitive(sdlg.new_row, 1);
+		gtk_widget_set_sensitive(sdlg.expr, 0);
+
+	}
+	else {
+		gtk_widget_hide(sdlg.wizard_vbox);
+		gtk_widget_set_sensitive(sdlg.new_row, 0);
+		gtk_widget_set_sensitive(sdlg.expr, 1);
+	}
+}
+
+
+/* Run the expression wizard dialog box */
+#include "dlg_search_tab.h"
+
+static void expr_wizard_init_model()
+{
+	const expr_wizard_t *w;
+	expr_wizard_op_t *o;
+	const char **s;
+
+	if (expr_wizard_dlg.md_left != NULL)
+		return;
+
+	/* render operator models */
+	for (o = op_tab; o->ops != NULL; o++) {
+		o->model = gtk_list_store_newv(1, model_op);
+		for (s = o->ops; *s != NULL; s++)
+			gtk_list_store_insert_with_values(o->model, NULL, -1, 0, *s, -1);
+	}
+
+	/* render right constant models */
+	for (o = right_const_tab; o->ops != NULL; o++) {
+		o->model = gtk_list_store_newv(1, model_op);
+		for (s = o->ops; *s != NULL; s++)
+			gtk_list_store_insert_with_values(o->model, NULL, -1, 0, *s, -1);
+	}
+
+	{															/* create the left tree model */
+		GtkTreeIter *parent = NULL, iter, iparent;
+		expr_wizard_dlg.md_left = gtk_tree_store_newv(2, model_op);
+		for (w = expr_tab; w->left_desc != NULL; w++) {
+			if (w->left_var == NULL)
+				parent = NULL;
+			gtk_tree_store_append(expr_wizard_dlg.md_left, &iter, parent);
+			gtk_tree_store_set(expr_wizard_dlg.md_left, &iter, 0, w->left_desc, 1, w, -1);
+			if (w->left_var == NULL) {
+				/* new section */
+				iparent = iter;
+				parent = &iparent;
+			}
+		}
+	}
+}
+
+static void right_hide(void)
+{
+	gtk_widget_hide(expr_wizard_dlg.right_str);
+	gtk_widget_hide(expr_wizard_dlg.right_int);
+	gtk_widget_hide(expr_wizard_dlg.right_coord);
+	gtk_widget_hide(expr_wizard_dlg.tr_right);
+}
+
+static const expr_wizard_t *left_get_wiz(void)
+{
+	const expr_wizard_t *w;
+	GtkTreeSelection *tsel;
+	GtkTreeModel *tm;
+	GtkTreeIter iter;
+
+	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(expr_wizard_dlg.tr_left));
+	if (tsel == NULL)
+		return NULL;
+
+	gtk_tree_selection_get_selected(tsel, &tm, &iter);
+	if (iter.stamp == 0)
+		return NULL;
+
+	gtk_tree_model_get(tm, &iter, 1, &w, -1);
+	return w;
+}
+
+/* Returns the string current value of a single-column-string-tree */
+static const char *wiz_get_tree_str(GtkWidget * tr)
+{
+	const char *s;
+	GtkTreeSelection *tsel;
+	GtkTreeModel *tm;
+	GtkTreeIter iter;
+
+	tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tr));
+	if (tsel == NULL)
+		return NULL;
+
+	gtk_tree_selection_get_selected(tsel, &tm, &iter);
+	if (iter.stamp == 0)
+		return NULL;
+
+	gtk_tree_model_get(tm, &iter, 0, &s, -1);
+	return s;
+}
+
+static void left_chg_cb(GtkTreeView * t, gpointer * data)
+{
+	const expr_wizard_t *w = left_get_wiz();
+
+	right_hide();
+
+	if ((w == NULL) || (w->left_var == NULL))
+		return;
+
+	gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_op), GTK_TREE_MODEL(w->ops->model));
+
+	switch (w->rtype) {
+	case RIGHT_INT:
+		gtk_widget_show(expr_wizard_dlg.right_int);
+		break;
+	case RIGHT_STR:
+		gtk_widget_show(expr_wizard_dlg.right_str);
+		break;
+	case RIGHT_COORD:
+		gtk_widget_show(expr_wizard_dlg.right_coord);
+		break;
+	case RIGHT_CONST:
+		gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_right), GTK_TREE_MODEL(w->right_const->model));
+		gtk_widget_show(expr_wizard_dlg.tr_right);
+		break;
+	}
+}
+
+static char *expr_wizard_result(int desc)
+{
+	gds_t s;
+	char tmp[128];
+	const char *cs;
+	const expr_wizard_t *parent, *w = left_get_wiz();
+
+	if ((w == NULL) || (w->left_var == NULL))
+		return NULL;
+
+
+	gds_init(&s);
+	if (desc) {
+		/* search the parent */
+		for (parent = w; parent >= expr_tab; parent--)
+			if (parent->left_var == NULL)
+				break;
+
+		if (parent->left_desc != NULL)
+			pcb_append_printf(&s, "%s\t%s", parent->left_desc, w->left_desc);
+		else
+			pcb_append_printf(&s, "%s", w->left_desc);
+	}
+	else
+		pcb_append_printf(&s, "(%s", w->left_var);
+
+	cs = wiz_get_tree_str(expr_wizard_dlg.tr_op);
+	if (cs == NULL)
+		goto err;
+
+	if (desc)
+		pcb_append_printf(&s, "\n%s\n", cs);
+	else
+		pcb_append_printf(&s, " %s ", cs);
+
+	switch (w->rtype) {
+	case RIGHT_INT:
+		pcb_append_printf(&s, "%.0f", gtk_adjustment_get_value(expr_wizard_dlg.right_adj));
+		break;
+	case RIGHT_STR:
+		if (!desc)
+			gds_append_str(&s, "\"");
+		pcb_append_printf(&s, "%s", gtk_entry_get_text(GTK_ENTRY(expr_wizard_dlg.right_str)));
+		if (!desc)
+			gds_append_str(&s, "\"");
+		break;
+	case RIGHT_COORD:
+		pcb_gtk_coord_entry_get_value_str(GHID_COORD_ENTRY(expr_wizard_dlg.right_coord), tmp, sizeof(tmp));
+		pcb_append_printf(&s, "%s", tmp);
+		break;
+	case RIGHT_CONST:
+		cs = wiz_get_tree_str(expr_wizard_dlg.tr_right);
+		if (cs == NULL)
+			goto err;
+		pcb_append_printf(&s, "%s", cs);
+		break;
+	}
+
+	if (!desc)
+		gds_append_str(&s, ")");
+
+	return s.array;
+
+err:;
+	free(s.array);
+	return NULL;
+}
+
+/* look up a tab entry with a slow linear search */
+static const expr_wizard_t *find_tab_entry(const expr_wizard_t * start_at, const char *desc, int need_hdr, int *idx)
+{
+	const expr_wizard_t *w;
+	int i = 0, initial = 1;
+
+	for (w = start_at; w->left_desc != NULL; w++) {
+		if (need_hdr) {
+			if (w->left_var != NULL) {
+				if (initial)
+					i++;
+				continue;
+			}
+			else
+				initial = 0;
+		}
+		else {
+			if (w->left_var == NULL)
+				return NULL;
+		}
+		if (strcmp(w->left_desc, desc) == 0) {
+			*idx = i;
+			return w;
+		}
+		i++;
+	}
+
+	return NULL;
+}
+
+/* Set enum-like tree cursor from a string; returns 0 if not found, 1 if found. */
+static int set_tree_from_enum(GtkWidget * tree, const char **vals, const char *target)
+{
+	int n, found;
+	const char **s;
+	for (n = 0, found = 0, s = vals; *s != NULL; s++, n++) {
+		if (strcmp(*s, target) == 0) {
+			found = 1;
+			break;
+		}
+	}
+	if (found) {
+		GtkTreePath *path = gtk_tree_path_new_from_indices(n, -1);
+		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree), path, NULL, FALSE);
+		gtk_tree_path_free(path);
+	}
+	return found;
+}
+
+/* Set the value of expr wizard widgets to match the button text from the previous set */
+void expr_wizard_import(const char *desc_)
+{
+	char *desc, *left, *left_parent, *left_desc, *op, *right, *sep;
+	const expr_wizard_t *w;
+	int l1idx = -1, l2idx = -1;
+
+	if (desc_ == NULL)
+		return;
+
+	/* split the string into left, op and right */
+	desc = pcb_strdup(desc_);
+	left = desc;
+
+	op = strchr(left, '\n');
+	if (op == NULL)
+		goto fail;
+	*op = '\0';
+	op++;
+
+	right = strchr(op, '\n');
+	if (right == NULL)
+		goto fail;
+	*right = '\0';
+	right++;
+
+	/* split left */
+	sep = strchr(left, '\t');
+	if (sep != NULL) {
+		*sep = '\0';
+		sep++;
+		left_parent = left;
+		left_desc = sep;
+	}
+	else {
+		left_parent = NULL;
+		left_desc = left;
+	}
+
+/*	printf("lp='%s' ld='%s' op='%s' r='%s'\n", left_parent, left_desc, op, right);*/
+	/* Find the tab entry */
+
+	if (left_parent != NULL) {
+		w = find_tab_entry(expr_tab, left_parent, 1, &l1idx);
+		if (w == NULL)
+			goto fail;
+		w++;
+	}
+	else
+		w = expr_tab;
+	w = find_tab_entry(w, left_desc, 0, &l2idx);
+	if (w == NULL)
+		goto fail;
+
+	/* set left tree widget cursor */
+	{
+		GtkTreePath *path;
+		if (left_parent != NULL)
+			path = gtk_tree_path_new_from_indices(l1idx, l2idx, -1);
+		else
+			path = gtk_tree_path_new_from_indices(l2idx, -1);
+
+		gtk_tree_view_expand_to_path(GTK_TREE_VIEW(expr_wizard_dlg.tr_left), path);
+		gtk_tree_view_set_cursor(GTK_TREE_VIEW(expr_wizard_dlg.tr_left), path, NULL, FALSE);
+		gtk_tree_path_free(path);
+	}
+
+	/* set op cursor */
+	set_tree_from_enum(expr_wizard_dlg.tr_op, w->ops->ops, op);
+
+	/* set value field */
+	{
+		switch (w->rtype) {
+		case RIGHT_STR:
+			gtk_entry_set_text(GTK_ENTRY(expr_wizard_dlg.right_str), right);
+			break;
+		case RIGHT_INT:
+			{
+				char *end;
+				double d = strtod(right, &end);
+				if (*end == '\0')
+					gtk_spin_button_set_value(GTK_SPIN_BUTTON(expr_wizard_dlg.right_int), d);
+				break;
+			}
+		case RIGHT_COORD:
+			{
+				pcb_bool succ;
+				double d = pcb_get_value_ex(right, NULL, NULL, NULL, "mm", &succ);
+				if (succ)
+					pcb_gtk_coord_entry_set_value(GHID_COORD_ENTRY(expr_wizard_dlg.right_coord), d);
+				break;
+			}
+		case RIGHT_CONST:
+			set_tree_from_enum(expr_wizard_dlg.tr_right, w->right_const->ops, right);
+			break;
+		}
+	}
+
+fail:;
+	free(desc);
+}
+
+static void expr_wizard_dialog(GtkWidget *top_window, expr1_t * e)
+{
+	GtkWidget *dialog, *vbox, *hbox;
+	GtkCellRenderer *renderer;
+	gboolean response;
+
+	expr_wizard_init_model();
+
+	/* Create the dialog */
+	dialog = gtk_dialog_new_with_buttons("Expression wizard",
+																			 GTK_WINDOW(top_window),
+																			 GTK_DIALOG_MODAL,
+																			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+	hbox = gtk_hbox_new(FALSE, 4);
+	gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+
+	/* left */
+	vbox = gtk_vbox_new(FALSE, 4);
+	expr_wizard_dlg.tr_left = gtk_tree_view_new();
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(expr_wizard_dlg.tr_left), -1, "variable", renderer, "text", 0,
+																							NULL);
+	gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_left), GTK_TREE_MODEL(expr_wizard_dlg.md_left));
+	g_signal_connect(G_OBJECT(expr_wizard_dlg.tr_left), "cursor-changed", G_CALLBACK(left_chg_cb), NULL);
+	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.tr_left, FALSE, TRUE, 4);
+
+
+	expr_wizard_dlg.entry_left = gtk_entry_new();
+	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.entry_left, FALSE, TRUE, 4);
+
+	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 4);
+
+	/* operator */
+	vbox = gtk_vbox_new(FALSE, 4);
+
+	expr_wizard_dlg.tr_op = gtk_tree_view_new();
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(expr_wizard_dlg.tr_op), -1, "op", renderer, "text", 0, NULL);
+	gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_op), GTK_TREE_MODEL(op_tab[OPS_ANY].model));
+	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.tr_op, FALSE, FALSE, 4);
+
+	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 4);
+
+	/* right */
+	vbox = gtk_vbox_new(FALSE, 4);
+
+	expr_wizard_dlg.tr_right = gtk_tree_view_new();
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(expr_wizard_dlg.tr_right), -1, "constant", renderer, "text", 0,
+																							NULL);
+/*	gtk_tree_view_set_model(GTK_TREE_VIEW(expr_wizard_dlg.tr_right), GTK_TREE_MODEL(expr_wizard_dlg.md_objtype));*/
+	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.tr_right, FALSE, TRUE, 4);
+
+	expr_wizard_dlg.right_str = gtk_entry_new();
+	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.right_str, FALSE, TRUE, 4);
+
+	expr_wizard_dlg.right_adj = GTK_ADJUSTMENT(gtk_adjustment_new(10, 0,	/* min */
+																																8, 1, 1,	/* steps */
+																																0.0));
+/*	g_signal_connect(G_OBJECT(expr_wizard_dlg.right_adj), "value-changed", G_CALLBACK(config_auto_idx_changed_cb), NULL); */
+	expr_wizard_dlg.right_int = gtk_spin_button_new(expr_wizard_dlg.right_adj, 1, 8);
+	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.right_int, FALSE, TRUE, 4);
+
+	expr_wizard_dlg.right_coord = pcb_gtk_coord_entry_new(0, PCB_MM_TO_COORD(2100), 0, conf_core.editor.grid_unit, CE_MEDIUM);
+	gtk_box_pack_start(GTK_BOX(vbox), expr_wizard_dlg.right_coord, FALSE, TRUE, 4);
+
+	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 4);
+
+	/* pack content */
+	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
+	gtk_widget_show_all(dialog);
+	right_hide();
+
+	/* Run the dialog */
+	expr_wizard_import(gtk_button_get_label(GTK_BUTTON(e->content)));
+	response = gtk_dialog_run(GTK_DIALOG(dialog));
+	if (response == GTK_RESPONSE_OK) {
+		char *res = expr_wizard_result(1);
+		if (res != NULL) {
+			gtk_button_set_label(GTK_BUTTON(e->content), res);
+			free(res);
+		}
+		if (e->code != NULL)
+			free(e->code);
+		e->code = expr_wizard_result(0);
+		gtk_button_set_image(GTK_BUTTON(e->content), gtk_image_new_from_icon_name("gtk-refresh", GTK_ICON_SIZE_MENU));
+		rebuild();
+	}
+	gtk_widget_destroy(dialog);
+}
+
+
+/******** Advanced search window creation and administration ********/
+static void dialog_cb(GtkDialog * dlg, gint response_id, gpointer * data)
+{
+	const char *act, *script;
+
+	switch (response_id) {
+	case GTK_RESPONSE_APPLY:
+		script = gtk_entry_get_text(GTK_ENTRY(sdlg.expr));
+		act = gtk_combo_box_get_active_text(GTK_COMBO_BOX(sdlg.action));
+		pcb_hid_actionl("query", act, script, NULL);
+		break;
+	case GTK_RESPONSE_CLOSE:
+		gtk_widget_destroy(GTK_WIDGET(dlg));
+		break;
+	}
+}
+
+static void ghid_search_window_create(GtkWidget *top_window)
+{
+	GtkWidget *vbox_win, *lab, *vbox;
+	GtkWidget *content_area;
+	const char *actions[] = { "select", "unselect", NULL };
+	const char **s;
+	int ver;
+
+	ver = pcb_hid_actionl("query", "version", NULL);
+	if (ver < 0100) {
+		sdlg.window = NULL;
+		pcb_message(PCB_MSG_ERROR, "The query plugin is not avaialble, can not do advanced search.\n");
+		return;
+	}
+
+	/* make sure the list is empty */
+	memset(&sdlg.wizard, 0, sizeof(sdlg.wizard));
+
+	sdlg.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	sdlg.window = gtk_dialog_new_with_buttons(_("Advanced search"),
+																						GTK_WINDOW(top_window),
+																						GTK_DIALOG_DESTROY_WITH_PARENT,
+																						GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, NULL);
+
+	g_signal_connect(sdlg.window, "response", G_CALLBACK(dialog_cb), NULL);
+
+	content_area = gtk_dialog_get_content_area(GTK_DIALOG(sdlg.window));
+
+	vbox_win = gtk_vbox_new(FALSE, 4);
+	gtk_container_add(GTK_CONTAINER(content_area), vbox_win);
+
+	lab = gtk_label_new("Query expression:");
+	gtk_box_pack_start(GTK_BOX(vbox_win), lab, FALSE, FALSE, 0);
+	gtk_misc_set_alignment(GTK_MISC(lab), -1, 0.);
+
+/* expr entry */
+	sdlg.expr = gtk_entry_new();
+	gtk_box_pack_start(GTK_BOX(vbox_win), sdlg.expr, FALSE, FALSE, 0);
+
+	{
+		GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
+
+		sdlg.action = gtk_combo_box_new_text();
+		gtk_widget_set_tooltip_text(sdlg.action, "Do this with any object matching the query expression");
+		for (s = actions; *s != NULL; s++)
+			gtk_combo_box_append_text(GTK_COMBO_BOX(sdlg.action), *s);
+		gtk_box_pack_start(GTK_BOX(hbox), sdlg.action, FALSE, FALSE, 0);
+		gtk_combo_box_set_active(GTK_COMBO_BOX(sdlg.action), 0);
+
+		gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("matching items"), FALSE, FALSE, 0);
+
+		gtk_box_pack_start(GTK_BOX(vbox_win), hbox, FALSE, FALSE, 0);
+	}
+
+	sdlg.wizard_enable = gtk_check_button_new_with_label("Enable wizard");
+	g_signal_connect(sdlg.wizard_enable, "toggled", G_CALLBACK(wizard_toggle_cb), NULL);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdlg.wizard_enable), 1);
+	gtk_box_pack_start(GTK_BOX(vbox_win), sdlg.wizard_enable, FALSE, FALSE, 0);
+
+/* */
+	vbox = ghid_framed_vbox(vbox_win, "wizard", 1, TRUE, 4, 10);
+
+	sdlg.wizard_vbox = gtk_vbox_new(FALSE, 6);
+	gtk_box_pack_start(GTK_BOX(vbox), sdlg.wizard_vbox, TRUE, TRUE, 4);
+
+	sdlg.new_row = gtk_button_new_with_label("Add new row");
+	g_signal_connect(sdlg.new_row, "clicked", G_CALLBACK(new_row_cb), top_window);
+	gtk_box_pack_start(GTK_BOX(vbox), sdlg.new_row, FALSE, FALSE, 0);
+	gtk_button_set_image(GTK_BUTTON(sdlg.new_row), gtk_image_new_from_icon_name("gtk-new", GTK_ICON_SIZE_MENU));
+	gtk_widget_set_tooltip_text(sdlg.new_row, "Append a row of expressions to the query with AND");
+
+
+/* Add one row of wizard to save a click in the most common case */
+	append_row(top_window);
+
+	gtk_widget_realize(sdlg.window);
+}
+
+void ghid_search_window_show(GtkWidget *top_window, gboolean raise)
+{
+	ghid_search_window_create(top_window);
+	if (sdlg.window == NULL)
+		return;
+	gtk_widget_show_all(sdlg.window);
+	wplc_place(WPLC_SEARCH, sdlg.window);
+	if (raise)
+		gtk_window_present(GTK_WINDOW(sdlg.window));
+}
diff --git a/src_plugins/lib_gtk_common/dlg_search.h b/src_plugins/lib_gtk_common/dlg_search.h
new file mode 100644
index 0000000..aab2e09
--- /dev/null
+++ b/src_plugins/lib_gtk_common/dlg_search.h
@@ -0,0 +1,28 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <gtk/gtk.h>
+
+/* advanced search dialog */
+void ghid_search_window_show(GtkWidget *top_window, gboolean raise);
+
+
diff --git a/src_plugins/hid_gtk/ghid-search-tab.h b/src_plugins/lib_gtk_common/dlg_search_tab.h
similarity index 100%
rename from src_plugins/hid_gtk/ghid-search-tab.h
rename to src_plugins/lib_gtk_common/dlg_search_tab.h
diff --git a/src_plugins/lib_gtk_common/in_keyboard.c b/src_plugins/lib_gtk_common/in_keyboard.c
new file mode 100644
index 0000000..bc047cc
--- /dev/null
+++ b/src_plugins/lib_gtk_common/in_keyboard.c
@@ -0,0 +1,118 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This code was originally written by Bill Wilson for the PCB Gtk port. */
+
+#include "config.h"
+#include "in_keyboard.h"
+#include <gdk/gdkkeysyms.h>
+#include <ctype.h>
+#include <string.h>
+
+gboolean ghid_is_modifier_key_sym(gint ksym)
+{
+	if (ksym == GDK_KEY_Shift_R || ksym == GDK_KEY_Shift_L || ksym == GDK_KEY_Control_R || ksym == GDK_KEY_Control_L)
+		return TRUE;
+	return FALSE;
+}
+
+ModifierKeysState ghid_modifier_keys_state(GtkWidget *drawing_area, GdkModifierType *state)
+{
+	GdkModifierType mask;
+	ModifierKeysState mk;
+	gboolean shift, control, mod1;
+
+	if (!state)
+		gdk_window_get_pointer(gtk_widget_get_window(drawing_area), NULL, NULL, &mask);
+	else
+		mask = *state;
+
+	shift = (mask & GDK_SHIFT_MASK);
+	control = (mask & GDK_CONTROL_MASK);
+	mod1 = (mask & GDK_MOD1_MASK);
+
+	if (shift && !control && !mod1)
+		mk = SHIFT_PRESSED;
+	else if (!shift && control && !mod1)
+		mk = CONTROL_PRESSED;
+	else if (!shift && !control && mod1)
+		mk = MOD1_PRESSED;
+	else if (shift && control && !mod1)
+		mk = SHIFT_CONTROL_PRESSED;
+	else if (shift && !control && mod1)
+		mk = SHIFT_MOD1_PRESSED;
+	else if (!shift && control && mod1)
+		mk = CONTROL_MOD1_PRESSED;
+	else if (shift && control && mod1)
+		mk = SHIFT_CONTROL_MOD1_PRESSED;
+	else
+		mk = NONE_PRESSED;
+
+	return mk;
+}
+
+gboolean ghid_port_key_press_cb(GtkWidget *drawing_area, GdkEventKey *kev, gpointer data)
+{
+	pcb_gtk_view_t *view = data;
+
+	if (ghid_is_modifier_key_sym(kev->keyval))
+		return FALSE;
+
+	if (kev->keyval <= 0xffff) {
+		GdkModifierType state = (GdkModifierType) (kev->state);
+		int slen, mods = 0;
+		static pcb_hid_cfg_keyseq_t *seq[32];
+		static int seq_len = 0;
+		unsigned short int kv = kev->keyval;
+
+		ghid_note_event_location(NULL);
+
+		extern GdkModifierType ghid_glob_mask;
+		ghid_glob_mask = state;
+
+		if (state & GDK_MOD1_MASK)    mods |= PCB_M_Alt;
+		if (state & GDK_CONTROL_MASK) mods |= PCB_M_Ctrl;
+		if (state & GDK_SHIFT_MASK) {
+/* TODO#3: this works only on US keyboard */
+			static const char *ignore_shift = "~!@#$%^&*()_+{}|:\"<>?";
+			if ((kv < 32) || (kv > 126) || (strchr(ignore_shift, kv) == NULL)) {
+				mods |= PCB_M_Shift;
+				if ((kv >= 'A') && (kv <= 'Z'))
+					kv = tolower(kv);
+			}
+		}
+
+		if (kv == GDK_KEY_ISO_Left_Tab) kv = GDK_KEY_Tab;
+		slen = pcb_hid_cfg_keys_input(&ghid_keymap, mods, kv, seq, &seq_len);
+		if (slen > 0) {
+			view->has_entered  = 1;
+			pcb_hid_cfg_keys_action(seq, slen);
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
diff --git a/src_plugins/lib_gtk_common/in_keyboard.h b/src_plugins/lib_gtk_common/in_keyboard.h
new file mode 100644
index 0000000..96cf75d
--- /dev/null
+++ b/src_plugins/lib_gtk_common/in_keyboard.h
@@ -0,0 +1,37 @@
+#ifndef PCB_GTK_IN_KEYBOARD_H
+#define PCB_GTK_IN_KEYBOARD_H
+
+#include <gtk/gtk.h>
+#include <gdk/gdkevents.h>
+
+#include "hid_cfg_input.h"
+#include "ui_zoompan.h"
+
+typedef enum {
+	NONE_PRESSED = 0,
+	SHIFT_PRESSED = PCB_M_Shift,
+	CONTROL_PRESSED = PCB_M_Ctrl,
+	MOD1_PRESSED = PCB_M_Mod1,
+	SHIFT_CONTROL_PRESSED = PCB_M_Shift | PCB_M_Ctrl,
+	SHIFT_MOD1_PRESSED = PCB_M_Shift | PCB_M_Mod1,
+	CONTROL_MOD1_PRESSED = PCB_M_Ctrl | PCB_M_Mod1,
+	SHIFT_CONTROL_MOD1_PRESSED = PCB_M_Shift | PCB_M_Ctrl | PCB_M_Mod1
+} ModifierKeysState;
+
+/** */
+gboolean ghid_is_modifier_key_sym(gint ksym);
+
+/** Returns key modifier state */
+ModifierKeysState ghid_modifier_keys_state(GtkWidget *drawing_area, GdkModifierType *state);
+
+/** Handle user keys in the output drawing area. */
+gboolean ghid_port_key_press_cb(GtkWidget *drawing_area, GdkEventKey *kev, gpointer data);
+
+/* Temporary call back to hid_gtk: */
+extern void ghid_note_event_location(GdkEventButton *ev);
+
+/* Temporary variable from hid_gtk: move the whole keymap thing here */
+extern pcb_hid_cfg_keys_t ghid_keymap;
+
+
+#endif
diff --git a/src_plugins/lib_gtk_common/in_mouse.c b/src_plugins/lib_gtk_common/in_mouse.c
new file mode 100644
index 0000000..da6427f
--- /dev/null
+++ b/src_plugins/lib_gtk_common/in_mouse.c
@@ -0,0 +1,392 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996,1997,1998,1999 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017, Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This file was originally written by Bill Wilson for the PCB Gtk port;
+   refactored for pcb-rnd by Tibor 'Igor2' Palinkas */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include "in_mouse.h"
+
+#include "const.h"
+#include "board.h"
+/*#include "action_helper.h"*/
+#include "crosshair.h"
+
+#include "in_keyboard.h"
+#include "bu_status_line.h"
+
+pcb_hid_cfg_mouse_t ghid_mouse;
+int ghid_wheel_zoom = 0;
+
+pcb_hid_cfg_mod_t ghid_mouse_button(int ev_button)
+{
+	/* GDK numbers buttons from 1..5, there seems to be no symbolic names */
+	return (PCB_MB_LEFT << (ev_button - 1));
+}
+
+static GdkCursorType old_cursor;
+GdkPixmap *XC_clock_source, *XC_clock_mask, *XC_hand_source, *XC_hand_mask, *XC_lock_source, *XC_lock_mask;
+
+#define CUSTOM_CURSOR_CLOCKWISE		(GDK_LAST_CURSOR + 10)
+#define CUSTOM_CURSOR_DRAG			  (GDK_LAST_CURSOR + 11)
+#define CUSTOM_CURSOR_LOCK			  (GDK_LAST_CURSOR + 12)
+
+#define ICON_X_HOT 8
+#define ICON_Y_HOT 8
+
+
+static GdkCursorType gport_set_cursor(pcb_gtk_mouse_t *ctx, GdkCursorType shape)
+{
+	GdkWindow *window;
+	GdkColor fg = { 0, 65535, 65535, 65535 };	/* white */
+	GdkColor bg = { 0, 0, 0, 0 };	/* black */
+	GdkCursorType old_shape = ctx->X_cursor_shape;
+
+	if (ctx->drawing_area == NULL)
+		return GDK_X_CURSOR;
+
+	window = gtk_widget_get_window(ctx->drawing_area);
+
+	if (ctx->X_cursor_shape == shape)
+		return shape;
+
+	/* check if window exists to prevent from fatal errors */
+	if (window == NULL)
+		return GDK_X_CURSOR;
+
+	ctx->X_cursor_shape = shape;
+	if (shape > GDK_LAST_CURSOR) {
+		if (shape == CUSTOM_CURSOR_CLOCKWISE)
+			ctx->X_cursor = gdk_cursor_new_from_pixmap(XC_clock_source, XC_clock_mask, &fg, &bg, ICON_X_HOT, ICON_Y_HOT);
+		else if (shape == CUSTOM_CURSOR_DRAG)
+			ctx->X_cursor = gdk_cursor_new_from_pixmap(XC_hand_source, XC_hand_mask, &fg, &bg, ICON_X_HOT, ICON_Y_HOT);
+		else if (shape == CUSTOM_CURSOR_LOCK)
+			ctx->X_cursor = gdk_cursor_new_from_pixmap(XC_lock_source, XC_lock_mask, &fg, &bg, ICON_X_HOT, ICON_Y_HOT);
+	}
+	else
+		ctx->X_cursor = gdk_cursor_new(shape);
+
+	gdk_window_set_cursor(window, ctx->X_cursor);
+	gdk_cursor_unref(ctx->X_cursor);
+
+	return old_shape;
+}
+
+void ghid_point_cursor(pcb_gtk_mouse_t *ctx)
+{
+	old_cursor = gport_set_cursor(ctx, GDK_DRAPED_BOX);
+}
+
+void ghid_hand_cursor(pcb_gtk_mouse_t *ctx)
+{
+	old_cursor = gport_set_cursor(ctx, GDK_HAND2);
+}
+
+void ghid_watch_cursor(pcb_gtk_mouse_t *ctx)
+{
+	GdkCursorType tmp;
+
+	tmp = gport_set_cursor(ctx, GDK_WATCH);
+	if (tmp != GDK_WATCH)
+		old_cursor = tmp;
+}
+
+void ghid_mode_cursor(pcb_gtk_mouse_t *ctx, int mode)
+{
+	switch (mode) {
+	case PCB_MODE_NO:
+		gport_set_cursor(ctx, (GdkCursorType) CUSTOM_CURSOR_DRAG);
+		break;
+
+	case PCB_MODE_VIA:
+		gport_set_cursor(ctx, GDK_ARROW);
+		break;
+
+	case PCB_MODE_LINE:
+		gport_set_cursor(ctx, GDK_PENCIL);
+		break;
+
+	case PCB_MODE_ARC:
+		gport_set_cursor(ctx, GDK_QUESTION_ARROW);
+		break;
+
+	case PCB_MODE_ARROW:
+		gport_set_cursor(ctx, GDK_LEFT_PTR);
+		break;
+
+	case PCB_MODE_POLYGON:
+	case PCB_MODE_POLYGON_HOLE:
+		gport_set_cursor(ctx, GDK_SB_UP_ARROW);
+		break;
+
+	case PCB_MODE_PASTE_BUFFER:
+		gport_set_cursor(ctx, GDK_HAND1);
+		break;
+
+	case PCB_MODE_TEXT:
+		gport_set_cursor(ctx, GDK_XTERM);
+		break;
+
+	case PCB_MODE_RECTANGLE:
+		gport_set_cursor(ctx, GDK_UL_ANGLE);
+		break;
+
+	case PCB_MODE_THERMAL:
+		gport_set_cursor(ctx, GDK_IRON_CROSS);
+		break;
+
+	case PCB_MODE_REMOVE:
+		gport_set_cursor(ctx, GDK_PIRATE);
+		break;
+
+	case PCB_MODE_ROTATE:
+		if (ghid_shift_is_pressed())
+			gport_set_cursor(ctx, (GdkCursorType) CUSTOM_CURSOR_CLOCKWISE);
+		else
+			gport_set_cursor(ctx, GDK_EXCHANGE);
+		break;
+
+	case PCB_MODE_COPY:
+	case PCB_MODE_MOVE:
+		gport_set_cursor(ctx, GDK_CROSSHAIR);
+		break;
+
+	case PCB_MODE_INSERT_POINT:
+		gport_set_cursor(ctx, GDK_DOTBOX);
+		break;
+
+	case PCB_MODE_LOCK:
+		gport_set_cursor(ctx, (GdkCursorType) CUSTOM_CURSOR_LOCK);
+	}
+}
+
+void ghid_corner_cursor(pcb_gtk_mouse_t *ctx)
+{
+	GdkCursorType shape;
+
+	if (pcb_crosshair.Y <= pcb_crosshair.AttachedBox.Point1.Y)
+		shape = (pcb_crosshair.X >= pcb_crosshair.AttachedBox.Point1.X) ? GDK_UR_ANGLE : GDK_UL_ANGLE;
+	else
+		shape = (pcb_crosshair.X >= pcb_crosshair.AttachedBox.Point1.X) ? GDK_LR_ANGLE : GDK_LL_ANGLE;
+	if (ctx->X_cursor_shape != shape)
+		gport_set_cursor(ctx, shape);
+}
+
+void ghid_restore_cursor(pcb_gtk_mouse_t *ctx)
+{
+	gport_set_cursor(ctx, old_cursor);
+}
+
+	/* =============================================================== */
+static gboolean got_location;
+
+/*  If user hits a key instead of the mouse button, we'll abort unless
+    it's the enter key (which accepts the current crosshair location).
+ */
+static gboolean loop_key_press_cb(GtkWidget * drawing_area, GdkEventKey * kev, GMainLoop ** loop)
+{
+	gint ksym = kev->keyval;
+
+	if (ghid_is_modifier_key_sym(ksym))
+		return TRUE;
+
+	switch (ksym) {
+	case GDK_KEY_Return:					/* Accept cursor location */
+		if (g_main_loop_is_running(*loop))
+			g_main_loop_quit(*loop);
+		break;
+
+	default:											/* Abort */
+		got_location = FALSE;
+		if (g_main_loop_is_running(*loop))
+			g_main_loop_quit(*loop);
+		break;
+	}
+	return TRUE;
+}
+
+/*  User hit a mouse button in the Output drawing area, so quit the loop
+    and the cursor values when the button was pressed will be used.
+ */
+static gboolean loop_button_press_cb(GtkWidget * drawing_area, GdkEventButton * ev, GMainLoop ** loop)
+{
+	if (g_main_loop_is_running(*loop))
+		g_main_loop_quit(*loop);
+	ghid_note_event_location(ev);
+	return TRUE;
+}
+
+/*  Run a glib GMainLoop which intercepts key and mouse button events from
+    the top level loop.  When a mouse or key is hit in the Output drawing
+    area, quit the loop so the top level loop can continue and use the
+    the mouse pointer coordinates at the time of the mouse button event.
+ */
+static gboolean run_get_location_loop(pcb_gtk_mouse_t *ctx, const gchar * message)
+{
+	static int getting_loc = 0;
+	GMainLoop *loop;
+	gulong button_handler, key_handler;
+	gint oldObjState, oldLineState, oldBoxState;
+
+	/* Do not enter the loop recursively (ask for coord only once); also don't
+	   ask for coord if the scrollwheel triggered the event, it may cause strange
+	   GUI lockups when done outside of the drawing area
+	 */
+	if ((getting_loc) || (ghid_wheel_zoom))
+		return pcb_false;
+
+	getting_loc = 1;
+	ghid_status_line_set_text(message);
+
+	oldObjState = pcb_crosshair.AttachedObject.State;
+	oldLineState = pcb_crosshair.AttachedLine.State;
+	oldBoxState = pcb_crosshair.AttachedBox.State;
+	pcb_notify_crosshair_change(pcb_false);
+	pcb_crosshair.AttachedObject.State = PCB_CH_STATE_FIRST;
+	pcb_crosshair.AttachedLine.State = PCB_CH_STATE_FIRST;
+	pcb_crosshair.AttachedBox.State = PCB_CH_STATE_FIRST;
+	ghid_hand_cursor(ctx);
+	pcb_notify_crosshair_change(pcb_true);
+
+	/*  Stop the top level GMainLoop from getting user input from keyboard
+	   and mouse so we can install our own handlers here.  Also set the
+	   control interface insensitive so all the user can do is hit a key
+	   or mouse button in the Output drawing area.
+	 */
+	ghid_interface_input_signals_disconnect();
+	ghid_interface_set_sensitive(FALSE);
+
+	got_location = TRUE;					/* Will be unset by hitting most keys */
+	button_handler =
+		g_signal_connect(G_OBJECT(ctx->drawing_area), "button_press_event", G_CALLBACK(loop_button_press_cb), &loop);
+	key_handler = g_signal_connect(G_OBJECT(ctx->top_window), "key_press_event", G_CALLBACK(loop_key_press_cb), &loop);
+
+	loop = g_main_loop_new(NULL, FALSE);
+	g_main_loop_run(loop);
+
+	g_main_loop_unref(loop);
+
+	g_signal_handler_disconnect(ctx->drawing_area, button_handler);
+	g_signal_handler_disconnect(ctx->top_window, key_handler);
+
+	ghid_interface_input_signals_connect();	/* return to normal */
+	ghid_interface_set_sensitive(TRUE);
+
+	pcb_notify_crosshair_change(pcb_false);
+	pcb_crosshair.AttachedObject.State = oldObjState;
+	pcb_crosshair.AttachedLine.State = oldLineState;
+	pcb_crosshair.AttachedBox.State = oldBoxState;
+	pcb_notify_crosshair_change(pcb_true);
+	ghid_restore_cursor(ctx);
+
+	ghid_set_status_line_label();
+
+	getting_loc = 0;
+	return got_location;
+}
+
+void ghid_get_user_xy(pcb_gtk_mouse_t *ctx, const char *msg)
+{
+	run_get_location_loop(ctx, msg);
+}
+
+/* Mouse scroll wheel events */
+gint ghid_port_window_mouse_scroll_cb(GtkWidget *widget, GdkEventScroll *ev, void *out)
+{
+	ModifierKeysState mk;
+	GdkModifierType state;
+	int button;
+
+	state = (GdkModifierType) (ev->state);
+	mk = ghid_modifier_keys_state(widget, &state);
+
+	/* X11 gtk hard codes buttons 4, 5, 6, 7 as below in
+	 * gtk+/gdk/x11/gdkevents-x11.c:1121, but quartz and windows have
+	 * special mouse scroll events, so this may conflict with a mouse
+	 * who has buttons 4 - 7 that aren't the scroll wheel?
+	 */
+	switch (ev->direction) {
+		case GDK_SCROLL_UP:    button = PCB_MB_SCROLL_UP; break;
+		case GDK_SCROLL_DOWN:  button = PCB_MB_SCROLL_DOWN; break;
+		case GDK_SCROLL_LEFT:  button = PCB_MB_SCROLL_LEFT; break;
+		case GDK_SCROLL_RIGHT: button = PCB_MB_SCROLL_RIGHT; break;
+		default: return FALSE;
+	}
+
+	ghid_wheel_zoom = 1;
+	hid_cfg_mouse_action(&ghid_mouse, button | mk);
+	ghid_wheel_zoom = 0;
+
+	return TRUE;
+}
+
+gboolean ghid_port_button_press_cb(GtkWidget *drawing_area, GdkEventButton *ev, gpointer data)
+{
+	ModifierKeysState mk;
+	GdkModifierType state;
+	GdkModifierType mask;
+/*	pcb_gtk_mouse_t *ctx = gdata;*/
+
+	/* Reject double and triple click events */
+	if (ev->type != GDK_BUTTON_PRESS)
+		return TRUE;
+
+	ghid_note_event_location(ev);
+	state = (GdkModifierType) (ev->state);
+	mk = ghid_modifier_keys_state(drawing_area, &state);
+
+	extern GdkModifierType ghid_glob_mask;
+	ghid_glob_mask = state;
+
+	gdk_window_get_pointer(gtk_widget_get_window(drawing_area), NULL, NULL, &mask);
+
+	hid_cfg_mouse_action(&ghid_mouse, ghid_mouse_button(ev->button) | mk);
+
+	ghid_port_button_press_main();
+
+	return TRUE;
+}
+
+gboolean ghid_port_button_release_cb(GtkWidget *drawing_area, GdkEventButton *ev, gpointer data)
+{
+	ModifierKeysState mk;
+	GdkModifierType state;
+/*	pcb_gtk_mouse_t *ctx = data;*/
+
+	ghid_note_event_location(ev);
+	state = (GdkModifierType) (ev->state);
+	mk = ghid_modifier_keys_state(drawing_area, &state);
+
+	hid_cfg_mouse_action(&ghid_mouse, ghid_mouse_button(ev->button) | mk | PCB_M_Release);
+
+	ghid_port_button_release_main();
+	return TRUE;
+}
+
diff --git a/src_plugins/lib_gtk_common/in_mouse.h b/src_plugins/lib_gtk_common/in_mouse.h
new file mode 100644
index 0000000..c8de2b2
--- /dev/null
+++ b/src_plugins/lib_gtk_common/in_mouse.h
@@ -0,0 +1,45 @@
+#ifndef PCB_GTK_IN_MOUSE_H
+#define PCB_GTK_IN_MOUSE_H
+
+#include "hid_cfg_input.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkevents.h>
+
+typedef struct pcb_gtk_mouse_s {
+	GtkWidget *drawing_area, *top_window;
+	GdkCursor *X_cursor;          /* used X cursor */
+	GdkCursorType X_cursor_shape; /* and its shape */
+} pcb_gtk_mouse_t;
+
+extern pcb_hid_cfg_mouse_t ghid_mouse;
+extern int ghid_wheel_zoom;
+
+pcb_hid_cfg_mod_t ghid_mouse_button(int ev_button);
+
+void ghid_hand_cursor(pcb_gtk_mouse_t *ctx);
+void ghid_point_cursor(pcb_gtk_mouse_t *ctx);
+/** Changes the cursor appearance to signifies a wait state */
+void ghid_watch_cursor(pcb_gtk_mouse_t *ctx);
+/** Changes the cursor appearance according to @mode */
+void ghid_mode_cursor(pcb_gtk_mouse_t *ctx, gint mode);
+void ghid_corner_cursor(pcb_gtk_mouse_t *ctx);
+void ghid_restore_cursor(pcb_gtk_mouse_t *ctx);
+
+void ghid_get_user_xy(pcb_gtk_mouse_t *ctx, const char *msg);
+
+gint ghid_port_window_mouse_scroll_cb(GtkWidget *widget, GdkEventScroll *ev, void *out);
+
+gboolean ghid_port_button_press_cb(GtkWidget * drawing_area, GdkEventButton * ev, gpointer data);
+gboolean ghid_port_button_release_cb(GtkWidget * drawing_area, GdkEventButton * ev, gpointer data);
+
+/* Temporary calls to hid_gtk */
+extern gboolean ghid_idle_cb(gpointer data);
+extern int ghid_shift_is_pressed();
+extern void ghid_interface_input_signals_disconnect(void);
+extern void ghid_interface_input_signals_connect(void);
+extern void ghid_interface_set_sensitive(gboolean sensitive);
+extern void ghid_port_button_press_main(void);
+extern void ghid_port_button_release_main(void);
+
+#endif
diff --git a/src_plugins/lib_gtk_common/lib_gtk_common.c b/src_plugins/lib_gtk_common/lib_gtk_common.c
new file mode 100644
index 0000000..8870b2f
--- /dev/null
+++ b/src_plugins/lib_gtk_common/lib_gtk_common.c
@@ -0,0 +1,34 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2017 Tibor Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA
+ *  haceaton at aplcomm.jhuapl.edu
+ *
+ */
+
+#include <stdlib.h>
+#include "plugins.h"
+
+pcb_uninit_t hid_lib_gtk_common_init(void)
+{
+	return NULL;
+}
+
diff --git a/src_plugins/lib_gtk_common/ui_zoompan.c b/src_plugins/lib_gtk_common/ui_zoompan.c
new file mode 100644
index 0000000..13128c8
--- /dev/null
+++ b/src_plugins/lib_gtk_common/ui_zoompan.c
@@ -0,0 +1,493 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+#include "ui_zoompan.h"
+
+#include "unit.h"
+#include "action_helper.h"
+#include "error.h"
+#include "conf_core.h"
+#include "board.h"
+#include "compat_misc.h"
+#include "compat_nls.h"
+#include "draw.h"
+#include "data.h"
+#include "layer_vis.h"
+#include "bu_status_line.h"
+
+/* defined by the hid (gtk version or render specific): */
+void ghid_pan_common(void);
+void ghid_port_ranges_scale(void);
+void ghid_invalidate_all();
+
+double pcb_gtk_clamp_zoom(const pcb_gtk_view_t *vw, double coord_per_px)
+{
+	double min_zoom, max_zoom, max_zoom_w, max_zoom_h, out_zoom;
+
+	min_zoom = 200;
+
+	/* max zoom is calculated so that zoom * canvas_size * 2 doesn't overflow pcb_coord_t */
+	max_zoom_w = (double)COORD_MAX / (double)vw->canvas_width;
+	max_zoom_h = (double)COORD_MAX / (double)vw->canvas_height;
+	max_zoom = MIN(max_zoom_w, max_zoom_h) / 2.0;
+
+	out_zoom = coord_per_px;
+	if (out_zoom < min_zoom)
+		out_zoom = min_zoom;
+	if (out_zoom > max_zoom)
+		out_zoom = max_zoom;
+
+	return out_zoom;
+}
+
+
+static void pcb_gtk_pan_common(pcb_gtk_view_t *v)
+{
+	int event_x, event_y;
+
+	/* We need to fix up the PCB coordinates corresponding to the last
+	 * event so convert it back to event coordinates temporarily. */
+	pcb_gtk_coords_pcb2event(v, v->pcb_x, v->pcb_y, &event_x, &event_y);
+
+	/* Don't pan so far the board is completely off the screen */
+	v->x0 = MAX(-v->width, v->x0);
+	v->y0 = MAX(-v->height, v->y0);
+	v->x0 = MIN(v->x0, PCB->MaxWidth);
+	v->y0 = MIN(v->y0, PCB->MaxHeight);
+
+	/* Fix up noted event coordinates to match where we clamped. Alternatively
+	 * we could call ghid_note_event_location (NULL); to get a new pointer
+	 * location, but this costs us an xserver round-trip (on X11 platforms)
+	 */
+	pcb_gtk_coords_event2pcb(v, event_x, event_y, &v->pcb_x, &v->pcb_y);
+
+	ghid_pan_common();
+}
+
+pcb_bool pcb_gtk_coords_pcb2event(const pcb_gtk_view_t *v, pcb_coord_t pcb_x, pcb_coord_t pcb_y, int *event_x, int *event_y)
+{
+	*event_x = DRAW_X(v, pcb_x);
+	*event_y = DRAW_Y(v, pcb_y);
+
+	return pcb_true;
+}
+
+pcb_bool pcb_gtk_coords_event2pcb(const pcb_gtk_view_t *v, int event_x, int event_y, pcb_coord_t * pcb_x, pcb_coord_t * pcb_y)
+{
+	*pcb_x = EVENT_TO_PCB_X(v, event_x);
+	*pcb_y = EVENT_TO_PCB_Y(v, event_y);
+
+	return pcb_true;
+}
+
+void pcb_gtk_zoom_post(pcb_gtk_view_t *v)
+{
+	v->coord_per_px = pcb_gtk_clamp_zoom(v, v->coord_per_px);
+	v->width = v->canvas_width * v->coord_per_px;
+	v->height = v->canvas_height * v->coord_per_px;
+}
+
+/* gport->view.coord_per_px:
+ * zoom value is PCB units per screen pixel.  Larger numbers mean zooming
+ * out - the largest value means you are looking at the whole board.
+ *
+ * gport->view_width and gport->view_height are in PCB coordinates
+ */
+static void ghid_zoom_view_abs(pcb_gtk_view_t *v, pcb_coord_t center_x, pcb_coord_t center_y, double new_zoom)
+{
+	double clamped_zoom;
+	double xtmp, ytmp;
+	pcb_coord_t cmaxx, cmaxy;
+
+	clamped_zoom = pcb_gtk_clamp_zoom(v, new_zoom);
+	if (clamped_zoom != new_zoom)
+		return;
+
+	if (v->coord_per_px == new_zoom)
+		return;
+
+	/* Do not allow zoom level that'd overflow the coord type */
+	cmaxx = v->canvas_width  * (new_zoom / 2.0);
+	cmaxy = v->canvas_height * (new_zoom / 2.0);
+	if ((cmaxx >= COORD_MAX/2) || (cmaxy >= COORD_MAX/2)) {
+		return;
+	}
+
+	xtmp = (SIDE_X(center_x) - v->x0) / (double) v->width;
+	ytmp = (SIDE_Y(center_y) - v->y0) / (double) v->height;
+
+	v->coord_per_px = new_zoom;
+	pcb_pixel_slop = new_zoom;
+	ghid_port_ranges_scale();
+
+	v->x0 = SIDE_X(center_x) - xtmp * v->width;
+	v->y0 = SIDE_Y(center_y) - ytmp * v->height;
+
+	pcb_gtk_pan_common(v);
+
+	ghid_set_status_line_label();
+}
+
+
+
+void pcb_gtk_zoom_view_rel(pcb_gtk_view_t *v, pcb_coord_t center_x, pcb_coord_t center_y, double factor)
+{
+	ghid_zoom_view_abs(v, center_x, center_y, v->coord_per_px * factor);
+}
+
+void pcb_gtk_zoom_view_fit(pcb_gtk_view_t *v)
+{
+	pcb_gtk_pan_view_abs(v, SIDE_X(0), SIDE_Y(0), 0, 0);
+	ghid_zoom_view_abs(v, SIDE_X(0), SIDE_Y(0), MAX(PCB->MaxWidth / v->canvas_width, PCB->MaxHeight / v->canvas_height));
+}
+
+static void pcb_gtk_flip_view(pcb_gtk_view_t *v, pcb_coord_t center_x, pcb_coord_t center_y, pcb_bool flip_x, pcb_bool flip_y)
+{
+	int widget_x, widget_y;
+
+	pcb_draw_inhibit_inc();
+
+	/* Work out where on the screen the flip point is */
+	pcb_gtk_coords_pcb2event(v, center_x, center_y, &widget_x, &widget_y);
+
+	conf_set_design("editor/view/flip_x", "%d", conf_core.editor.view.flip_x != flip_x);
+	conf_set_design("editor/view/flip_y", "%d", conf_core.editor.view.flip_y != flip_y);
+
+	/* Pan the board so the center location remains in the same place */
+	pcb_gtk_pan_view_abs(v, center_x, center_y, widget_x, widget_y);
+
+	pcb_draw_inhibit_dec();
+
+	ghid_invalidate_all();
+}
+
+void pcb_gtk_pan_view_abs(pcb_gtk_view_t *v, pcb_coord_t pcb_x, pcb_coord_t pcb_y, int widget_x, int widget_y)
+{
+	v->x0 = SIDE_X(pcb_x) - widget_x * v->coord_per_px;
+	v->y0 = SIDE_Y(pcb_y) - widget_y * v->coord_per_px;
+
+	pcb_gtk_pan_common(v);
+}
+
+void pcb_gtk_pan_view_rel(pcb_gtk_view_t *v, pcb_coord_t dx, pcb_coord_t dy)
+{
+	v->x0 += dx;
+	v->y0 += dy;
+
+	pcb_gtk_pan_common(v);
+}
+
+
+/* ------------------------------------------------------------ */
+
+const char pcb_acts_zoom[] = "Zoom()\n" "Zoom(factor)";
+
+const char pcb_acth_zoom[] = N_("Various zoom factor changes.");
+
+/* %start-doc actions Zoom
+Changes the zoom (magnification) of the view of the board.  If no
+arguments are passed, the view is scaled such that the board just fits
+inside the visible window (i.e. ``view all'').  Otherwise,
+ at var{factor} specifies a change in zoom factor.  It may be prefixed by
+ at code{+}, @code{-}, or @code{=} to change how the zoom factor is
+modified.  The @var{factor} is a floating point number, such as
+ at code{1.5} or @code{0.75}.
+
+ at table @code
+
+ at item + at var{factor}
+Values greater than 1.0 cause the board to be drawn smaller; more of
+the board will be visible.  Values between 0.0 and 1.0 cause the board
+to be drawn bigger; less of the board will be visible.
+
+ at item - at var{factor}
+Values greater than 1.0 cause the board to be drawn bigger; less of
+the board will be visible.  Values between 0.0 and 1.0 cause the board
+to be drawn smaller; more of the board will be visible.
+
+ at item =@var{factor}
+
+The @var{factor} is an absolute zoom factor; the unit for this value
+is "PCB units per screen pixel".  Since PCB units are 0.01 mil, a
+ at var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
+about the actual resolution of most screens - resulting in an "actual
+size" board.  Similarly, a @var{factor} of 100 gives you a 10x actual
+size.
+
+ at end table
+
+Note that zoom factors of zero are silently ignored.
+
+
+
+%end-doc */
+
+int pcb_gtk_zoom(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	const char *vp;
+	double v;
+
+	if (argc > 1)
+		PCB_ACT_FAIL(zoom);
+
+	if (argc < 1) {
+		pcb_gtk_zoom_view_fit(vw);
+		return 0;
+	}
+
+	vp = argv[0];
+	if (*vp == '+' || *vp == '-' || *vp == '=')
+		vp++;
+	v = g_ascii_strtod(vp, 0);
+	if (v <= 0)
+		return 1;
+	switch (argv[0][0]) {
+	case '-':
+		pcb_gtk_zoom_view_rel(vw, x, y, 1 / v);
+		break;
+	default:
+	case '+':
+		pcb_gtk_zoom_view_rel(vw, x, y, v);
+		break;
+	case '=':
+		ghid_zoom_view_abs(vw, x, y, v);
+		break;
+	}
+
+	return 0;
+}
+
+/* ------------------------------------------------------------ */
+
+const char pcb_acts_center[] = "Center()\n";
+const char pcb_acth_center[] = N_("Moves the pointer to the center of the window.");
+
+/* %start-doc actions Center
+
+Move the pointer to the center of the window, but only if it's
+currently within the window already.
+
+%end-doc */
+
+int pcb_gtk_act_center(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t pcb_x, pcb_coord_t pcb_y, int offset_x, int offset_y, int *out_pointer_x, int *out_pointer_y)
+{
+	int widget_x, widget_y;
+
+	if (argc != 0)
+		PCB_ACT_FAIL(center);
+
+	/* Aim to put the given x, y PCB coordinates in the center of the widget */
+	widget_x = vw->canvas_width / 2;
+	widget_y = vw->canvas_height / 2;
+
+	pcb_gtk_pan_view_abs(vw, pcb_x, pcb_y, widget_x, widget_y);
+
+	/* Now move the mouse pointer to the place where the board location
+	 * actually ended up.
+	 *
+	 * XXX: Should only do this if we confirm we are inside our window?
+	 */
+
+	pcb_gtk_coords_pcb2event(vw, pcb_x, pcb_y, &widget_x, &widget_y);
+
+	*out_pointer_x = offset_x + widget_x;
+	*out_pointer_y = offset_y + widget_y;
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+const char pcb_acts_swapsides[] = "SwapSides(|v|h|r)";
+const char pcb_acth_swapsides[] = N_("Swaps the side of the board you're looking at.");
+
+/* %start-doc actions SwapSides
+
+This action changes the way you view the board.
+
+ at table @code
+
+ at item v
+Flips the board over vertically (up/down).
+
+ at item h
+Flips the board over horizontally (left/right), like flipping pages in
+a book.
+
+ at item r
+Rotates the board 180 degrees without changing sides.
+
+ at end table
+
+If no argument is given, the board isn't moved but the opposite side
+is shown.
+
+Normally, this action changes which pads and silk layer are drawn as
+pcb_true silk, and which are drawn as the "invisible" layer.  It also
+determines which solder mask you see.
+
+As a special case, if the layer group for the side you're looking at
+is visible and currently active, and the layer group for the opposite
+is not visible (i.e. disabled), then this action will also swap which
+layer group is visible and active, effectively swapping the ``working
+side'' of the board.
+
+%end-doc */
+
+
+int pcb_gtk_swap_sides(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	pcb_layergrp_id_t active_group = pcb_layer_get_group(pcb_layer_stack[0]);
+	pcb_layergrp_id_t comp_group = -1, solder_group = -1;
+	pcb_bool comp_on = pcb_false, solder_on = pcb_false;
+
+	if (pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &solder_group, 1) > 0)
+		solder_on = LAYER_PTR(PCB->LayerGroups.grp[solder_group].lid[0])->On;
+
+	if (pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &comp_group, 1) > 0)
+		comp_on = LAYER_PTR(PCB->LayerGroups.grp[comp_group].lid[0])->On;
+
+	pcb_draw_inhibit_inc();
+	if (argc > 0) {
+		switch (argv[0][0]) {
+		case 'h':
+		case 'H':
+			pcb_gtk_flip_view(vw, vw->pcb_x, vw->pcb_y, pcb_true, pcb_false);
+			break;
+		case 'v':
+		case 'V':
+			pcb_gtk_flip_view(vw, vw->pcb_x, vw->pcb_y, pcb_false, pcb_true);
+			break;
+		case 'r':
+		case 'R':
+			pcb_gtk_flip_view(vw, vw->pcb_x, vw->pcb_y, pcb_true, pcb_true);
+			conf_toggle_editor(show_solder_side); /* Swapped back below */
+			break;
+		default:
+			pcb_draw_inhibit_dec();
+			return 1;
+		}
+	}
+
+	conf_toggle_editor(show_solder_side);
+
+	if ((active_group == comp_group && comp_on && !solder_on) || (active_group == solder_group && solder_on && !comp_on)) {
+		pcb_bool new_solder_vis = conf_core.editor.show_solder_side;
+
+		if (comp_group >= 0)
+			pcb_layervis_change_group_vis(PCB->LayerGroups.grp[comp_group].lid[0], !new_solder_vis, !new_solder_vis);
+		if (solder_group >= 0)
+			pcb_layervis_change_group_vis(PCB->LayerGroups.grp[solder_group].lid[0], new_solder_vis, new_solder_vis);
+	}
+
+	pcb_draw_inhibit_dec();
+
+	ghid_invalidate_all();
+
+	return 0;
+}
+
+/* ------------------------------------------------------------ */
+const char pcb_acts_scroll[] = "Scroll(up|down|left|right, [div])";
+const char pcb_acth_scroll[] = N_("Scroll the viewport.");
+
+/* % start-doc actions Scroll
+
+ at item up|down|left|right
+Specifies the direction to scroll
+
+ at item div
+Optional.  Specifies how much to scroll by.  The viewport is scrolled
+by 1/div of what is visible, so div = 1 scrolls a whole page. If not
+default is given, div=40.
+
+%end-doc */
+
+int pcb_gtk_act_scroll(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	gdouble dx = 0.0, dy = 0.0;
+	int div = 40;
+
+	if (argc != 1 && argc != 2)
+		PCB_ACT_FAIL(scroll);
+
+	if (argc == 2)
+		div = atoi(argv[1]);
+
+	if (pcb_strcasecmp(argv[0], "up") == 0)
+		dy = -vw->height / div;
+	else if (pcb_strcasecmp(argv[0], "down") == 0)
+		dy = vw->height / div;
+	else if (pcb_strcasecmp(argv[0], "right") == 0)
+		dx = vw->width / div;
+	else if (pcb_strcasecmp(argv[0], "left") == 0)
+		dx = -vw->width / div;
+	else
+		PCB_ACT_FAIL(scroll);
+
+	pcb_gtk_pan_view_rel(vw, dx, dy);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------ */
+const char pcb_acts_pan[] = "Pan([thumb], Mode)";
+const char pcb_acth_pan[] = N_("Start or stop panning (Mode = 1 to start, 0 to stop)\n" "Optional thumb argument is ignored for now in gtk hid.\n");
+
+/* %start-doc actions Pan
+
+Start or stop panning.  To start call with Mode = 1, to stop call with
+Mode = 0.
+
+%end-doc */
+
+int pcb_gtk_act_pan(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
+{
+	int mode;
+
+	if (argc != 1 && argc != 2)
+		PCB_ACT_FAIL(pan);
+
+	if (argc == 1) {
+		mode = atoi(argv[0]);
+	}
+	else {
+		mode = atoi(argv[1]);
+		pcb_message(PCB_MSG_WARNING, _("The gtk gui currently ignores the optional first argument to the Pan action.\nFeel free to provide patches.\n"));
+	}
+
+	vw->panning = mode;
+
+	return 0;
+}
+
+
+void pcb_gtk_get_coords(pcb_gtk_mouse_t *mouse, pcb_gtk_view_t *vw, const char *msg, pcb_coord_t * x, pcb_coord_t * y)
+{
+	if (!vw->has_entered && msg)
+		ghid_get_user_xy(mouse, msg);
+	if (vw->has_entered) {
+		*x = vw->pcb_x;
+		*y = vw->pcb_y;
+	}
+}
diff --git a/src_plugins/lib_gtk_common/ui_zoompan.h b/src_plugins/lib_gtk_common/ui_zoompan.h
new file mode 100644
index 0000000..6e79551
--- /dev/null
+++ b/src_plugins/lib_gtk_common/ui_zoompan.h
@@ -0,0 +1,106 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef PCB_LIB_GTK_COMMON_UI_ZOOMPAN_H
+#define PCB_LIB_GTK_COMMON_UI_ZOOMPAN_H
+
+#include <glib.h>
+#include "unit.h"
+#include "pcb_bool.h"
+#include "in_mouse.h"
+
+	/* Go from from the grid units in use (millimeters or mils) to PCB units
+	   |  and back again.
+	   |  PCB keeps values internally higher precision, but gui
+	   |  widgets (spin buttons, labels, etc) need mils or millimeters.
+	 */
+#define	FROM_PCB_UNITS(v)	pcb_coord_to_unit(conf_core.editor.grid_unit, v)
+#define	TO_PCB_UNITS(v)		pcb_unit_to_coord(conf_core.editor.grid_unit, v)
+
+#define SIDE_X(x)         ((conf_core.editor.view.flip_x ? PCB->MaxWidth - (x) : (x)))
+#define SIDE_Y(y)         ((conf_core.editor.view.flip_y ? PCB->MaxHeight - (y) : (y)))
+
+#define	DRAW_X(view, x)         (gint)((SIDE_X(x) - (view)->x0) / (view)->coord_per_px)
+#define	DRAW_Y(view, y)         (gint)((SIDE_Y(y) - (view)->y0) / (view)->coord_per_px)
+
+#define	EVENT_TO_PCB_X(view, x) SIDE_X((gint)((x) * (view)->coord_per_px + (view)->x0))
+#define	EVENT_TO_PCB_Y(view, y) SIDE_Y((gint)((y) * (view)->coord_per_px + (view)->y0))
+
+
+typedef struct {
+	double coord_per_px;					/* Zoom level described as PCB units per screen pixel */
+
+	pcb_coord_t x0;
+	pcb_coord_t y0;
+	pcb_coord_t width;
+	pcb_coord_t height;
+
+	gint canvas_width, canvas_height;
+
+	gboolean has_entered;
+	gboolean panning;
+	pcb_coord_t pcb_x, pcb_y;						/* PCB coordinates of the mouse pointer */
+	pcb_coord_t crosshair_x, crosshair_y;	/* PCB coordinates of the crosshair     */
+} pcb_gtk_view_t;
+
+/* take coord_per_px and validate it against other view parameters. Return
+    coord_per_px or the clamped value if it was too small or too large. */
+double pcb_gtk_clamp_zoom(const pcb_gtk_view_t *vw, double coord_per_px);
+
+void pcb_gtk_pan_view_abs(pcb_gtk_view_t *v, pcb_coord_t pcb_x, pcb_coord_t pcb_y, int widget_x, int widget_y);
+void pcb_gtk_pan_view_rel(pcb_gtk_view_t *v, pcb_coord_t dx, pcb_coord_t dy);
+void pcb_gtk_zoom_view_fit(pcb_gtk_view_t *v);
+void pcb_gtk_zoom_view_rel(pcb_gtk_view_t *v, pcb_coord_t center_x, pcb_coord_t center_y, double factor);
+
+/** Updates width and heigth using the new zoom level; call after a call
+    to pcb_gtk_zoom_*() */
+void pcb_gtk_zoom_post(pcb_gtk_view_t *v);
+
+pcb_bool pcb_gtk_coords_pcb2event(const pcb_gtk_view_t *v, pcb_coord_t pcb_x, pcb_coord_t pcb_y, int *event_x, int *event_y);
+pcb_bool pcb_gtk_coords_event2pcb(const pcb_gtk_view_t *v, int event_x, int event_y, pcb_coord_t * pcb_x, pcb_coord_t * pcb_y);
+
+
+extern const char pcb_acts_zoom[];
+extern const char pcb_acth_zoom[];
+int pcb_gtk_zoom(pcb_gtk_view_t *v, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
+
+extern const char pcb_acts_center[];
+extern const char pcb_acth_center[];
+int pcb_gtk_act_center(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t pcb_x, pcb_coord_t pcb_y, int offset_x, int offset_y, int *out_pointer_x, int *out_pointer_y);
+
+extern const char pcb_acts_swapsides[];
+extern const char pcb_acth_swapsides[];
+int pcb_gtk_swap_sides(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
+
+extern const char pcb_acts_scroll[];
+extern const char pcb_acth_scroll[];
+int pcb_gtk_act_scroll(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
+
+extern const char pcb_acts_pan[];
+extern const char pcb_acth_pan[];
+int pcb_gtk_act_pan(pcb_gtk_view_t *vw, int argc, const char **argv, pcb_coord_t x, pcb_coord_t y);
+
+void pcb_gtk_get_coords(pcb_gtk_mouse_t *mouse, pcb_gtk_view_t *vw, const char *msg, pcb_coord_t * x, pcb_coord_t * y);
+
+#endif
diff --git a/src_plugins/lib_gtk_common/util_block_hook.c b/src_plugins/lib_gtk_common/util_block_hook.c
new file mode 100644
index 0000000..6a84f68
--- /dev/null
+++ b/src_plugins/lib_gtk_common/util_block_hook.c
@@ -0,0 +1,78 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "util_block_hook.h"
+
+typedef struct {
+	GSource source;
+	void (*func) (pcb_hidval_t user_data);
+	pcb_hidval_t user_data;
+} BlockHookSource;
+
+static GSourceFuncs ghid_block_hook_funcs = {
+	ghid_block_hook_prepare,
+	ghid_block_hook_check,
+	ghid_block_hook_dispatch,
+	NULL													/* No destroy notification */
+};
+
+gboolean ghid_block_hook_prepare(GSource * source, gint * timeout)
+{
+	pcb_hidval_t data = ((BlockHookSource *) source)->user_data;
+	((BlockHookSource *) source)->func(data);
+	return FALSE;
+}
+
+gboolean ghid_block_hook_check(GSource * source)
+{
+	return FALSE;
+}
+
+gboolean ghid_block_hook_dispatch(GSource * source, GSourceFunc callback, gpointer user_data)
+{
+	return FALSE;
+}
+
+pcb_hidval_t ghid_add_block_hook(void (*func) (pcb_hidval_t data), pcb_hidval_t user_data)
+{
+	pcb_hidval_t ret;
+	BlockHookSource *source;
+
+	source = (BlockHookSource *) g_source_new(&ghid_block_hook_funcs, sizeof(BlockHookSource));
+
+	source->func = func;
+	source->user_data = user_data;
+
+	g_source_attach((GSource *) source, NULL);
+
+	ret.ptr = (void *) source;
+	return ret;
+}
+
+void ghid_stop_block_hook(pcb_hidval_t mlpoll)
+{
+	GSource *source = (GSource *) mlpoll.ptr;
+	g_source_destroy(source);
+}
diff --git a/src_plugins/lib_gtk_common/util_block_hook.h b/src_plugins/lib_gtk_common/util_block_hook.h
new file mode 100644
index 0000000..7cc7ef0
--- /dev/null
+++ b/src_plugins/lib_gtk_common/util_block_hook.h
@@ -0,0 +1,9 @@
+#include <glib.h>
+#include "hid.h"
+
+pcb_hidval_t ghid_add_block_hook(void (*func) (pcb_hidval_t data), pcb_hidval_t user_data);
+void ghid_stop_block_hook(pcb_hidval_t mlpoll);
+
+gboolean ghid_block_hook_prepare(GSource * source, gint * timeout);
+gboolean ghid_block_hook_check(GSource * source);
+gboolean ghid_block_hook_dispatch(GSource * source, GSourceFunc callback, gpointer user_data);
diff --git a/src_plugins/hid_gtk/gtk_debug.h b/src_plugins/lib_gtk_common/util_gtk_debug.h
similarity index 100%
rename from src_plugins/hid_gtk/gtk_debug.h
rename to src_plugins/lib_gtk_common/util_gtk_debug.h
diff --git a/src_plugins/lib_gtk_common/util_str.c b/src_plugins/lib_gtk_common/util_str.c
new file mode 100644
index 0000000..c2d39d6
--- /dev/null
+++ b/src_plugins/lib_gtk_common/util_str.c
@@ -0,0 +1,55 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This module, was originally written by Bill Wilson and the functions
+ * here are Copyright (C) 2004 by Bill Wilson.  These functions are utility
+ * functions which are taken from my other GPL'd projects gkrellm and
+ * gstocks and are copied here for the Gtk PCB port.
+ *
+ * pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ */
+
+#include "config.h"
+#include <string.h>
+#include "util_str.h"
+
+gboolean pcb_gtk_g_strdup(gchar ** dst, const gchar * src)
+{
+	if ((dst == NULL) || ((*dst == NULL) && (src == NULL)))
+		return FALSE;
+	if (*dst) {
+		if (src && !strcmp(*dst, src))
+			return FALSE;
+		g_free(*dst);
+	}
+	*dst = g_strdup(src);
+	return TRUE;
+}
+
+const gchar *pcb_str_strip_left(const gchar * s)
+{
+	if (s != NULL) {
+		while ((*s == ' ') || (*s == '\t'))
+			s++;
+	}
+	return s;
+}
diff --git a/src_plugins/lib_gtk_common/util_str.h b/src_plugins/lib_gtk_common/util_str.h
new file mode 100644
index 0000000..842ab4d
--- /dev/null
+++ b/src_plugins/lib_gtk_common/util_str.h
@@ -0,0 +1,40 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This module, was originally written by Bill Wilson and the functions
+ * here are Copyright (C) 2004 by Bill Wilson.  These functions are utility
+ * functions which are taken from my other GPL'd projects gkrellm and
+ * gstocks and are copied here for the Gtk PCB port.
+ *
+ * pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ */
+
+#ifndef PCB_LIB_GTK_COMMON_UTIL_STR_H
+#define PCB_LIB_GTK_COMMON_UTIL_STR_H
+
+#include <glib.h>
+
+gboolean pcb_gtk_g_strdup(gchar ** dst, const gchar * src);
+
+/** Moves the @s pointer starting from the beginning, skipping spaces. */
+const gchar *pcb_str_strip_left(const gchar * s);
+#endif
diff --git a/src_plugins/lib_gtk_common/util_timer.c b/src_plugins/lib_gtk_common/util_timer.c
new file mode 100644
index 0000000..e4030e0
--- /dev/null
+++ b/src_plugins/lib_gtk_common/util_timer.c
@@ -0,0 +1,63 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "util_timer.h"
+#include "conf_core.h"
+
+typedef struct {
+	void (*func) (pcb_hidval_t);
+	guint id;
+	pcb_hidval_t user_data;
+} GuiTimer;
+
+	/* We need a wrapper around the hid timer because a gtk timer needs
+	   |  to return FALSE else the timer will be restarted.
+	 */
+static gboolean ghid_timer(GuiTimer * timer)
+{
+	(*timer->func) (timer->user_data);
+	ghid_mode_cursor_main(conf_core.editor.mode);
+	return FALSE;									/* Turns timer off */
+}
+
+pcb_hidval_t ghid_add_timer(void (*func) (pcb_hidval_t user_data), unsigned long milliseconds, pcb_hidval_t user_data)
+{
+	GuiTimer *timer = g_new0(GuiTimer, 1);
+	pcb_hidval_t ret;
+
+	timer->func = func;
+	timer->user_data = user_data;
+	timer->id = g_timeout_add(milliseconds, (GSourceFunc) ghid_timer, timer);
+	ret.ptr = (void *) timer;
+	return ret;
+}
+
+void ghid_stop_timer(pcb_hidval_t timer)
+{
+	void *ptr = timer.ptr;
+
+	g_source_remove(((GuiTimer *) ptr)->id);
+	g_free(ptr);
+}
diff --git a/src_plugins/lib_gtk_common/util_timer.h b/src_plugins/lib_gtk_common/util_timer.h
new file mode 100644
index 0000000..33e1f02
--- /dev/null
+++ b/src_plugins/lib_gtk_common/util_timer.h
@@ -0,0 +1,7 @@
+#include "hid.h"
+
+pcb_hidval_t ghid_add_timer(void (*func) (pcb_hidval_t user_data), unsigned long milliseconds, pcb_hidval_t user_data);
+void ghid_stop_timer(pcb_hidval_t timer);
+
+/* Temporary call backs to hid_gtk: */
+extern void ghid_mode_cursor_main(int mode);
diff --git a/src_plugins/lib_gtk_common/util_watch.c b/src_plugins/lib_gtk_common/util_watch.c
new file mode 100644
index 0000000..9221b9e
--- /dev/null
+++ b/src_plugins/lib_gtk_common/util_watch.c
@@ -0,0 +1,96 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+#include "util_watch.h"
+#include "in_mouse.h"
+#include "conf_core.h"
+
+typedef struct {
+	void (*func) (pcb_hidval_t, int, unsigned int, pcb_hidval_t);
+	pcb_hidval_t user_data;
+	int fd;
+	GIOChannel *channel;
+	gint id;
+} GuiWatch;
+
+	/* We need a wrapper around the hid file watch to pass the correct flags
+	 */
+static gboolean ghid_watch(GIOChannel * source, GIOCondition condition, gpointer data)
+{
+	unsigned int pcb_condition = 0;
+	pcb_hidval_t x;
+	GuiWatch *watch = (GuiWatch *) data;
+
+	if (condition & G_IO_IN)
+		pcb_condition |= PCB_WATCH_READABLE;
+	if (condition & G_IO_OUT)
+		pcb_condition |= PCB_WATCH_WRITABLE;
+	if (condition & G_IO_ERR)
+		pcb_condition |= PCB_WATCH_ERROR;
+	if (condition & G_IO_HUP)
+		pcb_condition |= PCB_WATCH_HANGUP;
+
+	x.ptr = (void *) watch;
+	watch->func(x, watch->fd, pcb_condition, watch->user_data);
+
+	ghid_mode_cursor_main(conf_core.editor.mode);
+
+	return TRUE;									/* Leave watch on */
+}
+
+pcb_hidval_t ghid_watch_file(int fd, unsigned int condition,
+								void (*func) (pcb_hidval_t watch, int fd, unsigned int condition, pcb_hidval_t user_data),
+								pcb_hidval_t user_data)
+{
+	GuiWatch *watch = g_new0(GuiWatch, 1);
+	pcb_hidval_t ret;
+	unsigned int glib_condition = 0;
+
+	if (condition & PCB_WATCH_READABLE)
+		glib_condition |= G_IO_IN;
+	if (condition & PCB_WATCH_WRITABLE)
+		glib_condition |= G_IO_OUT;
+	if (condition & PCB_WATCH_ERROR)
+		glib_condition |= G_IO_ERR;
+	if (condition & PCB_WATCH_HANGUP)
+		glib_condition |= G_IO_HUP;
+
+	watch->func = func;
+	watch->user_data = user_data;
+	watch->fd = fd;
+	watch->channel = g_io_channel_unix_new(fd);
+	watch->id = g_io_add_watch(watch->channel, (GIOCondition) glib_condition, ghid_watch, watch);
+
+	ret.ptr = (void *) watch;
+	return ret;
+}
+
+void ghid_unwatch_file(pcb_hidval_t data)
+{
+	GuiWatch *watch = (GuiWatch *) data.ptr;
+
+	g_io_channel_shutdown(watch->channel, TRUE, NULL);
+	g_io_channel_unref(watch->channel);
+	g_free(watch);
+}
diff --git a/src_plugins/lib_gtk_common/util_watch.h b/src_plugins/lib_gtk_common/util_watch.h
new file mode 100644
index 0000000..ce6e7f0
--- /dev/null
+++ b/src_plugins/lib_gtk_common/util_watch.h
@@ -0,0 +1,13 @@
+#include "hid.h"
+
+pcb_hidval_t ghid_watch_file(int fd, unsigned int condition,
+								void (*func) (pcb_hidval_t watch, int fd, unsigned int condition, pcb_hidval_t user_data),
+								pcb_hidval_t user_data);
+
+void ghid_unwatch_file(pcb_hidval_t data);
+
+
+/* Temporary call backs to hid_gtk: */
+extern void ghid_mode_cursor_main(int mode);
+
+
diff --git a/src_plugins/lib_gtk_common/win_place.c b/src_plugins/lib_gtk_common/win_place.c
new file mode 100644
index 0000000..cf01a60
--- /dev/null
+++ b/src_plugins/lib_gtk_common/win_place.c
@@ -0,0 +1,115 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2016 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "config.h"
+#include "win_place.h"
+#include "conf_core.h"
+
+#define CONF_PREFIX "plugins/hid_gtk/window_geometry/"
+static const char *conf_prefix[WPLC_max] = { /* order DOES matter */
+	"top_",
+	"log_",
+	"drc_",
+	"library_",
+	"netlist_",
+	"keyref_",
+	"pinout_",
+	"search_"
+};
+
+static GtkWidget *wplc_windows[WPLC_max];
+
+/* true if the given configuration item has exactly one integer value */
+#define HAVE(native) ((native != NULL) && ((native)->used == 1) && ((native)->type == CFN_INTEGER))
+
+void wplc_place(wplc_win_t id, GtkWidget *new_win)
+{
+	char path[128], *pe;
+	conf_native_t *nx, *ny, *nw, *nh;
+	GtkWidget *win;
+
+	if ((id < 0) || (id >= WPLC_max))
+		return; /* invalid window */
+
+	if (!conf_core.editor.auto_place) {
+		if (new_win != NULL) /* remember window widgets in case editor.auto_place gets enabled later */
+			wplc_windows[id] = new_win;
+		return; /* feature disabled */
+	}
+
+	/* build base path for the specific window */
+	pe = path;
+	strcpy(pe, CONF_PREFIX);      pe += strlen(CONF_PREFIX);
+	strcpy(pe, conf_prefix[id]);  pe += strlen(conf_prefix[id]);
+
+	/* query each parameter */
+	strcpy(pe, "height"); nh = conf_get_field(path);
+	strcpy(pe, "width");  nw = conf_get_field(path);
+	strcpy(pe, "x");      nx = conf_get_field(path);
+	strcpy(pe, "y");      ny = conf_get_field(path);
+
+	if (new_win != NULL) {
+		wplc_windows[id] = new_win;
+		win = new_win;
+		/* for new windows set hint */
+		if (HAVE(nw) && HAVE(nh))
+			gtk_window_set_default_size(GTK_WINDOW(win), nw->val.integer[0], nh->val.integer[0]);
+		if (HAVE(nx) && HAVE(ny))
+			gtk_window_move(GTK_WINDOW(win), nx->val.integer[0], ny->val.integer[0]);
+		else
+			gtk_window_move(GTK_WINDOW(win), 10, 10); /* original behaviour */
+	}
+	else {
+		win = wplc_windows[id];
+		if (win != NULL) {
+			if (HAVE(nw) && HAVE(nh))
+				gtk_window_resize(GTK_WINDOW(win), nw->val.integer[0], nh->val.integer[0]);
+			if (HAVE(nx) && HAVE(ny))
+				gtk_window_move(GTK_WINDOW(win), nx->val.integer[0], ny->val.integer[0]);
+		}
+	}
+}
+#undef HAVE
+
+void wplc_config_event(GtkWidget *win, long *cx, long *cy, long *cw, long *ch)
+{
+	GtkAllocation allocation;
+	gboolean new_w, new_h, new_x, new_y;
+
+	gtk_widget_get_allocation(win, &allocation);
+
+	/* For whatever reason, get_allocation doesn't set these. Gtk. */
+	gtk_window_get_position(GTK_WINDOW(win), &allocation.x, &allocation.y);
+
+	new_w = (*cw != allocation.width);
+	new_h = (*ch != allocation.height);
+	new_x = (*cx != allocation.x);
+	new_y = (*cy != allocation.y);
+
+	*cx = allocation.x;
+	*cy = allocation.y;
+	*cw = allocation.width;
+	*ch = allocation.height;
+
+	if (new_w || new_h || new_x || new_y)
+		hid_gtk_wgeo_update();
+}
diff --git a/src_plugins/lib_gtk_common/win_place.h b/src_plugins/lib_gtk_common/win_place.h
new file mode 100644
index 0000000..10da71a
--- /dev/null
+++ b/src_plugins/lib_gtk_common/win_place.h
@@ -0,0 +1,26 @@
+#ifndef GHID_WIN_PLACE
+#define GHID_WIN_PLACE
+
+#include <gtk/gtk.h>
+
+typedef enum {
+	WPLC_TOP,
+	WPLC_LOG,
+	WPLC_DRC,
+	WPLC_LIBRARY,
+	WPLC_NETLIST,
+	WPLC_KEYREF,
+	WPLC_PINOUT,
+	WPLC_SEARCH,
+	WPLC_max
+} wplc_win_t;
+
+/* Called when geometry changes - should save new geo in the config */
+extern void hid_gtk_wgeo_update(void);
+
+/* Place the window if it's enabled and there are coords in the config. */
+void wplc_place(wplc_win_t id, GtkWidget *win);
+
+/* query window current window sizes and update wgeo cache */
+void wplc_config_event(GtkWidget *win, long *cx, long *cy, long *cw, long *ch);
+#endif
diff --git a/src_plugins/lib_gtk_common/wt_coord_entry.c b/src_plugins/lib_gtk_common/wt_coord_entry.c
new file mode 100644
index 0000000..61d8587
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_coord_entry.c
@@ -0,0 +1,302 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+
+/*! \file <wt_coord_entry.c>
+ *  \brief Implementation of pcb_gtk_coord_entry_t widget
+ *  \par Description
+ *  This widget is a modified spinbox for the user to enter
+ *  pcb coords. It is assigned a default unit (for display),
+ *  but this can be changed by the user by typing a new one
+ *  or right-clicking on the box.
+ *
+ *  Internally, it keeps track of its value in pcb coords.
+ *  From the user's perspective, it uses natural human units.
+ */
+
+#include "config.h"
+
+#include "wt_coord_entry.h"
+
+#include "pcb-printf.h"
+#include "compat_nls.h"
+
+
+enum {
+	UNIT_CHANGE_SIGNAL,
+	LAST_SIGNAL
+};
+
+static guint ghid_coord_entry_signals[LAST_SIGNAL] = { 0 };
+
+struct pcb_gtk_coord_entry_s {
+	GtkSpinButton parent;
+
+	pcb_coord_t min_value;
+	pcb_coord_t max_value;
+	pcb_coord_t value;
+
+	enum ce_step_size step_size;
+	const pcb_unit_t *unit;
+};
+
+struct pcb_gtk_coord_entry_class_s {
+	GtkSpinButtonClass parent_class;
+
+	void (*change_unit) (pcb_gtk_coord_entry_t *, const pcb_unit_t *);
+};
+
+/* SIGNAL HANDLERS */
+/*! \brief Callback for "Change Unit" menu click */
+static void menu_item_activate_cb(GtkMenuItem * item, pcb_gtk_coord_entry_t * ce)
+{
+	const char *text = gtk_menu_item_get_label(item);
+	const pcb_unit_t *unit = get_unit_struct(text);
+
+	g_signal_emit(ce, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, unit);
+}
+
+/*! \brief Callback for context menu creation */
+static void ghid_coord_entry_popup_cb(pcb_gtk_coord_entry_t * ce, GtkMenu * menu, gpointer data)
+{
+	int i, n;
+	const pcb_unit_t *unit_list;
+	GtkWidget *menu_item, *submenu;
+
+	/* Build submenu */
+	n = pcb_get_n_units();
+	unit_list = get_unit_list();
+
+	submenu = gtk_menu_new();
+	for (i = 0; i < n; ++i) {
+		menu_item = gtk_menu_item_new_with_label(unit_list[i].suffix);
+		g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(menu_item_activate_cb), ce);
+		gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menu_item);
+		gtk_widget_show(menu_item);
+	}
+
+	/* Add submenu to menu */
+	menu_item = gtk_separator_menu_item_new();
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menu_item);
+	gtk_widget_show(menu_item);
+
+	menu_item = gtk_menu_item_new_with_label(_("Change Units"));
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menu_item);
+	gtk_widget_show(menu_item);
+}
+
+/*! \brief Callback for user output */
+static gboolean ghid_coord_entry_output_cb(pcb_gtk_coord_entry_t * ce, gpointer data)
+{
+	GtkAdjustment *adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ce));
+	double value = gtk_adjustment_get_value(adj);
+	char *text;
+
+	text = pcb_strdup_printf("%.*f %s", ce->unit->default_prec, value, ce->unit->suffix);
+	gtk_entry_set_text(GTK_ENTRY(ce), text);
+	free(text);
+
+	return TRUE;
+}
+
+/*! \brief Callback for user input */
+static gboolean ghid_coord_text_changed_cb(pcb_gtk_coord_entry_t * entry, gpointer data)
+{
+	const char *text;
+	char *suffix;
+	const pcb_unit_t *new_unit;
+	double value;
+
+	/* Check if units have changed */
+	text = gtk_entry_get_text(GTK_ENTRY(entry));
+	value = strtod(text, &suffix);
+	new_unit = get_unit_struct(suffix);
+	if (new_unit && new_unit != entry->unit) {
+		entry->value = pcb_unit_to_coord(new_unit, value);
+		g_signal_emit(entry, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, new_unit);
+	}
+
+	return FALSE;
+}
+
+/*! \brief Callback for change in value (input or ^v clicks) */
+static gboolean ghid_coord_value_changed_cb(pcb_gtk_coord_entry_t * ce, gpointer data)
+{
+	GtkAdjustment *adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ce));
+
+	/* Re-calculate internal value */
+	double value = gtk_adjustment_get_value(adj);
+	ce->value = pcb_unit_to_coord(ce->unit, value);
+	/* Handle potential unit changes */
+	ghid_coord_text_changed_cb(ce, data);
+
+	return FALSE;
+}
+
+/*! \brief Change the unit used by a coord entry
+ *
+ *  \param [in] ce         The entry to be acted on
+ *  \parin [in] new_unit   The new unit to be used
+ */
+static void ghid_coord_entry_change_unit(pcb_gtk_coord_entry_t * ce, const pcb_unit_t * new_unit)
+{
+	double climb_rate = 0.0;
+	GtkAdjustment *adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ce));
+
+	ce->unit = new_unit;
+	/* Re-calculate min/max values for spinbox */
+	gtk_adjustment_configure(adj, pcb_coord_to_unit(new_unit, ce->value),
+													 pcb_coord_to_unit(new_unit, ce->min_value),
+													 pcb_coord_to_unit(new_unit, ce->max_value), ce->unit->step_small, ce->unit->step_medium, 0.0);
+
+	switch (ce->step_size) {
+	case CE_TINY:
+		climb_rate = new_unit->step_tiny;
+		break;
+	case CE_SMALL:
+		climb_rate = new_unit->step_small;
+		break;
+	case CE_MEDIUM:
+		climb_rate = new_unit->step_medium;
+		break;
+	case CE_LARGE:
+		climb_rate = new_unit->step_large;
+		break;
+	}
+	gtk_spin_button_configure(GTK_SPIN_BUTTON(ce), adj, climb_rate, new_unit->default_prec + strlen(new_unit->suffix));
+}
+
+/* CONSTRUCTOR */
+static void ghid_coord_entry_init(pcb_gtk_coord_entry_t * ce)
+{
+	/* Hookup signal handlers */
+	g_signal_connect(G_OBJECT(ce), "focus_out_event", G_CALLBACK(ghid_coord_text_changed_cb), NULL);
+	g_signal_connect(G_OBJECT(ce), "value_changed", G_CALLBACK(ghid_coord_value_changed_cb), NULL);
+	g_signal_connect(G_OBJECT(ce), "populate_popup", G_CALLBACK(ghid_coord_entry_popup_cb), NULL);
+	g_signal_connect(G_OBJECT(ce), "output", G_CALLBACK(ghid_coord_entry_output_cb), NULL);
+}
+
+static void ghid_coord_entry_class_init(pcb_gtk_coord_entry_class_t * klass)
+{
+	klass->change_unit = ghid_coord_entry_change_unit;
+
+	/* GtkAutoComplete *ce : the object acted on */
+	/* const pcb_unit_t *new_unit: the new unit that was set */
+	ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL] =
+		g_signal_new("change-unit",
+								 G_TYPE_FROM_CLASS(klass),
+								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+								 G_STRUCT_OFFSET(pcb_gtk_coord_entry_class_t, change_unit),
+								 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+}
+
+/* PUBLIC FUNCTIONS */
+GType pcb_gtk_coord_entry_get_type(void)
+{
+	static GType ce_type = 0;
+
+	if (!ce_type) {
+		const GTypeInfo ce_info = {
+			sizeof(pcb_gtk_coord_entry_class_t),
+			NULL,											/* base_init */
+			NULL,											/* base_finalize */
+			(GClassInitFunc) ghid_coord_entry_class_init,
+			NULL,											/* class_finalize */
+			NULL,											/* class_data */
+			sizeof(pcb_gtk_coord_entry_t),
+			0,												/* n_preallocs */
+			(GInstanceInitFunc) ghid_coord_entry_init,
+		};
+
+		ce_type = g_type_register_static(GTK_TYPE_SPIN_BUTTON, "pcb_gtk_coord_entry_t", &ce_info, 0);
+	}
+
+	return ce_type;
+}
+
+GtkWidget *pcb_gtk_coord_entry_new(pcb_coord_t min_val, pcb_coord_t max_val, pcb_coord_t value, const pcb_unit_t * unit,
+																	 enum ce_step_size step_size)
+{
+	/* Setup spinbox min/max values */
+	double small_step, big_step;
+	GtkAdjustment *adj;
+	pcb_gtk_coord_entry_t *ce = g_object_new(GHID_COORD_ENTRY_TYPE, NULL);
+
+	ce->unit = unit;
+	ce->min_value = min_val;
+	ce->max_value = max_val;
+	ce->value = value;
+
+	ce->step_size = step_size;
+	switch (step_size) {
+	case CE_TINY:
+		small_step = unit->step_tiny;
+		big_step = unit->step_small;
+		break;
+	case CE_SMALL:
+		small_step = unit->step_small;
+		big_step = unit->step_medium;
+		break;
+	case CE_MEDIUM:
+		small_step = unit->step_medium;
+		big_step = unit->step_large;
+		break;
+	case CE_LARGE:
+		small_step = unit->step_large;
+		big_step = unit->step_huge;
+		break;
+	default:
+		small_step = big_step = 0;
+		break;
+	}
+
+	adj = GTK_ADJUSTMENT(gtk_adjustment_new(pcb_coord_to_unit(unit, value),
+																					pcb_coord_to_unit(unit, min_val),
+																					pcb_coord_to_unit(unit, max_val), small_step, big_step, 0.0));
+	gtk_spin_button_configure(GTK_SPIN_BUTTON(ce), adj, small_step, unit->default_prec + strlen(unit->suffix));
+	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ce), FALSE);
+
+	return GTK_WIDGET(ce);
+}
+
+pcb_coord_t pcb_gtk_coord_entry_get_value(pcb_gtk_coord_entry_t * ce)
+{
+	return ce->value;
+}
+
+int pcb_gtk_coord_entry_get_value_str(pcb_gtk_coord_entry_t * ce, char *out, int out_len)
+{
+	GtkAdjustment *adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ce));
+	double value = gtk_adjustment_get_value(adj);
+	return pcb_snprintf(out, out_len, "%.*f %s", ce->unit->default_prec, value, ce->unit->suffix);
+}
+
+void pcb_gtk_coord_entry_set_value(pcb_gtk_coord_entry_t * ce, pcb_coord_t val)
+{
+	gtk_spin_button_set_value(GTK_SPIN_BUTTON(ce), pcb_coord_to_unit(ce->unit, val));
+}
diff --git a/src_plugins/lib_gtk_common/wt_coord_entry.h b/src_plugins/lib_gtk_common/wt_coord_entry.h
new file mode 100644
index 0000000..9b60759
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_coord_entry.h
@@ -0,0 +1,49 @@
+/* This is the modified GtkSpinbox used for entering Coords.
+ * Hopefully it can be used as a template whenever we migrate the
+ * rest of the Gtk HID to use GObjects and GtkWidget subclassing.
+ */
+#ifndef GHID_COORD_ENTRY_H__
+#define GHID_COORD_ENTRY_H__
+
+#include <gtk/gtk.h>
+
+#include "unit.h"
+
+G_BEGIN_DECLS										/* keep c++ happy */
+#define GHID_COORD_ENTRY_TYPE            (pcb_gtk_coord_entry_get_type ())
+#define GHID_COORD_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_COORD_ENTRY_TYPE, pcb_gtk_coord_entry_t))
+#define GHID_COORD_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GHID_COORD_ENTRY_TYPE, pcb_gtk_coord_entry_class_t))
+#define IS_GHID_COORD_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_COORD_ENTRY_TYPE))
+#define IS_GHID_COORD_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHID_COORD_ENTRY_TYPE))
+typedef struct pcb_gtk_coord_entry_s pcb_gtk_coord_entry_t;
+typedef struct pcb_gtk_coord_entry_class_s pcb_gtk_coord_entry_class_t;
+
+/* Step sizes */
+enum ce_step_size { CE_TINY, CE_SMALL, CE_MEDIUM, CE_LARGE };
+
+GType pcb_gtk_coord_entry_get_type(void);
+
+/** Creates a new pcb_gtk_coord_entry_t
+ *
+ *  \param [in] min_val    The minimum allowed value, in pcb coords
+ *  \param [in] max_val    The maximum allowed value, in pcb coords
+ *  \param [in] value      The default value, in pcb coords
+ *  \param [in] unit       The default unit
+ *  \param [in] step_size  How large the default increments should be
+ *
+ *  \return a freshly-allocated pcb_gtk_coord_entry_t
+ */
+GtkWidget *pcb_gtk_coord_entry_new(pcb_coord_t min_val, pcb_coord_t max_val, pcb_coord_t value, const pcb_unit_t * unit,
+																	 enum ce_step_size step_size);
+
+/** Gets a pcb_gtk_coord_entry_t's value, in pcb coords */
+pcb_coord_t pcb_gtk_coord_entry_get_value(pcb_gtk_coord_entry_t * ce);
+
+/** Gets a pcb_gtk_coord_entry_t's value as text */
+int pcb_gtk_coord_entry_get_value_str(pcb_gtk_coord_entry_t * ce, char *out, int out_len);
+
+/** Sets a pcb_gtk_coord_entry_t's value, in pcb coords */
+void pcb_gtk_coord_entry_set_value(pcb_gtk_coord_entry_t * ce, pcb_coord_t val);
+
+G_END_DECLS											/* keep c++ happy */
+#endif
diff --git a/src_plugins/lib_gtk_common/wt_layer_selector.c b/src_plugins/lib_gtk_common/wt_layer_selector.c
new file mode 100644
index 0000000..942b2d7
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_layer_selector.c
@@ -0,0 +1,704 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/*! \file <wt_layer_selector.c>
+ *  \brief Implementation of pcb_gtk_layer_selector_t widget
+ *  \par Description
+ *  This widget is the layer selector on the left side of the Gtk
+ *  GUI. It also builds the relevant sections of the menu for layer
+ *  selection and visibility toggling, and keeps these in sync.
+ */
+
+#include "config.h"
+
+#include "wt_layer_selector.h"
+
+#include "pcb-printf.h"
+
+#include "wt_layer_selector_cr.h"
+
+
+#define INITIAL_ACTION_MAX	40
+
+/* Forward dec'ls */
+struct _layer;
+static void ghid_layer_selector_finalize(GObject * object);
+static void menu_pick_cb(GtkRadioAction * action, struct _layer *ldata);
+
+/*! \brief Signals exposed by the widget */
+enum {
+	SELECT_LAYER_SIGNAL,
+	TOGGLE_LAYER_SIGNAL,
+	LAST_SIGNAL
+};
+
+/*! \brief Columns used for internal data store */
+enum {
+	STRUCT_COL,
+	USER_ID_COL,
+	VISIBLE_COL,
+	COLOR_COL,
+	TEXT_COL,
+	FONT_COL,
+	ACTIVATABLE_COL,
+	SEPARATOR_COL,
+	N_COLS
+};
+
+static GtkTreeView *ghid_layer_selector_parent_class;
+static guint ghid_layer_selector_signals[LAST_SIGNAL] = { 0 };
+
+struct pcb_gtk_layer_selector_s {
+	GtkTreeView parent;
+
+	GtkListStore *list_store;
+	GtkTreeSelection *selection;
+	GtkTreeViewColumn *visibility_column;
+
+	GtkActionGroup *action_group;
+	GtkAccelGroup *accel_group;
+
+	GSList *radio_group;
+	int n_actions;
+
+	gboolean accel_available[20];
+
+	gboolean last_activatable;
+
+	gulong selection_changed_sig_id;
+};
+
+struct pcb_gtk_layer_selector_class_s {
+	GtkTreeViewClass parent_class;
+
+	void (*select_layer) (pcb_gtk_layer_selector_t *, gint);
+	void (*toggle_layer) (pcb_gtk_layer_selector_t *, gint);
+};
+
+struct _layer {
+	gint accel_index;							/* Index into ls->accel_available */
+	GtkWidget *pick_item;
+	GtkWidget *view_item;
+	GtkToggleAction *view_action;
+	GtkRadioAction *pick_action;
+	GtkTreeRowReference *rref;
+};
+
+/*! \brief Deletes the action and accelerator from a layer */
+static void free_ldata(pcb_gtk_layer_selector_t * ls, struct _layer *ldata)
+{
+	if (ldata->pick_action) {
+		gtk_action_disconnect_accelerator(GTK_ACTION(ldata->pick_action));
+		gtk_action_group_remove_action(ls->action_group, GTK_ACTION(ldata->pick_action));
+/* TODO: make this work without wrecking the radio action group
+ *           g_object_unref (G_OBJECT (ldata->pick_action)); 
+ *                   */
+	}
+	if (ldata->view_action) {
+		gtk_action_disconnect_accelerator(GTK_ACTION(ldata->view_action));
+		gtk_action_group_remove_action(ls->action_group, GTK_ACTION(ldata->view_action));
+		g_object_unref(G_OBJECT(ldata->view_action));
+	}
+	gtk_tree_row_reference_free(ldata->rref);
+	if (ldata->accel_index >= 0)
+		ls->accel_available[ldata->accel_index] = TRUE;
+	g_free(ldata);
+
+}
+
+/*! \brief internal set-visibility function -- emits no signals */
+static void set_visibility(pcb_gtk_layer_selector_t * ls, GtkTreeIter * iter, struct _layer *ldata, gboolean state)
+{
+	gtk_list_store_set(ls->list_store, iter, VISIBLE_COL, state, -1);
+
+	if ((ldata) && (ldata->view_item)) {
+		gtk_action_block_activate(GTK_ACTION(ldata->view_action));
+		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ldata->view_item), state);
+		gtk_action_unblock_activate(GTK_ACTION(ldata->view_action));
+	}
+}
+
+/*! \brief Flips the visibility state of a given layer 
+ *  \par Function Description
+ *  Changes the internal toggle state and menu checkbox state
+ *  of the layer pointed to by iter. Emits a toggle-layer signal.
+ *
+ *  \param [in] ls    The selector to be acted on
+ *  \param [in] iter  A GtkTreeIter pointed at the relevant layer
+ *  \param [in] emit  Whether or not to emit a signal
+ */
+static void toggle_visibility(pcb_gtk_layer_selector_t * ls, GtkTreeIter * iter, gboolean emit)
+{
+	gint user_id;
+	struct _layer *ldata;
+	gboolean toggle;
+	gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), iter, USER_ID_COL, &user_id, VISIBLE_COL, &toggle, STRUCT_COL, &ldata, -1);
+	set_visibility(ls, iter, ldata, !toggle);
+	if (emit)
+		g_signal_emit(ls, ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL], 0, user_id);
+}
+
+/*! \brief Decides if a GtkListStore entry is a layer or separator */
+static gboolean tree_view_separator_func(GtkTreeModel * model, GtkTreeIter * iter, gpointer data)
+{
+	gboolean ret_val;
+	gtk_tree_model_get(model, iter, SEPARATOR_COL, &ret_val, -1);
+	return ret_val;
+}
+
+/*! \brief Decides if a GtkListStore entry may be selected */
+static gboolean tree_selection_func(GtkTreeSelection * selection,
+																		GtkTreeModel * model, GtkTreePath * path, gboolean selected, gpointer data)
+{
+	GtkTreeIter iter;
+
+	if (gtk_tree_model_get_iter(model, &iter, path)) {
+		gboolean activatable;
+		gtk_tree_model_get(model, &iter, ACTIVATABLE_COL, &activatable, -1);
+		return activatable;
+	}
+
+	return FALSE;
+}
+
+/* SIGNAL HANDLERS */
+/*! \brief Callback for mouse-click: toggle visibility */
+static gboolean button_press_cb(pcb_gtk_layer_selector_t * ls, GdkEventButton * event)
+{
+	/* Handle visibility independently to prevent changing the active
+	 *  layer, which will happen if we let this event propagate.  */
+	GtkTreeViewColumn *column;
+	GtkTreePath *path;
+
+	/* Ignore the synthetic presses caused by double and tripple clicks, and
+	 * also ignore all but left-clicks
+	 */
+	if (event->type != GDK_BUTTON_PRESS || event->button != 1)
+		return TRUE;
+
+	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(ls), event->x, event->y, &path, &column, NULL, NULL)) {
+		GtkTreeIter iter;
+		gboolean activatable, separator;
+		gtk_tree_model_get_iter(GTK_TREE_MODEL(ls->list_store), &iter, path);
+		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, ACTIVATABLE_COL, &activatable, SEPARATOR_COL, &separator, -1);
+		/* Toggle visibility for non-activatable layers no matter
+		 *  where you click. */
+		if (!separator && (column == ls->visibility_column || !activatable)) {
+			toggle_visibility(ls, &iter, TRUE);
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+/*! \brief Callback for layer selection change: sync menu, emit signal */
+static void selection_changed_cb(GtkTreeSelection * selection, pcb_gtk_layer_selector_t * ls)
+{
+	GtkTreeIter iter;
+	if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
+		gint user_id;
+		struct _layer *ldata;
+		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &ldata, USER_ID_COL, &user_id, -1);
+
+		if (ldata && ldata->pick_action) {
+			gtk_action_block_activate(GTK_ACTION(ldata->pick_action));
+			gtk_radio_action_set_current_value(ldata->pick_action, user_id);
+			gtk_action_unblock_activate(GTK_ACTION(ldata->pick_action));
+		}
+		g_signal_emit(ls, ghid_layer_selector_signals[SELECT_LAYER_SIGNAL], 0, user_id);
+	}
+}
+
+/*! \brief Callback for menu actions: sync layer selection list, emit signal */
+static void menu_view_cb(GtkToggleAction * action, struct _layer *ldata)
+{
+	pcb_gtk_layer_selector_t *ls;
+	GtkTreeModel *model = gtk_tree_row_reference_get_model(ldata->rref);
+	GtkTreePath *path = gtk_tree_row_reference_get_path(ldata->rref);
+	gboolean state = gtk_toggle_action_get_active(action);
+	GtkTreeIter iter;
+	gint user_id;
+
+	gtk_tree_model_get_iter(model, &iter, path);
+	gtk_list_store_set(GTK_LIST_STORE(model), &iter, VISIBLE_COL, state, -1);
+	gtk_tree_model_get(model, &iter, USER_ID_COL, &user_id, -1);
+
+	ls = g_object_get_data(G_OBJECT(model), "layer-selector");
+	g_signal_emit(ls, ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL], 0, user_id);
+}
+
+/*! \brief Callback for menu actions: sync layer selection list, emit signal */
+static void menu_pick_cb(GtkRadioAction * action, struct _layer *ldata)
+{
+	/* We only care about the activation signal (as opposed to deactivation).
+	 * A row we are /deactivating/ might not even exist anymore! */
+	if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
+		pcb_gtk_layer_selector_t *ls;
+		GtkTreeModel *model = gtk_tree_row_reference_get_model(ldata->rref);
+		GtkTreePath *path = gtk_tree_row_reference_get_path(ldata->rref);
+		GtkTreeIter iter;
+		gint user_id;
+
+		gtk_tree_model_get_iter(model, &iter, path);
+		gtk_tree_model_get(model, &iter, USER_ID_COL, &user_id, -1);
+
+		ls = g_object_get_data(G_OBJECT(model), "layer-selector");
+		g_signal_handler_block(ls->selection, ls->selection_changed_sig_id);
+		gtk_tree_selection_select_path(ls->selection, path);
+		g_signal_handler_unblock(ls->selection, ls->selection_changed_sig_id);
+		g_signal_emit(ls, ghid_layer_selector_signals[SELECT_LAYER_SIGNAL], 0, user_id);
+	}
+}
+
+/* CONSTRUCTOR */
+static void ghid_layer_selector_init(pcb_gtk_layer_selector_t * ls)
+{
+	/* Hookup signal handlers */
+}
+
+static void ghid_layer_selector_class_init(pcb_gtk_layer_selector_class_t * klass)
+{
+	GObjectClass *object_class = (GObjectClass *) klass;
+
+	ghid_layer_selector_signals[SELECT_LAYER_SIGNAL] =
+		g_signal_new("select-layer",
+								 G_TYPE_FROM_CLASS(klass),
+								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+								 G_STRUCT_OFFSET(pcb_gtk_layer_selector_class_t, select_layer),
+								 NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
+	ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL] =
+		g_signal_new("toggle-layer",
+								 G_TYPE_FROM_CLASS(klass),
+								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+								 G_STRUCT_OFFSET(pcb_gtk_layer_selector_class_t, toggle_layer),
+								 NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
+
+	object_class->finalize = ghid_layer_selector_finalize;
+}
+
+/*! \brief Cleans up object before garbage collection */
+static void ghid_layer_selector_finalize(GObject * object)
+{
+	GtkTreeIter iter;
+	pcb_gtk_layer_selector_t *ls = (pcb_gtk_layer_selector_t *) object;
+
+	g_object_unref(ls->accel_group);
+	g_object_unref(ls->action_group);
+
+	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
+	do {
+		struct _layer *ldata;
+		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &ldata, -1);
+		free_ldata(ls, ldata);
+	}
+	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
+
+	G_OBJECT_CLASS(ghid_layer_selector_parent_class)->finalize(object);
+}
+
+/* PUBLIC FUNCTIONS */
+GType pcb_gtk_layer_selector_get_type(void)
+{
+	static GType ls_type = 0;
+
+	if (!ls_type) {
+		const GTypeInfo ls_info = {
+			sizeof(pcb_gtk_layer_selector_class_t),
+			NULL,											/* base_init */
+			NULL,											/* base_finalize */
+			(GClassInitFunc) ghid_layer_selector_class_init,
+			NULL,											/* class_finalize */
+			NULL,											/* class_data */
+			sizeof(pcb_gtk_layer_selector_t),
+			0,												/* n_preallocs */
+			(GInstanceInitFunc) ghid_layer_selector_init,
+		};
+
+		ls_type = g_type_register_static(GTK_TYPE_TREE_VIEW, "pcb_gtk_layer_selector_t", &ls_info, 0);
+	}
+
+	return ls_type;
+}
+
+GtkWidget *pcb_gtk_layer_selector_new(void)
+{
+	int i;
+	GtkCellRenderer *renderer1 = ghid_cell_renderer_visibility_new();
+	GtkCellRenderer *renderer2 = gtk_cell_renderer_text_new();
+	GtkTreeViewColumn *opacity_col = gtk_tree_view_column_new_with_attributes("", renderer1,
+																																						"active", VISIBLE_COL,
+																																						"color", COLOR_COL, NULL);
+	GtkTreeViewColumn *name_col = gtk_tree_view_column_new_with_attributes("", renderer2,
+																																				 "text", TEXT_COL,
+																																				 "font", FONT_COL,
+																																				 NULL);
+
+	pcb_gtk_layer_selector_t *ls = g_object_new(GHID_LAYER_SELECTOR_TYPE, NULL);
+
+	/* action index, active, color, text, font, is_separator */
+	ls->list_store = gtk_list_store_new(N_COLS, G_TYPE_POINTER, G_TYPE_INT,
+																			G_TYPE_BOOLEAN, G_TYPE_STRING,
+																			G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+	gtk_tree_view_insert_column(GTK_TREE_VIEW(ls), opacity_col, -1);
+	gtk_tree_view_insert_column(GTK_TREE_VIEW(ls), name_col, -1);
+	gtk_tree_view_set_model(GTK_TREE_VIEW(ls), GTK_TREE_MODEL(ls->list_store));
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ls), FALSE);
+
+	ls->last_activatable = TRUE;
+	ls->visibility_column = opacity_col;
+	ls->selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ls));
+	ls->accel_group = gtk_accel_group_new();
+	ls->action_group = gtk_action_group_new("LayerSelector");
+	ls->n_actions = 0;
+	for (i = 0; i < 20; ++i)
+		ls->accel_available[i] = TRUE;
+
+	gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(ls), tree_view_separator_func, NULL, NULL);
+	gtk_tree_selection_set_select_function(ls->selection, tree_selection_func, NULL, NULL);
+	gtk_tree_selection_set_mode(ls->selection, GTK_SELECTION_BROWSE);
+
+	g_object_set_data(G_OBJECT(ls->list_store), "layer-selector", ls);
+	g_signal_connect(ls, "button_press_event", G_CALLBACK(button_press_cb), NULL);
+	ls->selection_changed_sig_id = g_signal_connect(ls->selection, "changed", G_CALLBACK(selection_changed_cb), ls);
+
+	g_object_ref(ls->accel_group);
+
+	return GTK_WIDGET(ls);
+}
+
+void pcb_gtk_layer_selector_add_layer(pcb_gtk_layer_selector_t * ls,
+																			gint user_id,
+																			const gchar * name, const gchar * color_string, gboolean visible, gboolean activatable)
+{
+	struct _layer *new_layer = NULL;
+	gchar *pname, *vname;
+	gboolean new_iter = TRUE;
+	gboolean last_activatable = TRUE;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	int i;
+
+	/* Look for existing layer with this ID */
+	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter))
+		do {
+			gboolean is_sep, active;
+			gint read_id;
+			gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store),
+												 &iter, USER_ID_COL, &read_id, SEPARATOR_COL, &is_sep, ACTIVATABLE_COL, &active, -1);
+			if (!is_sep) {
+				last_activatable = active;
+				if (read_id == user_id) {
+					new_iter = FALSE;
+					break;
+				}
+			}
+		}
+		while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
+
+	/* Handle separator addition */
+	if (new_iter) {
+		if (activatable != last_activatable) {
+			/* Add separator between activatable/non-activatable boundaries */
+			gtk_list_store_append(ls->list_store, &iter);
+			gtk_list_store_set(ls->list_store, &iter, STRUCT_COL, NULL, SEPARATOR_COL, TRUE, -1);
+		}
+		/* Create new layer */
+		new_layer = malloc(sizeof(*new_layer));
+		gtk_list_store_append(ls->list_store, &iter);
+		gtk_list_store_set(ls->list_store, &iter,
+											 STRUCT_COL, new_layer,
+											 USER_ID_COL, user_id,
+											 VISIBLE_COL, visible,
+											 COLOR_COL, color_string,
+											 TEXT_COL, name,
+											 FONT_COL, activatable ? NULL : "Italic", ACTIVATABLE_COL, activatable, SEPARATOR_COL, FALSE, -1);
+	}
+	else {
+		/* If the row exists, we clear out its ldata to create
+		 * a new action, accelerator and menu item. */
+		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &new_layer, -1);
+		free_ldata(ls, new_layer);
+		new_layer = malloc(sizeof(*new_layer));
+
+		gtk_list_store_set(ls->list_store, &iter,
+											 STRUCT_COL, new_layer,
+											 VISIBLE_COL, visible,
+											 COLOR_COL, color_string,
+											 TEXT_COL, name, FONT_COL, activatable ? NULL : "Italic", ACTIVATABLE_COL, activatable, -1);
+	}
+
+	/* -- Setup new actions -- */
+	vname = g_strdup_printf("LayerView%d", ls->n_actions);
+	pname = g_strdup_printf("LayerPick%d", ls->n_actions);
+
+	/* Create row reference for actions */
+	path = gtk_tree_model_get_path(GTK_TREE_MODEL(ls->list_store), &iter);
+	new_layer->rref = gtk_tree_row_reference_new(GTK_TREE_MODEL(ls->list_store), path);
+	gtk_tree_path_free(path);
+
+	/* Create selection action */
+	if (activatable) {
+		new_layer->pick_action = gtk_radio_action_new(pname, name, NULL, NULL, user_id);
+		gtk_radio_action_set_group(new_layer->pick_action, ls->radio_group);
+		ls->radio_group = gtk_radio_action_get_group(new_layer->pick_action);
+	}
+	else
+		new_layer->pick_action = NULL;
+
+	/* Create visibility action */
+	new_layer->view_action = gtk_toggle_action_new(vname, name, NULL, NULL);
+	gtk_toggle_action_set_active(new_layer->view_action, visible);
+
+	/* Determine keyboard accelerators */
+	for (i = 0; i < 20; ++i)
+		if (ls->accel_available[i])
+			break;
+	if (i < 20) {
+		/* Map 1-0 to actions 1-10 (with '0' meaning 10) */
+		gchar *accel1 = g_strdup_printf("%s%d",
+																		i < 10 ? "" : "<Alt>",
+																		(i + 1) % 10);
+		gchar *accel2 = g_strdup_printf("<Ctrl>%s%d",
+																		i < 10 ? "" : "<Alt>",
+																		(i + 1) % 10);
+
+		if (activatable) {
+			GtkAction *action = GTK_ACTION(new_layer->pick_action);
+			gtk_action_set_accel_group(action, ls->accel_group);
+			gtk_action_group_add_action_with_accel(ls->action_group, action, accel1);
+			gtk_action_connect_accelerator(action);
+			g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(menu_pick_cb), new_layer);
+		}
+		gtk_action_set_accel_group(GTK_ACTION(new_layer->view_action), ls->accel_group);
+		gtk_action_group_add_action_with_accel(ls->action_group, GTK_ACTION(new_layer->view_action), accel2);
+		gtk_action_connect_accelerator(GTK_ACTION(new_layer->view_action));
+		g_signal_connect(G_OBJECT(new_layer->view_action), "activate", G_CALLBACK(menu_view_cb), new_layer);
+
+		ls->accel_available[i] = FALSE;
+		new_layer->accel_index = i;
+		g_free(accel2);
+		g_free(accel1);
+	}
+	else {
+		new_layer->accel_index = -1;
+	}
+	/* finalize new layer struct */
+	new_layer->pick_item = new_layer->view_item = NULL;
+
+	/* cleanup */
+	g_free(vname);
+	g_free(pname);
+
+	ls->n_actions++;
+}
+
+gint pcb_gtk_layer_selector_install_pick_items(pcb_gtk_layer_selector_t * ls, GtkMenuShell * shell, gint pos)
+{
+	GtkTreeIter iter;
+	int n = 0;
+
+	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
+	do {
+		struct _layer *ldata;
+		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &ldata, -1);
+		if (ldata && ldata->pick_action) {
+			GtkAction *action = GTK_ACTION(ldata->pick_action);
+			ldata->pick_item = gtk_action_create_menu_item(action);
+			gtk_menu_shell_insert(shell, ldata->pick_item, pos + n);
+			++n;
+		}
+	}
+	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
+
+	return n;
+}
+
+gint pcb_gtk_layer_selector_install_view_items(pcb_gtk_layer_selector_t * ls, GtkMenuShell * shell, gint pos)
+{
+	GtkTreeIter iter;
+	int n = 0;
+
+	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
+	do {
+		struct _layer *ldata;
+		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, STRUCT_COL, &ldata, -1);
+		if (ldata && ldata->view_action) {
+			GtkAction *action = GTK_ACTION(ldata->view_action);
+			ldata->view_item = gtk_action_create_menu_item(action);
+			gtk_menu_shell_insert(shell, ldata->view_item, pos + n);
+			++n;
+		}
+	}
+	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
+
+	return n;
+}
+
+GtkAccelGroup *pcb_gtk_layer_selector_get_accel_group(pcb_gtk_layer_selector_t * ls)
+{
+	return ls->accel_group;
+}
+
+/*! \brief used internally */
+static gboolean toggle_foreach_func(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
+{
+	gint id;
+	pcb_gtk_layer_selector_t *ls = g_object_get_data(G_OBJECT(model),
+																									 "layer-selector");
+
+	gtk_tree_model_get(model, iter, USER_ID_COL, &id, -1);
+	if (id == *(gint *) data) {
+		toggle_visibility(ls, iter, TRUE);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+void pcb_gtk_layer_selector_toggle_layer(pcb_gtk_layer_selector_t * ls, gint user_id)
+{
+	gtk_tree_model_foreach(GTK_TREE_MODEL(ls->list_store), toggle_foreach_func, &user_id);
+}
+
+/*! \brief used internally */
+static gboolean select_foreach_func(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
+{
+	gint id;
+	pcb_gtk_layer_selector_t *ls = g_object_get_data(G_OBJECT(model),
+																									 "layer-selector");
+
+	gtk_tree_model_get(model, iter, USER_ID_COL, &id, -1);
+	if (id == *(gint *) data) {
+		gtk_tree_selection_select_path(ls->selection, path);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+void pcb_gtk_layer_selector_select_layer(pcb_gtk_layer_selector_t * ls, gint user_id)
+{
+	gtk_tree_model_foreach(GTK_TREE_MODEL(ls->list_store), select_foreach_func, &user_id);
+}
+
+gboolean pcb_gtk_layer_selector_select_next_visible(pcb_gtk_layer_selector_t * ls)
+{
+	GtkTreeIter iter;
+	if (gtk_tree_selection_get_selected(ls->selection, NULL, &iter)) {
+		/* Scan forward, looking for selectable iter */
+		do {
+			gboolean visible, activatable;
+			gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, VISIBLE_COL, &visible, ACTIVATABLE_COL, &activatable, -1);
+			if (visible && activatable) {
+				gtk_tree_selection_select_iter(ls->selection, &iter);
+				return TRUE;
+			}
+		}
+		while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
+		/* Move iter to start, and repeat. */
+		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
+		do {
+			gboolean visible, activatable;
+			gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, VISIBLE_COL, &visible, ACTIVATABLE_COL, &activatable, -1);
+			if (visible && activatable) {
+				gtk_tree_selection_select_iter(ls->selection, &iter);
+				return TRUE;
+			}
+		}
+		while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
+		/* Failing this, just emit a selected signal on the original layer. */
+		selection_changed_cb(ls->selection, ls);
+	}
+	/* If we get here, nothing is selectable, so fail. */
+	return FALSE;
+}
+
+void pcb_gtk_layer_selector_update_colors(pcb_gtk_layer_selector_t * ls, const gchar * (*callback) (int user_id))
+{
+	GtkTreeIter iter;
+	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
+	do {
+		gint user_id;
+		const gchar *new_color;
+		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store), &iter, USER_ID_COL, &user_id, -1);
+		new_color = callback(user_id);
+		if (new_color != NULL)
+			gtk_list_store_set(ls->list_store, &iter, COLOR_COL, new_color, -1);
+	}
+	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
+}
+
+void pcb_gtk_layer_selector_delete_layers(pcb_gtk_layer_selector_t * ls, gboolean(*callback) (int user_id))
+{
+	GtkTreeIter iter, last_iter;
+
+	gboolean iter_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
+	while (iter_valid) {
+		struct _layer *ldata;
+		gboolean sep, was_sep = FALSE;
+		gint user_id;
+
+		/* Find next iter to delete */
+		while (iter_valid) {
+			gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store),
+												 &iter, USER_ID_COL, &user_id, STRUCT_COL, &ldata, SEPARATOR_COL, &sep, -1);
+			if (!sep && callback(user_id))
+				break;
+
+			/* save iter in case it's a bad separator */
+			was_sep = sep;
+			last_iter = iter;
+			/* iterate */
+			iter_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter);
+		}
+
+		if (iter_valid) {
+			/* remove preceeding separator */
+			if (was_sep)
+				gtk_list_store_remove(ls->list_store, &last_iter);
+
+					/*** remove row ***/
+			iter_valid = gtk_list_store_remove(ls->list_store, &iter);
+			free_ldata(ls, ldata);
+		}
+		last_iter = iter;
+	}
+}
+
+void pcb_gtk_layer_selector_show_layers(pcb_gtk_layer_selector_t * ls, gboolean(*callback) (int user_id))
+{
+	GtkTreeIter iter;
+	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls->list_store), &iter);
+	do {
+		struct _layer *ldata;
+		gboolean sep;
+		gint user_id;
+
+		gtk_tree_model_get(GTK_TREE_MODEL(ls->list_store),
+											 &iter, USER_ID_COL, &user_id, STRUCT_COL, &ldata, SEPARATOR_COL, &sep, -1);
+		if (!sep)
+			set_visibility(ls, &iter, ldata, callback(user_id));
+	}
+	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ls->list_store), &iter));
+}
diff --git a/src_plugins/lib_gtk_common/wt_layer_selector.h b/src_plugins/lib_gtk_common/wt_layer_selector.h
new file mode 100644
index 0000000..2a0105b
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_layer_selector.h
@@ -0,0 +1,144 @@
+#ifndef GHID_LAYER_SELECTOR_H__
+#define GHID_LAYER_SELECTOR_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS										/* keep c++ happy */
+#define GHID_LAYER_SELECTOR_TYPE            (pcb_gtk_layer_selector_get_type ())
+#define GHID_LAYER_SELECTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_LAYER_SELECTOR_TYPE, pcb_gtk_layer_selector_t))
+#define GHID_LAYER_SELECTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GHID_LAYER_SELECTOR_TYPE, pcb_gtk_layer_selector_class_t))
+#define IS_GHID_LAYER_SELECTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_LAYER_SELECTOR_TYPE))
+#define IS_GHID_LAYER_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHID_LAYER_SELECTOR_TYPE))
+typedef struct pcb_gtk_layer_selector_s pcb_gtk_layer_selector_t;
+typedef struct pcb_gtk_layer_selector_class_s pcb_gtk_layer_selector_class_t;
+
+GType pcb_gtk_layer_selector_get_type(void);
+
+/** Creates and returns a new freshly-allocated pcb_gtk_layer_selector_t widget */
+GtkWidget *pcb_gtk_layer_selector_new(void);
+
+/** Adds a layer to a pcb_gtk_layer_selector_t.
+    \par Function Description
+    This function adds an entry to a pcb_gtk_layer_selector_t, which will
+    appear in the layer-selection list as well as visibility and selection
+    menus (assuming this is a selectable layer). For the first 20 layers,
+    keyboard accelerators will be added for selection/visibility toggling.
+  
+    If the user_id passed already exists in the layer selector, that layer
+    will have its data overwritten with the new stuff.
+  
+    \param [in] ls            The selector to be acted on
+    \param [in] user_id       An ID used to identify the layer; will be passed to selection/visibility callbacks
+    \param [in] name          The name of the layer; will be used on selector and menus
+    \param [in] color_string  The color of the layer on selector
+    \param [in] visibile      Whether the layer is visible
+    \param [in] activatable   Whether the layer appears in menus and can be selected
+ */
+void pcb_gtk_layer_selector_add_layer(pcb_gtk_layer_selector_t * ls,
+																			gint user_id,
+																			const gchar * name, const gchar * color_string, gboolean visible, gboolean activatable);
+
+/** Installs the "Current Layer" menu items for a layer selector
+    \par Function Description
+    Takes a menu shell and installs menu items for layer selection in
+    the shell, at the given position.
+  
+    \param [in] ls      The selector to be acted on
+    \param [in] shell   The menu to install the items in
+    \param [in] pos     The position in the menu to install items
+  
+    \return the number of items installed
+ */
+gint pcb_gtk_layer_selector_install_pick_items(pcb_gtk_layer_selector_t * ls, GtkMenuShell * shell, gint pos);
+
+/** Installs the "Shown Layers" menu items for a layer selector
+    \par Function Description
+    Takes a menu shell and installs menu items for layer selection in
+    the shell, at the given position.
+  
+    \param [in] ls      The selector to be acted on
+    \param [in] shell   The menu to install the items in
+    \param [in] pos     The position in the menu to install items
+  
+    \return the number of items installed
+ */
+gint pcb_gtk_layer_selector_install_view_items(pcb_gtk_layer_selector_t * ls, GtkMenuShell * shell, gint pos);
+
+/** Returns the GtkAccelGroup of a layer selector
+    \par Function Description
+  
+    \param [in] ls            The selector to be acted on
+  
+    \return the accel group of the selector
+ */
+GtkAccelGroup *pcb_gtk_layer_selector_get_accel_group(pcb_gtk_layer_selector_t * ls);
+
+/** Toggles a layer's visibility
+    \par Function Description
+    Toggles the layer indicated by user_id, emitting a layer-toggle signal.
+  
+    \param [in] ls       The selector to be acted on
+    \param [in] user_id  The ID of the layer to be affected
+ */
+void pcb_gtk_layer_selector_toggle_layer(pcb_gtk_layer_selector_t * ls, gint user_id);
+
+/** Selects a layer
+    \par Function Description
+    Select the layer indicated by user_id, emitting a layer-select signal.
+  
+    \param [in] ls       The selector to be acted on
+    \param [in] user_id  The ID of the layer to be affected
+ */
+void pcb_gtk_layer_selector_select_layer(pcb_gtk_layer_selector_t * ls, gint user_id);
+
+/** Selects the next visible layer
+    \par Function Description
+    Used to ensure hidden layers are not active; if the active layer is
+    visible, this function is a noop. Otherwise, it will look for the
+    next layer that IS visible, and select that. Failing that, it will
+    return FALSE.
+  
+    \param [in] ls       The selector to be acted on
+  
+    \return TRUE on success, FALSE if all selectable layers are hidden
+ */
+gboolean pcb_gtk_layer_selector_select_next_visible(pcb_gtk_layer_selector_t * ls);
+
+/** Sets the colors of all layers in a layer-selector
+    \par Function Description
+    Updates the colors of a layer selector via a callback mechanism:
+    the user_id of each layer is passed to the callback function,
+    which returns a color string to update the layer's color, or NULL
+    to leave it alone.
+  
+    \param [in] ls       The selector to be acted on
+    \param [in] callback Takes the user_id of the layer and returns a color string
+ */
+void pcb_gtk_layer_selector_update_colors(pcb_gtk_layer_selector_t * ls, const gchar * (*callback) (int user_id));
+
+/** Deletes layers from a layer selector
+    \par Function Description
+    Deletes layers according to a callback function: a return value of TRUE
+    means delete, FALSE means leave it alone. Do not try to delete all layers
+    using this function; with nothing left to select, pcb will likely go into
+    an infinite recursion between pcb_hid_action() and g_signal().
+  
+    Separators will be deleted if the layer AFTER them is deleted.
+  
+    \param [in] ls       The selector to be acted on
+    \param [in] callback Takes the user_id of the layer and returns a boolean
+ */
+void pcb_gtk_layer_selector_delete_layers(pcb_gtk_layer_selector_t * ls, gboolean(*callback) (int user_id));
+
+/** Sets the visibility toggle-state of all layers
+    \par Function Description
+    Shows layers according to a callback function: a return value of TRUE
+    means show, FALSE means hide.
+  
+    \param [in] ls       The selector to be acted on
+    \param [in] callback Takes the user_id of the layer and returns a boolean
+ */
+void pcb_gtk_layer_selector_show_layers(pcb_gtk_layer_selector_t * ls, gboolean(*callback) (int user_id));
+
+G_END_DECLS											/* keep c++ happy */
+#endif
diff --git a/src_plugins/lib_gtk_common/wt_layer_selector_cr.c b/src_plugins/lib_gtk_common/wt_layer_selector_cr.c
new file mode 100644
index 0000000..be2b6b3
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_layer_selector_cr.c
@@ -0,0 +1,260 @@
+/* COPYRIGHT: missing in the original file inherited from gEDA/PCB:
+   must be the same as in other gtk-related sources. */
+/*! \file <gtk-pcb-cell-render-visibility.c>
+ *  \brief Implementation of GtkCellRenderer for layer visibility toggler
+ *  \par More Information
+ *  For details on the functions implemented here, see the Gtk
+ *  documentation for the GtkCellRenderer object, which defines
+ *  the interface we are implementing.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "config.h"
+#include "compat_nls.h"
+
+#include "wt_layer_selector_cr.h"
+
+#include "util_str.h"
+
+
+enum {
+	TOGGLED,
+	LAST_SIGNAL
+};
+static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
+
+enum {
+	PROP_ACTIVE = 1,
+	PROP_COLOR
+};
+
+struct _GHidCellRendererVisibility {
+	GtkCellRenderer parent;
+
+	gboolean active;
+	gchar *color;
+};
+
+struct _GHidCellRendererVisibilityClass {
+	GtkCellRendererClass parent_class;
+
+	void (*toggled) (GHidCellRendererVisibility * cell, const gchar * path);
+};
+
+/* RENDERER FUNCTIONS */
+/*! \brief Calculates the window area the renderer will use */
+static void
+ghid_cell_renderer_visibility_get_size(GtkCellRenderer * cell,
+																			 GtkWidget * widget,
+																			 GdkRectangle * cell_area, gint * x_offset, gint * y_offset, gint * width, gint * height)
+{
+	GtkStyle *style = gtk_widget_get_style(widget);
+	gint w, h;
+	gint xpad, ypad;
+	gfloat xalign, yalign;
+
+	gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
+	gtk_cell_renderer_get_alignment(cell, &xalign, &yalign);
+
+	w = VISIBILITY_TOGGLE_SIZE + 2 * (xpad + style->xthickness);
+	h = VISIBILITY_TOGGLE_SIZE + 2 * (ypad + style->ythickness);
+
+	if (width)
+		*width = w;
+	if (height)
+		*height = h;
+
+	if (cell_area) {
+		if (x_offset) {
+			if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
+				xalign = 1. - xalign;
+			*x_offset = MAX(0, xalign * (cell_area->width - w));
+		}
+		if (y_offset)
+			*y_offset = MAX(0, yalign * (cell_area->height - h));
+	}
+}
+
+/*! \brief Actually renders the swatch */
+static void
+ghid_cell_renderer_visibility_render(GtkCellRenderer * cell,
+																		 GdkWindow * window,
+																		 GtkWidget * widget,
+																		 GdkRectangle * background_area,
+																		 GdkRectangle * cell_area, GdkRectangle * expose_area, GtkCellRendererState flags)
+{
+	GHidCellRendererVisibility *pcb_cell;
+	GdkRectangle toggle_rect;
+	GdkRectangle draw_rect;
+	gint xpad, ypad;
+
+	pcb_cell = GHID_CELL_RENDERER_VISIBILITY(cell);
+	ghid_cell_renderer_visibility_get_size(cell, widget, cell_area,
+																				 &toggle_rect.x, &toggle_rect.y, &toggle_rect.width, &toggle_rect.height);
+	gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
+
+	toggle_rect.x += cell_area->x + xpad;
+	toggle_rect.y += cell_area->y + ypad;
+	toggle_rect.width -= xpad * 2;
+	toggle_rect.height -= ypad * 2;
+
+	if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
+		return;
+
+	if (gdk_rectangle_intersect(expose_area, cell_area, &draw_rect)) {
+		GdkColor color;
+		cairo_t *cr = gdk_cairo_create(window);
+		if (expose_area) {
+			gdk_cairo_rectangle(cr, expose_area);
+			cairo_clip(cr);
+		}
+		cairo_set_line_width(cr, 1);
+
+		cairo_rectangle(cr, toggle_rect.x + 0.5, toggle_rect.y + 0.5, toggle_rect.width - 1, toggle_rect.height - 1);
+		cairo_set_source_rgb(cr, 1, 1, 1);
+		cairo_fill_preserve(cr);
+		cairo_set_source_rgb(cr, 0, 0, 0);
+		cairo_stroke(cr);
+
+		gdk_color_parse(pcb_cell->color, &color);
+		if (flags & GTK_CELL_RENDERER_PRELIT) {
+			color.red = (4 * color.red + 65535) / 5;
+			color.green = (4 * color.green + 65535) / 5;
+			color.blue = (4 * color.blue + 65535) / 5;
+		}
+		gdk_cairo_set_source_color(cr, &color);
+		if (pcb_cell->active)
+			cairo_rectangle(cr, toggle_rect.x + 0.5, toggle_rect.y + 0.5, toggle_rect.width - 1, toggle_rect.height - 1);
+		else {
+			cairo_move_to(cr, toggle_rect.x + 1, toggle_rect.y + 1);
+			cairo_rel_line_to(cr, toggle_rect.width / 2, 0);
+			cairo_rel_line_to(cr, -toggle_rect.width / 2, toggle_rect.width / 2);
+			cairo_close_path(cr);
+		}
+		cairo_fill(cr);
+
+		cairo_destroy(cr);
+	}
+}
+
+/*! \brief Toggless the swatch */
+static gint
+ghid_cell_renderer_visibility_activate(GtkCellRenderer * cell,
+																			 GdkEvent * event,
+																			 GtkWidget * widget,
+																			 const gchar * path,
+																			 GdkRectangle * background_area, GdkRectangle * cell_area, GtkCellRendererState flags)
+{
+	g_signal_emit(cell, toggle_cell_signals[TOGGLED], 0, path);
+	return TRUE;
+}
+
+/* Setter/Getter */
+static void ghid_cell_renderer_visibility_get_property(GObject * object, guint param_id, GValue * value, GParamSpec * pspec)
+{
+	GHidCellRendererVisibility *pcb_cell = GHID_CELL_RENDERER_VISIBILITY(object);
+
+	switch (param_id) {
+	case PROP_ACTIVE:
+		g_value_set_boolean(value, pcb_cell->active);
+		break;
+	case PROP_COLOR:
+		g_value_set_string(value, pcb_cell->color);
+		break;
+	}
+}
+
+static void
+ghid_cell_renderer_visibility_set_property(GObject * object, guint param_id, const GValue * value, GParamSpec * pspec)
+{
+	GHidCellRendererVisibility *pcb_cell = GHID_CELL_RENDERER_VISIBILITY(object);
+
+	switch (param_id) {
+	case PROP_ACTIVE:
+		pcb_cell->active = g_value_get_boolean(value);
+		break;
+	case PROP_COLOR:
+		g_free(pcb_cell->color);
+		pcb_cell->color = g_value_dup_string(value);
+		break;
+	}
+}
+
+
+/* CONSTRUCTOR */
+static void ghid_cell_renderer_visibility_init(GHidCellRendererVisibility * ls)
+{
+	g_object_set(ls, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
+}
+
+static void ghid_cell_renderer_visibility_class_init(GHidCellRendererVisibilityClass * klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS(klass);
+	GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass);
+
+	object_class->get_property = ghid_cell_renderer_visibility_get_property;
+	object_class->set_property = ghid_cell_renderer_visibility_set_property;
+
+	cell_class->get_size = ghid_cell_renderer_visibility_get_size;
+	cell_class->render = ghid_cell_renderer_visibility_render;
+	cell_class->activate = ghid_cell_renderer_visibility_activate;
+
+	g_object_class_install_property(object_class, PROP_ACTIVE,
+																	g_param_spec_boolean("active",
+																											 _("Visibility state"),
+																											 _("Visibility of the layer"), FALSE, G_PARAM_READWRITE));
+	g_object_class_install_property(object_class, PROP_COLOR,
+																	g_param_spec_string("color", _("Layer color"), _("Layer color"), FALSE, G_PARAM_READWRITE));
+
+
+ /**
+  * GHidCellRendererVisibility::toggled:
+  * @cell_renderer: the object which received the signal
+  * @path: string representation of #GtkTreePath describing the 
+  *        event location
+  *
+  * The ::toggled signal is emitted when the cell is toggled. 
+  **/
+	toggle_cell_signals[TOGGLED] =
+		g_signal_new(_("toggled"),
+								 G_OBJECT_CLASS_TYPE(object_class),
+								 G_SIGNAL_RUN_LAST,
+								 G_STRUCT_OFFSET(GHidCellRendererVisibilityClass, toggled),
+								 NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+/* PUBLIC FUNCTIONS */
+GType ghid_cell_renderer_visibility_get_type(void)
+{
+	static GType ls_type = 0;
+
+	if (!ls_type) {
+		const GTypeInfo ls_info = {
+			sizeof(GHidCellRendererVisibilityClass),
+			NULL,											/* base_init */
+			NULL,											/* base_finalize */
+			(GClassInitFunc) ghid_cell_renderer_visibility_class_init,
+			NULL,											/* class_finalize */
+			NULL,											/* class_data */
+			sizeof(GHidCellRendererVisibility),
+			0,												/* n_preallocs */
+			(GInstanceInitFunc) ghid_cell_renderer_visibility_init,
+		};
+
+		ls_type = g_type_register_static(GTK_TYPE_CELL_RENDERER, "GHidCellRendererVisibility", &ls_info, 0);
+	}
+
+	return ls_type;
+}
+
+GtkCellRenderer *ghid_cell_renderer_visibility_new(void)
+{
+	GHidCellRendererVisibility *rv = g_object_new(GHID_CELL_RENDERER_VISIBILITY_TYPE, NULL);
+
+	rv->active = FALSE;
+
+	return GTK_CELL_RENDERER(rv);
+}
diff --git a/src_plugins/lib_gtk_common/wt_layer_selector_cr.h b/src_plugins/lib_gtk_common/wt_layer_selector_cr.h
new file mode 100644
index 0000000..a6de5a5
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_layer_selector_cr.h
@@ -0,0 +1,23 @@
+#ifndef GHID_CELL_RENDERER_VISIBILITY_H__
+#define GHID_CELL_RENDERER_VISIBILITY_H__
+
+/* Cell renderer for the layer selector widget */
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS										/* keep c++ happy */
+#define VISIBILITY_TOGGLE_SIZE	16
+#define GHID_CELL_RENDERER_VISIBILITY_TYPE            (ghid_cell_renderer_visibility_get_type ())
+#define GHID_CELL_RENDERER_VISIBILITY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_CELL_RENDERER_VISIBILITY_TYPE, GHidCellRendererVisibility))
+#define GHID_CELL_RENDERER_VISIBILITY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GHID_CELL_RENDERER_VISIBILITY_TYPE, GHidCellRendererVisibilityClass))
+#define IS_GHID_CELL_RENDERER_VISIBILITY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_CELL_RENDERER_VISIBILITY_TYPE))
+#define IS_GHID_CELL_RENDERER_VISIBILITY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHID_CELL_RENDERER_VISIBILITY_TYPE))
+typedef struct _GHidCellRendererVisibility GHidCellRendererVisibility;
+typedef struct _GHidCellRendererVisibilityClass GHidCellRendererVisibilityClass;
+
+GType ghid_cell_renderer_visibility_get_type(void);
+GtkCellRenderer *ghid_cell_renderer_visibility_new(void);
+
+G_END_DECLS											/* keep c++ happy */
+#endif
diff --git a/src_plugins/lib_gtk_common/wt_preview.c b/src_plugins/lib_gtk_common/wt_preview.c
new file mode 100644
index 0000000..0b8c76a
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_preview.c
@@ -0,0 +1,566 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This file copied and modified by Peter Clifton, starting from
+ * gui-pinout-window.c, written by Bill Wilson for the PCB Gtk port
+ * then got a major refactoring by Tibor 'Igor2' Palinkas in pcb-rnd
+ */
+
+#include "config.h"
+#include "conf_core.h"
+
+#include "wt_preview.h"
+
+#include "copy.h"
+#include "data.h"
+#include "draw.h"
+#include "move.h"
+#include "rotate.h"
+#include "obj_all.h"
+#include "macro.h"
+
+#include "in_mouse.h"
+
+/* Just define a sensible scale, lets say (for example), 100 pixel per 150 mil */
+#define SENSIBLE_VIEW_SCALE  (100. / PCB_MIL_TO_COORD (150.))
+static void pinout_set_view(pcb_gtk_preview_t * pinout)
+{
+	float scale = SENSIBLE_VIEW_SCALE;
+	pcb_element_t *elem = &pinout->element;
+
+#warning switch for .kind here and do a zoom-to-extend on layer
+
+	pinout->x_max = elem->BoundingBox.X2 + conf_core.appearance.pinout.offset_x;
+	pinout->y_max = elem->BoundingBox.Y2 + conf_core.appearance.pinout.offset_y;
+	pinout->w_pixels = scale * (elem->BoundingBox.X2 - elem->BoundingBox.X1);
+	pinout->h_pixels = scale * (elem->BoundingBox.Y2 - elem->BoundingBox.Y1);
+}
+
+
+static void pinout_set_data(pcb_gtk_preview_t * pinout, pcb_element_t * element)
+{
+	if (element == NULL) {
+		pcb_element_destroy(&pinout->element);
+		pinout->w_pixels = 0;
+		pinout->h_pixels = 0;
+		return;
+	}
+
+	/* 
+	 * copy element data 
+	 * enable output of pin and padnames
+	 * move element to a 5% offset from zero position
+	 * set all package lines/arcs to zero width
+	 */
+	pcb_element_copy(NULL, &pinout->element, element, FALSE, 0, 0);
+	PCB_PIN_LOOP(&pinout->element);
+	{
+		PCB_FLAG_SET(PCB_FLAG_DISPLAYNAME, pin);
+	}
+	PCB_END_LOOP;
+
+	PCB_PAD_LOOP(&pinout->element);
+	{
+		PCB_FLAG_SET(PCB_FLAG_DISPLAYNAME, pad);
+	}
+	PCB_END_LOOP;
+
+
+	pcb_element_move(NULL, &pinout->element,
+											conf_core.appearance.pinout.offset_x -
+											pinout->element.BoundingBox.X1, conf_core.appearance.pinout.offset_y - pinout->element.BoundingBox.Y1);
+
+	pinout_set_view(pinout);
+
+	PCB_ELEMENT_PCB_LINE_LOOP(&pinout->element);
+	{
+		line->Thickness = 0;
+	}
+	PCB_END_LOOP;
+
+	PCB_ARC_LOOP(&pinout->element);
+	{
+		/* 
+		 * for whatever reason setting a thickness of 0 causes the arcs to
+		 * not display so pick 1 which does display but is still quite
+		 * thin.
+		 */
+		arc->Thickness = 1;
+	}
+	PCB_END_LOOP;
+}
+
+
+enum {
+	PROP_ELEMENT_DATA = 1,
+	PROP_GPORT = 2,
+	PROP_INIT_WIDGET = 3,
+	PROP_EXPOSE = 4,
+	PROP_KIND = 5,
+	PROP_LAYER = 6,
+};
+
+
+static GObjectClass *ghid_pinout_preview_parent_class = NULL;
+
+
+/*! \brief GObject constructed
+ *
+ *  \par Function Description
+ *  Initialise the pinout preview object once it is constructed.
+ *  Chain up in case the parent class wants to do anything too.
+ *
+ *  \param [in] object  The pinout preview object
+ */
+static void ghid_pinout_preview_constructed(GObject * object)
+{
+
+	/* chain up to the parent class */
+	if (G_OBJECT_CLASS(ghid_pinout_preview_parent_class)->constructed != NULL)
+		G_OBJECT_CLASS(ghid_pinout_preview_parent_class)->constructed(object);
+
+}
+
+
+
+/*! \brief GObject finalise handler
+ *
+ *  \par Function Description
+ *  Just before the pcb_gtk_preview_t GObject is finalized, free our
+ *  allocated data, and then chain up to the parent's finalize handler.
+ *
+ *  \param [in] widget  The GObject being finalized.
+ */
+static void ghid_pinout_preview_finalize(GObject * object)
+{
+	pcb_gtk_preview_t *pinout = GHID_PINOUT_PREVIEW(object);
+
+	/* Passing NULL for element data will free the old memory */
+	pinout_set_data(pinout, NULL);
+
+	G_OBJECT_CLASS(ghid_pinout_preview_parent_class)->finalize(object);
+}
+
+
+/*! \brief GObject property setter function
+ *
+ *  \par Function Description
+ *  Setter function for pcb_gtk_preview_t's GObject properties,
+ *  "settings-name" and "toplevel".
+ *
+ *  \param [in]  object       The GObject whose properties we are setting
+ *  \param [in]  property_id  The numeric id. under which the property was
+ *                            registered with g_object_class_install_property()
+ *  \param [in]  value        The GValue the property is being set from
+ *  \param [in]  pspec        A GParamSpec describing the property being set
+ */
+static void ghid_pinout_preview_set_property(GObject * object, guint property_id, const GValue * value, GParamSpec * pspec)
+{
+	pcb_gtk_preview_t *pinout = GHID_PINOUT_PREVIEW(object);
+	GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(pinout));
+
+	switch (property_id) {
+	case PROP_ELEMENT_DATA:
+		pinout->kind = PCB_GTK_PREVIEW_PINOUT;
+		pinout_set_data(pinout, (pcb_element_t *) g_value_get_pointer(value));
+		pinout->expose_data.content.elem = &pinout->element;
+		if (window != NULL)
+			gdk_window_invalidate_rect(window, NULL, FALSE);
+		break;
+	case PROP_GPORT:
+		pinout->gport = (void *)g_value_get_pointer(value);
+		break;
+	case PROP_INIT_WIDGET:
+		pinout->init_drawing_widget = (void *)g_value_get_pointer(value);
+		break;
+	case PROP_EXPOSE:
+		pinout->expose = (void *)g_value_get_pointer(value);
+		break;
+	case PROP_KIND:
+		pinout->kind = g_value_get_int(value);
+		break;
+	case PROP_LAYER:
+		pinout->kind = PCB_GTK_PREVIEW_LAYER;
+		pinout->expose_data.content.layer_id = g_value_get_long(value);
+		if (window != NULL)
+			gdk_window_invalidate_rect(window, NULL, FALSE);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+	}
+
+}
+
+
+/*! \brief GObject property getter function
+ *
+ *  \par Function Description
+ *  Getter function for pcb_gtk_preview_t's GObject properties,
+ *  "settings-name" and "toplevel".
+ *
+ *  \param [in]  object       The GObject whose properties we are getting
+ *  \param [in]  property_id  The numeric id. under which the property was
+ *                            registered with g_object_class_install_property()
+ *  \param [out] value        The GValue in which to return the value of the property
+ *  \param [in]  pspec        A GParamSpec describing the property being got
+ */
+static void ghid_pinout_preview_get_property(GObject * object, guint property_id, GValue * value, GParamSpec * pspec)
+{
+	switch (property_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+	}
+
+}
+
+/* Converter: set up a pinout expose and use the generic preview expose call */
+static gboolean ghid_preview_expose(GtkWidget * widget, GdkEventExpose * ev)
+{
+	pcb_gtk_preview_t *pinout = GHID_PINOUT_PREVIEW(widget);
+
+	switch(pinout->kind) {
+		case PCB_GTK_PREVIEW_PINOUT:
+			pinout->expose_data.view.X1 = 0;
+			pinout->expose_data.view.Y1 = 0;
+			pinout->expose_data.view.X2 = pinout->x_max;
+			pinout->expose_data.view.Y2 = pinout->y_max;
+			return pinout->expose(widget, ev, pcb_hid_expose_pinout, &pinout->expose_data);
+
+		case PCB_GTK_PREVIEW_LAYER:
+			return pinout->expose(widget, ev, pcb_hid_expose_layer, &pinout->expose_data);
+
+		case PCB_GTK_PREVIEW_INVALID:
+		case PCB_GTK_PREVIEW_kind_max:
+			return FALSE;
+	}
+
+	return FALSE;
+}
+
+/*! \brief GType class initialiser for pcb_gtk_preview_t
+ *
+ *  \par Function Description
+ *  GType class initialiser for pcb_gtk_preview_t. We override our parent
+ *  virtual class methods as needed and register our GObject properties.
+ *
+ *  \param [in]  klass       The pcb_gtk_preview_class_t we are initialising
+ */
+static void ghid_pinout_preview_class_init(pcb_gtk_preview_class_t * klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+	GtkWidgetClass *gtk_widget_class = GTK_WIDGET_CLASS(klass);
+
+	gobject_class->finalize = ghid_pinout_preview_finalize;
+	gobject_class->set_property = ghid_pinout_preview_set_property;
+	gobject_class->get_property = ghid_pinout_preview_get_property;
+	gobject_class->constructed = ghid_pinout_preview_constructed;
+
+	gtk_widget_class->expose_event = ghid_preview_expose;
+
+	ghid_pinout_preview_parent_class = (GObjectClass *) g_type_class_peek_parent(klass);
+
+	g_object_class_install_property(gobject_class, PROP_ELEMENT_DATA,
+		g_param_spec_pointer("element-data", "", "", G_PARAM_WRITABLE));
+
+	g_object_class_install_property(gobject_class, PROP_GPORT,
+		g_param_spec_pointer("gport", "", "", G_PARAM_WRITABLE));
+
+	g_object_class_install_property(gobject_class, PROP_INIT_WIDGET,
+		g_param_spec_pointer("init-widget", "", "", G_PARAM_WRITABLE));
+
+	g_object_class_install_property(gobject_class, PROP_EXPOSE,
+		g_param_spec_pointer("expose", "", "", G_PARAM_WRITABLE));
+
+	g_object_class_install_property(gobject_class, PROP_KIND,
+		g_param_spec_int("kind", "", "", 0, PCB_GTK_PREVIEW_kind_max-1, 0, G_PARAM_WRITABLE));
+
+	g_object_class_install_property(gobject_class, PROP_LAYER,
+		g_param_spec_long("layer", "", "", -(1UL<<31), (1UL<<31)-1, -1, G_PARAM_WRITABLE));
+}
+
+
+/*! \brief Function to retrieve pcb_gtk_preview_t's GType identifier.
+ *
+ *  \par Function Description
+ *  Function to retrieve pcb_gtk_preview_t's GType identifier.
+ *  Upon first call, this registers the pcb_gtk_preview_t in the GType system.
+ *  Subsequently it returns the saved value from its first execution.
+ *
+ *  \return the GType identifier associated with pcb_gtk_preview_t.
+ */
+GType pcb_gtk_preview_get_type()
+{
+	static GType ghid_pinout_preview_type = 0;
+
+	if (!ghid_pinout_preview_type) {
+		static const GTypeInfo ghid_pinout_preview_info = {
+			sizeof(pcb_gtk_preview_class_t),
+			NULL,											/* base_init */
+			NULL,											/* base_finalize */
+			(GClassInitFunc) ghid_pinout_preview_class_init,
+			NULL,											/* class_finalize */
+			NULL,											/* class_data */
+			sizeof(pcb_gtk_preview_t),
+			0,												/* n_preallocs */
+			NULL,											/* instance_init */
+		};
+
+		ghid_pinout_preview_type =
+			g_type_register_static(GTK_TYPE_DRAWING_AREA, "pcb_gtk_preview_t", &ghid_pinout_preview_info, (GTypeFlags) 0);
+	}
+
+	return ghid_pinout_preview_type;
+}
+
+
+GtkWidget *pcb_gtk_preview_pinout_new(void *gport, pcb_gtk_init_drawing_widget_t init_widget, pcb_gtk_preview_expose_t expose, pcb_element_t *element)
+{
+	pcb_gtk_preview_t *pinout_preview;
+
+	pinout_preview = (pcb_gtk_preview_t *) g_object_new(GHID_TYPE_PINOUT_PREVIEW,
+		"element-data", element,
+		"gport", gport,
+		"init-widget", init_widget,
+		"expose", expose,
+		"kind", PCB_GTK_PREVIEW_PINOUT,
+		NULL);
+
+	pinout_preview->init_drawing_widget(GTK_WIDGET(pinout_preview), pinout_preview->gport);
+
+	return GTK_WIDGET(pinout_preview);
+}
+
+static void update_expose_data(pcb_gtk_preview_t *prv)
+{
+	pcb_gtk_zoom_post(&prv->view);
+	prv->expose_data.view.X1 = prv->view.x0;
+	prv->expose_data.view.Y1 = prv->view.y0;
+	prv->expose_data.view.X2 = prv->view.x0 + prv->view.width;
+	prv->expose_data.view.Y2 = prv->view.y0 + prv->view.height;
+
+/*	pcb_printf("EXPOSE_DATA: %$mm %$mm - %$mm %$mm (%f %$mm)\n",
+		prv->expose_data.view.X1, prv->expose_data.view.Y1,
+		prv->expose_data.view.X2, prv->expose_data.view.Y2,
+		prv->view.coord_per_px, prv->view.x0);*/
+}
+
+static gboolean preview_configure_event_cb(GtkWidget *w, GdkEventConfigure * ev, void *tmp)
+{
+	pcb_gtk_preview_t *preview = (pcb_gtk_preview_t *)w;
+	preview->win_w = ev->width;
+	preview->win_h = ev->height;
+
+	preview->view.canvas_width = ev->width;
+	preview->view.canvas_height = ev->height;
+
+	update_expose_data(preview);
+	return TRUE;
+}
+
+static void get_ptr(pcb_gtk_preview_t *preview, pcb_coord_t *cx, pcb_coord_t *cy, gint *xp, gint *yp)
+{
+	gdk_window_get_pointer(gtk_widget_get_window(GTK_WIDGET(preview)), xp, yp, NULL);
+#undef SIDE_X
+#undef SIDE_Y
+#define SIDE_X(x) x
+#define SIDE_Y(y) y
+	*cx = EVENT_TO_PCB_X(&preview->view, *xp);
+	*cy = EVENT_TO_PCB_Y(&preview->view, *yp);
+#undef SIDE_X
+#undef SIDE_Y
+}
+
+static gboolean button_press(GtkWidget *w, pcb_hid_cfg_mod_t btn)
+{
+	pcb_gtk_preview_t *preview = (pcb_gtk_preview_t *)w;
+	pcb_coord_t cx, cy;
+	gint wx, wy;
+	get_ptr(preview, &cx, &cy, &wx, &wy);
+
+	switch(btn) {
+		case PCB_MB_LEFT:
+			if (preview->mouse_cb != NULL) {
+/*				pcb_printf("bp %mm %mm\n", cx, cy); */
+				if (preview->mouse_cb(w, PCB_HID_MOUSE_PRESS, cx, cy))
+					ghid_preview_expose(w, NULL);
+			}
+			break;
+		case PCB_MB_RIGHT:
+			preview->view.panning = 1;
+			preview->grabx = cx;
+			preview->graby = cy;
+			break;
+		case PCB_MB_SCROLL_UP:
+			pcb_gtk_zoom_view_rel(&preview->view, 0, 0, 0.8);
+			goto do_zoom;
+		case PCB_MB_SCROLL_DOWN:
+			pcb_gtk_zoom_view_rel(&preview->view, 0, 0, 1.25);
+			goto do_zoom;
+		default:
+			return FALSE;
+	}
+	return FALSE;
+
+	do_zoom:;
+	preview->view.x0 = cx - (preview->view.canvas_width / 2) * preview->view.coord_per_px;
+	preview->view.y0 = cy - (preview->view.canvas_height / 2) * preview->view.coord_per_px;
+	update_expose_data(preview);
+	ghid_preview_expose(w, NULL);
+
+	return FALSE;
+}
+
+static gboolean preview_button_press_cb(GtkWidget *w, GdkEventButton * ev, gpointer data)
+{
+	return button_press(w, ghid_mouse_button(ev->button));
+}
+
+static gboolean preview_scroll_cb(GtkWidget *w, GdkEventScroll *ev, gpointer data)
+{
+	switch (ev->direction) {
+		case GDK_SCROLL_UP:    return button_press(w, PCB_MB_SCROLL_UP);
+		case GDK_SCROLL_DOWN:  return button_press(w, PCB_MB_SCROLL_DOWN);
+		default:;
+	}
+	return FALSE;
+}
+
+static gboolean preview_button_release_cb(GtkWidget *w, GdkEventButton * ev, gpointer data)
+{
+	pcb_gtk_preview_t *preview = (pcb_gtk_preview_t *)w;
+
+	switch(ghid_mouse_button(ev->button)) {
+		case PCB_MB_RIGHT:
+			preview->view.panning = 0;
+			break;
+		case PCB_MB_LEFT:
+			if (preview->mouse_cb != NULL) {
+				pcb_coord_t cx, cy;
+				gint wx, wy;
+				get_ptr(preview, &cx, &cy, &wx, &wy);
+/*				pcb_printf("br %mm %mm\n", cx, cy); */
+				if (preview->mouse_cb(w, PCB_HID_MOUSE_RELEASE, cx, cy))
+					ghid_preview_expose(w, NULL);
+			}
+			break;
+		default: ;
+	}
+	return FALSE;
+}
+
+#warning TODO: this should go in the renderer (e.g. gdk) API .h
+gboolean ghid_preview_draw(GtkWidget * widget, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx);
+
+static gboolean preview_motion_cb(GtkWidget *w, GdkEventMotion * ev, gpointer data)
+{
+	pcb_gtk_preview_t *preview = (pcb_gtk_preview_t *)w;
+	pcb_coord_t cx, cy;
+	gint wx, wy;
+	get_ptr(preview, &cx, &cy, &wx, &wy);
+
+	if (preview->view.panning) {
+		preview->view.x0 = preview->grabx - wx * preview->view.coord_per_px;
+		preview->view.y0 = preview->graby - wy * preview->view.coord_per_px;
+		update_expose_data(preview);
+		ghid_preview_expose(w, NULL);
+		return FALSE;
+	}
+
+
+
+	if (preview->mouse_cb != NULL) {
+/*		pcb_printf("mo %mm %mm\n", cx, cy); */
+		preview->mouse_cb(w, PCB_HID_MOUSE_MOTION, cx, cy);
+		if (preview->overlay_draw_cb != NULL)
+			ghid_preview_draw(w, preview->overlay_draw_cb, &preview->expose_data);
+	}
+	return FALSE;
+}
+
+
+/*
+static gboolean preview_key_press_cb(GtkWidget *preview, GdkEventKey * kev, gpointer data)
+{
+	printf("kp\n");
+}
+
+static gboolean preview_key_release_cb(GtkWidget *preview, GdkEventKey * kev, gpointer data)
+{
+	printf("kr\n");
+}
+*/
+
+GtkWidget *pcb_gtk_preview_layer_new(void *gport, pcb_gtk_init_drawing_widget_t init_widget, pcb_gtk_preview_expose_t expose, pcb_layer_id_t layer)
+{
+	pcb_gtk_preview_t *prv;
+
+	prv = (pcb_gtk_preview_t *) g_object_new(GHID_TYPE_PINOUT_PREVIEW,
+		"layer", layer,
+		"gport", gport,
+		"init-widget", init_widget,
+		"expose", expose,
+		"kind", PCB_GTK_PREVIEW_LAYER,
+		"width-request", 50,
+		"height-request", 50,
+		NULL);
+
+#warning TODO: maybe expose these through the object API so the caller can set it up?
+	memset(&prv->view, 0, sizeof(prv->view));
+	prv->view.width = PCB_MM_TO_COORD(110);
+	prv->view.height = PCB_MM_TO_COORD(110);
+	prv->view.coord_per_px = PCB_MM_TO_COORD(0.25);
+
+	update_expose_data(prv);
+
+	prv->expose_data.force = 1;
+	prv->init_drawing_widget(GTK_WIDGET(prv), prv->gport);
+
+	gtk_widget_add_events(GTK_WIDGET(prv), GDK_EXPOSURE_MASK
+		| GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK | GDK_BUTTON_RELEASE_MASK
+		| GDK_BUTTON_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_KEY_PRESS_MASK
+		| GDK_FOCUS_CHANGE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
+
+
+	g_signal_connect(G_OBJECT(prv), "button_press_event", G_CALLBACK(preview_button_press_cb), NULL);
+	g_signal_connect(G_OBJECT(prv), "button_release_event", G_CALLBACK(preview_button_release_cb), NULL);
+	g_signal_connect(G_OBJECT(prv), "scroll_event", G_CALLBACK(preview_scroll_cb), NULL);
+	g_signal_connect(G_OBJECT(prv), "configure_event", G_CALLBACK(preview_configure_event_cb), NULL);
+	g_signal_connect(G_OBJECT(prv), "motion_notify_event", G_CALLBACK(preview_motion_cb), NULL);
+
+/*
+	g_signal_connect(G_OBJECT(prv), "key_press_event", G_CALLBACK(preview_key_press_cb), NULL);
+	g_signal_connect(G_OBJECT(prv), "key_release_event", G_CALLBACK(preview_key_release_cb), NULL);
+*/
+
+	return GTK_WIDGET(prv);
+}
+
+void pcb_gtk_preview_get_natsize(pcb_gtk_preview_t * pinout, int *width, int *height)
+{
+	*width = pinout->w_pixels;
+	*height = pinout->h_pixels;
+}
diff --git a/src_plugins/lib_gtk_common/wt_preview.h b/src_plugins/lib_gtk_common/wt_preview.h
new file mode 100644
index 0000000..a314d0a
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_preview.h
@@ -0,0 +1,101 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau at rz.uni-ulm.de
+ *
+ */
+
+/* This file was originally written by Peter Clifton
+   then got a major refactoring by Tibor 'Igor2' Palinkas in pcb-rnd
+*/
+
+#ifndef PCB_GTK_WT_REVIEW_H
+#define PCB_GTK_WT_REVIEW_H
+
+#include <gtk/gtk.h>
+#include "obj_elem.h"
+#include "hid.h"
+#include "layer.h"
+#include "ui_zoompan.h"
+
+#define GHID_TYPE_PINOUT_PREVIEW           (pcb_gtk_preview_get_type())
+#define GHID_PINOUT_PREVIEW(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_TYPE_PINOUT_PREVIEW, pcb_gtk_preview_t))
+#define GHID_PINOUT_PREVIEW_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass),  GHID_TYPE_PINOUT_PREVIEW, pcb_gtk_preview_class_t))
+#define GHID_IS_PINOUT_PREVIEW(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_TYPE_PINOUT_PREVIEW))
+#define GHID_PINOUT_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),  GHID_TYPE_PINOUT_PREVIEW, pcb_gtk_preview_class_t))
+
+typedef struct pcb_gtk_preview_class_s pcb_gtk_preview_class_t;
+typedef struct pcb_gtk_preview_s pcb_gtk_preview_t;
+
+
+struct pcb_gtk_preview_class_s {
+	GtkDrawingAreaClass parent_class;
+};
+
+typedef void (*pcb_gtk_init_drawing_widget_t)(GtkWidget *widget, void *port);
+typedef gboolean (*pcb_gtk_preview_expose_t)(GtkWidget *widget, GdkEventExpose * ev, pcb_hid_expose_t expcall, const pcb_hid_expose_ctx_t *ctx);
+typedef pcb_bool (*pcb_gtk_preview_mouse_ev_t)(void *widget, pcb_hid_mouse_ev_t kind, pcb_coord_t x, pcb_coord_t y);
+
+
+typedef enum pcb_gtk_preview_kind_e {
+	PCB_GTK_PREVIEW_INVALID,
+	PCB_GTK_PREVIEW_PINOUT, /* render a single element */
+	PCB_GTK_PREVIEW_LAYER,  /* render a specific layer */
+
+	PCB_GTK_PREVIEW_kind_max
+} pcb_gtk_preview_kind_t;
+
+struct pcb_gtk_preview_s {
+	GtkDrawingArea parent_instance;
+
+	pcb_hid_expose_ctx_t expose_data;
+	pcb_gtk_view_t view;
+
+	pcb_coord_t x_max, y_max; /* for the element preview only */
+	gint win_w, win_h;
+	gint w_pixels, h_pixels;			/* natural size of element preview */
+
+	void *gport;
+	pcb_gtk_init_drawing_widget_t init_drawing_widget;
+	pcb_gtk_preview_expose_t expose;
+	pcb_gtk_preview_kind_t kind;
+	pcb_gtk_preview_mouse_ev_t mouse_cb;
+	pcb_hid_expose_t overlay_draw_cb;
+	pcb_coord_t grabx, graby;
+
+
+	pcb_element_t element;
+};
+
+
+
+GType pcb_gtk_preview_get_type(void);
+
+/* Query the natural size of a preview widget */
+void pcb_gtk_preview_get_natsize(pcb_gtk_preview_t * pinout, int *width, int *height);
+
+GtkWidget *pcb_gtk_preview_pinout_new(void *gport, pcb_gtk_init_drawing_widget_t init_widget, pcb_gtk_preview_expose_t expose, pcb_element_t *element);
+GtkWidget *pcb_gtk_preview_layer_new(void *gport, pcb_gtk_init_drawing_widget_t init_widget, pcb_gtk_preview_expose_t expose, pcb_layer_id_t layer);
+
+
+#endif /* PCB_GTK_WT_REVIEW_H */
diff --git a/src_plugins/lib_gtk_common/wt_route_style.c b/src_plugins/lib_gtk_common/wt_route_style.c
new file mode 100644
index 0000000..a459f9d
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_route_style.c
@@ -0,0 +1,371 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *  pcb-rnd, interactive printed circuit board design
+ *  Copyright (C) 2017 Alain Vigne
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/** Implementation of pcb_gtk_route_style_t widget.
+    This widget is calling another Dialog, upon "Edit" clicked button */
+
+#include "config.h"
+#include "conf_core.h"
+
+#include <gdk/gdkkeysyms.h>
+
+#include "dlg_route_style.h"
+
+#include "pcb-printf.h"
+#include "board.h"
+#include "compat_nls.h"
+
+#include "bu_status_line.h"
+
+
+/** Global action creation counter */
+static gint action_count;
+
+static GtkVBox *pcb_gtk_route_style_parent_class;
+guint pcb_gtk_route_style_signals_id[STYLE_LAST_SIGNAL] = { 0 };
+
+
+#warning TODO: this should be in core
+void pcb_gtk_route_style_copy(int idx)
+{
+	pcb_route_style_t *drst;
+
+	if ((idx < 0) || (idx >= vtroutestyle_len(&PCB->RouteStyle)))
+		return;
+	drst = PCB->RouteStyle.array + idx;
+	pcb_custom_route_style.Thick = drst->Thick;
+	pcb_custom_route_style.Clearance = drst->Clearance;
+	pcb_custom_route_style.Diameter = drst->Diameter;
+	pcb_custom_route_style.Hole = drst->Hole;
+}
+
+/** Launches the Edit dialog */
+static void edit_button_cb(GtkButton * btn, gpointer rss)
+{
+	pcb_gtk_route_style_edit_dialog((pcb_gtk_route_style_t *) rss);
+}
+
+/** Callback for user selection of a route style */
+static void radio_select_cb(GtkToggleAction * action, gpointer data)
+{
+	pcb_gtk_route_style_t *rss = (pcb_gtk_route_style_t *) data;
+
+	rss->active_style = g_object_get_data(G_OBJECT(action), "route-style");
+	if (gtk_toggle_action_get_active(action))
+		g_signal_emit(rss, pcb_gtk_route_style_signals_id[SELECT_STYLE_SIGNAL], 0, rss->active_style->rst);
+}
+
+/* CONSTRUCTOR */
+static void ghid_route_style_init(pcb_gtk_route_style_t * rss)
+{
+}
+
+/** Clean up object before garbage collection */
+static void ghid_route_style_finalize(GObject * object)
+{
+	pcb_gtk_route_style_t *rss = (pcb_gtk_route_style_t *) object;
+
+	pcb_gtk_route_style_empty(rss);
+
+	g_object_unref(rss->accel_group);
+	g_object_unref(rss->action_group);
+
+	G_OBJECT_CLASS(pcb_gtk_route_style_parent_class)->finalize(object);
+}
+
+static void ghid_route_style_class_init(pcb_gtk_route_style_class_t * klass)
+{
+	GObjectClass *object_class = (GObjectClass *) klass;
+
+	pcb_gtk_route_style_parent_class = g_type_class_peek_parent(klass);
+
+	pcb_gtk_route_style_signals_id[SELECT_STYLE_SIGNAL] =
+		g_signal_new("select-style",
+								 G_TYPE_FROM_CLASS(klass),
+								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+								 G_STRUCT_OFFSET(pcb_gtk_route_style_class_t, select_style),
+								 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+	pcb_gtk_route_style_signals_id[STYLE_EDITED_SIGNAL] =
+		g_signal_new("style-edited",
+								 G_TYPE_FROM_CLASS(klass),
+								 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+								 G_STRUCT_OFFSET(pcb_gtk_route_style_class_t, style_edited),
+								 NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+	object_class->finalize = ghid_route_style_finalize;
+}
+
+
+/* PUBLIC FUNCTIONS */
+
+GType pcb_gtk_route_style_get_type(void)
+{
+	static GType rss_type = 0;
+
+	if (!rss_type) {
+		const GTypeInfo rss_info = {
+			sizeof(pcb_gtk_route_style_class_t),
+			NULL,											/* base_init */
+			NULL,											/* base_finalize */
+			(GClassInitFunc) ghid_route_style_class_init,
+			NULL,											/* class_finalize */
+			NULL,											/* class_data */
+			sizeof(pcb_gtk_route_style_t),
+			0,												/* n_preallocs */
+			(GInstanceInitFunc) ghid_route_style_init,
+		};
+
+		rss_type = g_type_register_static(GTK_TYPE_VBOX, "pcb_gtk_route_style_t", &rss_info, 0);
+	}
+
+	return rss_type;
+}
+
+GtkWidget *pcb_gtk_route_style_new()
+{
+	pcb_gtk_route_style_t *rss = g_object_new(GHID_ROUTE_STYLE_TYPE, NULL);
+
+	rss->active_style = NULL;
+	rss->action_radio_group = NULL;
+	rss->button_radio_group = NULL;
+	rss->model = gtk_list_store_new(STYLE_N_COLS, G_TYPE_STRING, G_TYPE_POINTER);
+
+	rss->accel_group = gtk_accel_group_new();
+	rss->action_group = gtk_action_group_new("RouteStyleSelector");
+
+	/* Create edit button */
+	rss->edit_button = gtk_button_new_with_label(_("Route Styles"));
+	g_signal_connect(G_OBJECT(rss->edit_button), "clicked", G_CALLBACK(edit_button_cb), rss);
+	gtk_box_pack_start(GTK_BOX(rss), rss->edit_button, FALSE, FALSE, 0);
+
+	return GTK_WIDGET(rss);
+}
+
+pcb_gtk_obj_route_style_t *pcb_gtk_route_style_add_route_style(pcb_gtk_route_style_t * rss, pcb_route_style_t * data, int hide)
+{
+	GtkTreeIter iter;
+	GtkTreePath *path;
+	gchar *action_name = g_strdup_printf("RouteStyle%d", action_count);
+	pcb_gtk_obj_route_style_t *new_style = g_malloc(sizeof(*new_style));
+
+	/* Key the route style data with the pcb_route_style_t it controls */
+	new_style->hidden = hide;
+	new_style->rst = data;
+	new_style->action = gtk_radio_action_new(action_name, data->name, NULL, NULL, action_count);
+	gtk_radio_action_set_group(new_style->action, rss->action_radio_group);
+	rss->action_radio_group = gtk_radio_action_get_group(new_style->action);
+	new_style->button = gtk_radio_button_new(rss->button_radio_group);
+	rss->button_radio_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(new_style->button));
+	gtk_activatable_set_related_action(GTK_ACTIVATABLE(new_style->button), GTK_ACTION(new_style->action));
+
+	gtk_list_store_append(rss->model, &iter);
+	gtk_list_store_set(rss->model, &iter, STYLE_TEXT_COL, data->name, STYLE_DATA_COL, new_style, -1);
+	path = gtk_tree_model_get_path(GTK_TREE_MODEL(rss->model), &iter);
+	new_style->rref = gtk_tree_row_reference_new(GTK_TREE_MODEL(rss->model), path);
+	gtk_tree_path_free(path);
+
+	/* Setup accelerator */
+	if (action_count < 12) {
+		gchar *accel = g_strdup_printf("<Ctrl>F%d", action_count + 1);
+		gtk_action_set_accel_group(GTK_ACTION(new_style->action), rss->accel_group);
+		gtk_action_group_add_action_with_accel(rss->action_group, GTK_ACTION(new_style->action), accel);
+		g_free(accel);
+	}
+
+	/* Hookup and install radio button */
+	g_object_set_data(G_OBJECT(new_style->action), "route-style", new_style);
+	new_style->sig_id = g_signal_connect(G_OBJECT(new_style->action), "activate", G_CALLBACK(radio_select_cb), rss);
+	gtk_box_pack_start(GTK_BOX(rss), new_style->button, FALSE, FALSE, 0);
+
+	g_free(action_name);
+	++action_count;
+
+	if (hide)
+		gtk_widget_hide(new_style->button);
+
+	return new_style;
+}
+
+/** Adds a PCB route style to a \ref pcb_gtk_route_style_t object.
+    Note that the route style object passed to this function will be
+    updated directly.
+
+    \param rss     The widget to be acted on
+    \param data    PCB's route style object describing the style
+ */
+static void add_route_style_with_hidden_check(pcb_gtk_route_style_t * rss, pcb_route_style_t * data)
+{
+	if (!rss->hidden_button) {
+		if (*pcb_custom_route_style.name == '\0') {
+			memset(&pcb_custom_route_style, 0, sizeof(pcb_custom_route_style));
+			strcpy(pcb_custom_route_style.name, "<custom>");
+			pcb_gtk_route_style_copy(0);
+		}
+		pcb_gtk_route_style_add_route_style(rss, &pcb_custom_route_style, 1);
+		rss->hidden_button = 1;
+	}
+	if (data != NULL)
+		pcb_gtk_route_style_add_route_style(rss, data, 0);
+}
+
+gint pcb_gtk_route_style_install_items(pcb_gtk_route_style_t * rss, GtkMenuShell * shell, gint pos)
+{
+	gint n = 0;
+	GtkTreeIter iter;
+
+	if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter))
+		return 0;
+	do {
+		GtkAction *action;
+		pcb_gtk_obj_route_style_t *style;
+
+		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, STYLE_DATA_COL, &style, -1);
+		if (style->hidden)
+			continue;
+		action = GTK_ACTION(style->action);
+		style->menu_item = gtk_action_create_menu_item(action);
+		gtk_menu_shell_insert(shell, style->menu_item, pos + n);
+		++n;
+	}
+	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(rss->model), &iter));
+
+	return n;
+}
+
+gboolean pcb_gtk_route_style_select_style(pcb_gtk_route_style_t * rss, pcb_route_style_t * rst)
+{
+	GtkTreeIter iter;
+	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter);
+
+	do {
+		pcb_gtk_obj_route_style_t *style;
+
+		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, STYLE_DATA_COL, &style, -1);
+		if ((style != NULL) && (style->rst == rst)) {
+			g_signal_handler_block(G_OBJECT(style->action), style->sig_id);
+			gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(style->action), TRUE);
+			g_signal_handler_unblock(G_OBJECT(style->action), style->sig_id);
+			rss->active_style = style;
+			g_signal_emit(rss, pcb_gtk_route_style_signals_id[SELECT_STYLE_SIGNAL], 0, rss->active_style->rst);
+			return TRUE;
+		}
+	}
+	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(rss->model), &iter));
+
+	return FALSE;
+}
+
+GtkAccelGroup *pcb_gtk_route_style_get_accel_group(pcb_gtk_route_style_t * rss)
+{
+	return rss->accel_group;
+}
+
+void pcb_gtk_route_style_sync(pcb_gtk_route_style_t * rss,
+															pcb_coord_t Thick, pcb_coord_t Hole, pcb_coord_t Diameter, pcb_coord_t Clearance)
+{
+	GtkTreeIter iter;
+	int target, n;
+
+	/* Always update the label - even if there's no style, the current settings need to show */
+	ghid_set_status_line_label();
+
+	if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter))
+		return;
+
+	target = pcb_route_style_lookup(&PCB->RouteStyle, Thick, Diameter, Hole, Clearance, NULL);
+	if (target == -1) {
+		pcb_gtk_obj_route_style_t *style;
+
+		/* None of the styles matched: select the hidden custom button */
+		if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter))
+			return;
+
+		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, STYLE_DATA_COL, &style, -1);
+		g_signal_handler_block(G_OBJECT(style->action), style->sig_id);
+		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(style->action), TRUE);
+		g_signal_handler_unblock(G_OBJECT(style->action), style->sig_id);
+		rss->active_style = style;
+
+		return;
+	}
+
+	/* need to select the style with index stored in target */
+	n = -1;
+	do {
+		pcb_gtk_obj_route_style_t *style;
+		gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, STYLE_DATA_COL, &style, -1);
+		if (n == target) {
+			g_signal_handler_block(G_OBJECT(style->action), style->sig_id);
+			gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(style->action), TRUE);
+			g_signal_handler_unblock(G_OBJECT(style->action), style->sig_id);
+			rss->active_style = style;
+			break;
+		}
+		n++;
+	} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(rss->model), &iter));
+}
+
+void pcb_gtk_route_style_empty(pcb_gtk_route_style_t * rss)
+{
+	GtkTreeIter iter;
+	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(rss->model), &iter)) {
+		do {
+			pcb_gtk_obj_route_style_t *rsdata;
+			gtk_tree_model_get(GTK_TREE_MODEL(rss->model), &iter, STYLE_DATA_COL, &rsdata, -1);
+			if (rsdata != NULL) {
+				if (rsdata->action) {
+					gtk_action_disconnect_accelerator(GTK_ACTION(rsdata->action));
+					gtk_action_group_remove_action(rss->action_group, GTK_ACTION(rsdata->action));
+					g_object_unref(G_OBJECT(rsdata->action));
+				}
+				if (rsdata->button)
+					gtk_widget_destroy(GTK_WIDGET(rsdata->button));;
+				gtk_tree_row_reference_free(rsdata->rref);
+				free(rsdata);
+			}
+		} while (gtk_list_store_remove(rss->model, &iter));
+	}
+	rss->action_radio_group = NULL;
+	rss->button_radio_group = NULL;
+	rss->hidden_button = 0;
+}
+
+/** Called when a route style is selected. */
+static void route_style_changed_cb(pcb_gtk_route_style_t * rss, pcb_route_style_t * rst, gpointer data)
+{
+	pcb_use_route_style(rst);
+	ghid_set_status_line_label();
+}
+
+void make_route_style_buttons(pcb_gtk_route_style_t * rss)
+{
+	int i;
+
+	/* Make sure the <custom> item is added */
+	add_route_style_with_hidden_check(rss, NULL);
+
+	for (i = 0; i < vtroutestyle_len(&PCB->RouteStyle); ++i)
+		add_route_style_with_hidden_check(rss, &PCB->RouteStyle.array[i]);
+	g_signal_connect(G_OBJECT(rss), "select_style", G_CALLBACK(route_style_changed_cb), NULL);
+	g_signal_connect(G_OBJECT(rss), "style_edited", G_CALLBACK(route_styles_edited_cb), NULL);
+}
diff --git a/src_plugins/lib_gtk_common/wt_route_style.h b/src_plugins/lib_gtk_common/wt_route_style.h
new file mode 100644
index 0000000..ace6f81
--- /dev/null
+++ b/src_plugins/lib_gtk_common/wt_route_style.h
@@ -0,0 +1,163 @@
+#ifndef GHID_ROUTE_STYLE_H__
+#define GHID_ROUTE_STYLE_H__
+
+#include <gtk/gtk.h>
+
+#include "route_style.h"
+
+G_BEGIN_DECLS										/* keep c++ happy */
+#define GHID_ROUTE_STYLE_TYPE            (pcb_gtk_route_style_get_type ())
+#define GHID_ROUTE_STYLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj),  GHID_ROUTE_STYLE_TYPE, pcb_gtk_route_style_t))
+#define GHID_ROUTE_STYLE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),   GHID_ROUTE_STYLE_TYPE, pcb_gtk_route_style_class_t))
+#define IS_GHID_ROUTE_STYLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj),  GHID_ROUTE_STYLE_TYPE))
+#define IS_GHID_ROUTE_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),   GHID_ROUTE_STYLE_TYPE))
+/** Structure for "Edit Route Style" Dialog */
+typedef struct pcb_gtk_dlg_route_style_s pcb_gtk_dlg_route_style_t;
+
+/** The route style selector widget object data. */
+struct pcb_gtk_route_style_s {
+	/*  GTK3 incompatibility : GTK3 prefers a GtkGrid with "orientation" property
+	   set to GTK_ORIENTATION_VERTICAL, and packed children from
+	   the start, using gtk_container_add(GTK_CONTAINER(grid), w);
+	 */
+	GtkVBox parent;
+
+	GSList *button_radio_group;
+	GSList *action_radio_group;
+	GtkWidget *edit_button;
+
+	/*  GTK3 deprecated since version 3.10 Use GAction instead, and associate actions
+	   with GtkActionable widgets. Use GMenuModel for creating menus with gtk_menu_new_from_model().
+	 */
+	GtkActionGroup *action_group;
+	GtkAccelGroup *accel_group;
+
+	int hidden_button;						/* whether the hidden button is created         */
+	int selected;									/* index of the currently selected route style  */
+
+	GtkListStore *model;					/* All the route styles                         */
+	struct pcb_gtk_obj_route_style_s *active_style;	/* The current route style    */
+
+	GtkTreeIter new_iter;					/* iter for the <new> item */
+};
+
+typedef struct pcb_gtk_route_style_s pcb_gtk_route_style_t;
+
+/** The route style selector widget Class. */
+struct pcb_gtk_route_style_class_s {
+	GtkVBoxClass parent_class;
+
+	void (*select_style) (pcb_gtk_route_style_t *, pcb_route_style_t *);
+	void (*style_edited) (pcb_gtk_route_style_t *, gboolean);
+};
+
+typedef struct pcb_gtk_route_style_class_s pcb_gtk_route_style_class_t;
+
+/** Signals exposed by the widget. */
+enum {
+	SELECT_STYLE_SIGNAL,
+	STYLE_EDITED_SIGNAL,
+	STYLE_LAST_SIGNAL
+};
+
+/** All available GObject signals IDs. */
+extern guint pcb_gtk_route_style_signals_id[STYLE_LAST_SIGNAL];
+
+
+/** Columns used for internal data store. */
+enum {
+	STYLE_TEXT_COL,
+	STYLE_DATA_COL,
+	STYLE_N_COLS
+};
+
+/** Structure for a single Route Style object. */
+struct pcb_gtk_obj_route_style_s {
+	GtkRadioAction *action;
+	GtkWidget *button;
+	GtkWidget *menu_item;
+	GtkTreeRowReference *rref;
+	pcb_route_style_t *rst;
+	gulong sig_id;
+	int hidden;
+};
+
+typedef struct pcb_gtk_obj_route_style_s pcb_gtk_obj_route_style_t;
+
+/* API */
+
+/** GObject type for this widget. */
+GType pcb_gtk_route_style_get_type(void);
+
+/** Creates and returns a new freshly-allocated \ref pcb_gtk_route_style_t object. */
+GtkWidget *pcb_gtk_route_style_new(void);
+
+/** Installs the "Route Style" menu items.
+    Takes a menu shell and installs menu items for route style selection in
+    the shell, at the given position. Note that we aren't really guaranteed
+    the ordering of these items, since our internal data structure is a hash
+    table. This shouldn't be a problem.
+
+    \param rss     The widget to be acted on
+    \param shell   The menu to install the items in
+    \param pos     The position in the menu to install items
+
+    \return the number of items installed
+ */
+gint pcb_gtk_route_style_install_items(pcb_gtk_route_style_t * rss, GtkMenuShell * shell, gint pos);
+
+/** Adds a PCB route style to a \ref pcb_gtk_route_style_t object.
+    Note that the route style object passed to this function will be
+    updated directly. (TODO: AV: Check and complete)
+
+    \param rss     The widget to be acted on
+    \param data    PCB's route style object describing the style
+    \param hide    if TRUE ... (TODO: explain)
+ */
+pcb_gtk_obj_route_style_t *pcb_gtk_route_style_add_route_style(pcb_gtk_route_style_t * rss, pcb_route_style_t * data, int hide);
+
+/** Selects a route style and emits a select-style signal.
+    \param rss  The widget to be acted on
+    \param rst  The style to select
+
+    \return TRUE if a style was selected, FALSE otherwise
+ */
+gboolean pcb_gtk_route_style_select_style(pcb_gtk_route_style_t * rss, pcb_route_style_t * rst);
+
+/** Returns the GtkAccelGroup of a route style selector widget.
+    \param rss            The widget to be acted on
+ */
+GtkAccelGroup *pcb_gtk_route_style_get_accel_group(pcb_gtk_route_style_t * rss);
+
+/** Sets a \ref pcb_gtk_route_style_t selection to given values.
+    Given the line thickness, via size and clearance values of a route
+    style, this function selects a route style with the given values.
+    If there is no such style registered with the selector, nothing
+    will happen. This function does not emit any signals.
+
+    \param rss        The widget to be acted on
+    \param Thick      \ref pcb_coord_t  to match selection to
+    \param Hole       \ref pcb_coord_t  to match selection to
+    \param Diameter   \ref pcb_coord_t  to match selection to
+    \param Clearance  \ref pcb_coord_t  to match selection to
+ */
+void pcb_gtk_route_style_sync(pcb_gtk_route_style_t * rss, pcb_coord_t Thick, pcb_coord_t Hole, pcb_coord_t Diameter,
+															pcb_coord_t Clearance);
+
+/** What represents idx ? */
+void pcb_gtk_route_style_copy(int idx);
+
+/** Removes all styles from a route style widget. */
+void pcb_gtk_route_style_empty(pcb_gtk_route_style_t * rss);
+
+/*TODO: rename this function */
+/**  Configures the route style selector. */
+void make_route_style_buttons(pcb_gtk_route_style_t * rss);
+
+
+/* Temporary: call back to hid_gtk */
+extern void route_styles_edited_cb(pcb_gtk_route_style_t * rss, gboolean save, gpointer data);
+
+
+G_END_DECLS											/* keep c++ happy */
+#endif
diff --git a/src_plugins/plugins_feature.tmpasm b/src_plugins/plugins_feature.tmpasm
index 5ab1f89..6082ed8 100644
--- a/src_plugins/plugins_feature.tmpasm
+++ b/src_plugins/plugins_feature.tmpasm
@@ -2,6 +2,7 @@
 
 include {../src_plugins/lib_gensexpr/Plug.tmpasm}
 include {../src_plugins/lib_legacy_func/Plug.tmpasm}
+include {../src_plugins/lib_gtk_common/Plug.tmpasm}
 
 include {../src_plugins/autocrop/Plug.tmpasm}
 include {../src_plugins/autoplace/Plug.tmpasm}
@@ -10,6 +11,7 @@ include {../src_plugins/boardflip/Plug.tmpasm}
 include {../src_plugins/distalign/Plug.tmpasm}
 include {../src_plugins/distaligntext/Plug.tmpasm}
 include {../src_plugins/draw_fab/Plug.tmpasm}
+include {../src_plugins/draw_csect/Plug.tmpasm}
 include {../src_plugins/jostle/Plug.tmpasm}
 include {../src_plugins/polycombine/Plug.tmpasm}
 include {../src_plugins/polystitch/Plug.tmpasm}
@@ -20,7 +22,6 @@ include {../src_plugins/puller/Plug.tmpasm}
 include {../src_plugins/djopt/Plug.tmpasm}
 include {../src_plugins/mincut/Plug.tmpasm}
 include {../src_plugins/gpmi/Plug.tmpasm}
-include {../src_plugins/toporouter/Plug.tmpasm}
 include {../src_plugins/oldactions/Plug.tmpasm}
 include {../src_plugins/fontmode/Plug.tmpasm}
 include {../src_plugins/shand_cmd/Plug.tmpasm}
diff --git a/src_plugins/plugins_io.tmpasm b/src_plugins/plugins_io.tmpasm
index f5a71b5..b97a32b 100644
--- a/src_plugins/plugins_io.tmpasm
+++ b/src_plugins/plugins_io.tmpasm
@@ -5,6 +5,9 @@ include {../src_plugins/import_netlist/Plug.tmpasm}
 include {../src_plugins/import_sch/Plug.tmpasm}
 include {../src_plugins/import_dsn/Plug.tmpasm}
 include {../src_plugins/import_hyp/Plug.tmpasm}
+include {../src_plugins/import_mucs/Plug.tmpasm}
+include {../src_plugins/import_ltspice/Plug.tmpasm}
+include {../src_plugins/import_tinycad/Plug.tmpasm}
 
 include {../src_plugins/export_ps/Plug.tmpasm}
 include {../src_plugins/export_lpr/Plug.tmpasm}
@@ -22,6 +25,7 @@ include {../src_plugins/export_dsn/Plug.tmpasm}
 include {../src_plugins/export_ipcd356/Plug.tmpasm}
 include {../src_plugins/export_svg/Plug.tmpasm}
 include {../src_plugins/export_stat/Plug.tmpasm}
+include {../src_plugins/export_fidocadj/Plug.tmpasm}
 
 include {../src_plugins/hid_batch/Plug.tmpasm}
 include {../src_plugins/hid_gtk/Plug.tmpasm}
diff --git a/src_plugins/puller/puller.c b/src_plugins/puller/puller.c
index bd64ccf..aa5df04 100644
--- a/src_plugins/puller/puller.c
+++ b/src_plugins/puller/puller.c
@@ -2268,6 +2268,7 @@ static void trace_print_lines_arcs(void)
 static int pcb_act_GlobalPuller(int argc, const char **argv, pcb_coord_t x, pcb_coord_t y)
 {
 	int select_flags = 0;
+	unsigned int cflg;
 
 	setbuf(stdout, 0);
 	nloops = 0;
@@ -2283,10 +2284,9 @@ static int pcb_act_GlobalPuller(int argc, const char **argv, pcb_coord_t x, pcb_
 	/* This canonicalizes all the lines, and cleans up near-misses.  */
 	/* pcb_hid_actionl("djopt", "puller", 0); */
 
-	current_is_solder = (pcb_layer_get_group_(CURRENT)
-											 == pcb_layer_get_group(pcb_solder_silk_layer));
-	current_is_component = (pcb_layer_get_group_(CURRENT)
-													== pcb_layer_get_group(pcb_component_silk_layer));
+	cflg = pcb_layergrp_flags(pcb_layer_get_group_(CURRENT));
+	current_is_solder = (cflg & PCB_LYT_BOTTOM);
+	current_is_component = (cflg & PCB_LYT_TOP);
 
 	lines = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify) FreeExtra);
 	arcs = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify) FreeExtra);
@@ -2381,10 +2381,10 @@ static int pcb_act_GlobalPuller(int argc, const char **argv, pcb_coord_t x, pcb_
 /*****************************************************************************/
 
 pcb_hid_action_t puller_action_list[] = {
-	{"pcb_act_Puller", "Click on a line-arc intersection or line segment", pcb_act_Puller,
+	{"Puller", "Click on a line-arc intersection or line segment", pcb_act_Puller,
 	 pcb_acth_Puller, pcb_acts_Puller}
 	,
-	{"pcb_act_GlobalPuller", 0, pcb_act_GlobalPuller,
+	{"GlobalPuller", 0, pcb_act_GlobalPuller,
 	 pcb_acth_GlobalPuller, pcb_acts_GlobalPuller}
 };
 
diff --git a/src_plugins/query/query_access.c b/src_plugins/query/query_access.c
index ade9231..8a1f56d 100644
--- a/src_plugins/query/query_access.c
+++ b/src_plugins/query/query_access.c
@@ -262,7 +262,7 @@ static int field_layer_from_ptr(pcb_layer_t *l, pcb_qry_node_t *fld, pcb_qry_val
 /* process from .layer */
 static int layer_of_obj(pcb_qry_node_t *fld, pcb_qry_val_t *res, pcb_layer_type_t mask)
 {
-	int id;
+	pcb_layer_id_t id;
 	const char *s1;
 
 	if (pcb_layer_list(mask, &id, 1) != 1)
diff --git a/src_plugins/rubberband_orig/rubberband.c b/src_plugins/rubberband_orig/rubberband.c
index 3e417ad..dfe9269 100644
--- a/src_plugins/rubberband_orig/rubberband.c
+++ b/src_plugins/rubberband_orig/rubberband.c
@@ -47,6 +47,7 @@
 #include "obj_line_draw.h"
 #include "plugins.h"
 #include "conf_core.h"
+#include "layer_grp.h"
 
 #include "polygon.h"
 
@@ -80,6 +81,7 @@ static void CheckPadForRubberbandConnection(rubber_ctx_t *rbnd, pcb_pad_t *);
 static void CheckPinForRubberbandConnection(rubber_ctx_t *rbnd, pcb_pin_t *);
 static void CheckLinePointForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_t *, pcb_line_t *, pcb_point_t *, pcb_bool);
 static void CheckArcPointForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_t *, pcb_arc_t *, int *, pcb_bool);
+static void CheckArcForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_t *, pcb_arc_t *, pcb_bool);
 static void CheckPolygonForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_t *, pcb_polygon_t *);
 static void CheckLinePointForRat(rubber_ctx_t *rbnd, pcb_layer_t *, pcb_point_t *);
 static pcb_r_dir_t rubber_callback(const pcb_box_t *b, void *cl);
@@ -96,11 +98,21 @@ static pcb_r_dir_t rubber_callback(const pcb_box_t * b, void *cl)
 	double x, y, rad, dist1, dist2;
 	pcb_coord_t t;
 	int n, touches = 0;
+	int have_point1 = 0;
+	int have_point2 = 0;
 
 	t = line->Thickness / 2;
 
+	/* Don't add the line if both ends of it are already in the list. */
 	for(n = 0; n < rbnd->RubberbandN; n++)
-		if (rbnd->Rubberband[n].Line == line)
+		if (rbnd->Rubberband[n].Line == line) {
+			if(rbnd->Rubberband[n].MovedPoint == &line->Point1)
+				have_point1 = 1;
+			if(rbnd->Rubberband[n].MovedPoint == &line->Point2)
+				have_point2 = 1;
+		}
+
+	if(have_point1 && have_point2)
 			return PCB_R_DIR_NOT_FOUND;
 
 	if (PCB_FLAG_TEST(PCB_FLAG_LOCK, line))
@@ -117,7 +129,8 @@ static pcb_r_dir_t rubber_callback(const pcb_box_t * b, void *cl)
 	if (i->radius == 0) {
 		int found = 0;
 
-		if (line->Point1.X + t >= i->box.X1 && line->Point1.X - t <= i->box.X2
+		if (!have_point1
+				&& line->Point1.X + t >= i->box.X1 && line->Point1.X - t <= i->box.X2
 				&& line->Point1.Y + t >= i->box.Y1 && line->Point1.Y - t <= i->box.Y2) {
 			if (((i->box.X1 <= line->Point1.X) &&
 					 (line->Point1.X <= i->box.X2)) || ((i->box.Y1 <= line->Point1.Y) && (line->Point1.Y <= i->box.Y2))) {
@@ -150,7 +163,8 @@ static pcb_r_dir_t rubber_callback(const pcb_box_t * b, void *cl)
 				found++;
 			}
 		}
-		if (line->Point2.X + t >= i->box.X1 && line->Point2.X - t <= i->box.X2
+		if (!have_point2
+				&& line->Point2.X + t >= i->box.X1 && line->Point2.X - t <= i->box.X2
 				&& line->Point2.Y + t >= i->box.Y1 && line->Point2.Y - t <= i->box.Y2) {
 			if (((i->box.X1 <= line->Point2.X) &&
 					 (line->Point2.X <= i->box.X2)) || ((i->box.Y1 <= line->Point2.Y) && (line->Point2.Y <= i->box.Y2))) {
@@ -195,14 +209,14 @@ static pcb_r_dir_t rubber_callback(const pcb_box_t * b, void *cl)
 		return PCB_R_DIR_NOT_FOUND;
 
 #ifdef CLOSEST_ONLY							/* keep this to remind me */
-	if (dist1 < dist2)
+	if ((dist1 < dist2) && !have_point1)
 		pcb_rubber_band_create(rbnd, i->layer, line, &line->Point1);
-	else
+	else if(!have_point2)
 		pcb_rubber_band_create(rbnd, i->layer, line, &line->Point2);
 #else
-	if (dist1 <= 0)
+	if ((dist1 <= 0) && !have_point1)
 		pcb_rubber_band_create(rbnd, i->layer, line, &line->Point1);
-	if (dist2 <= 0)
+	if ((dist2 <= 0) && !have_point2)
 		pcb_rubber_band_create(rbnd, i->layer, line, &line->Point2);
 #endif
 	return PCB_R_DIR_FOUND_CONTINUE;
@@ -216,8 +230,9 @@ static pcb_r_dir_t rubber_callback(const pcb_box_t * b, void *cl)
 static void CheckPadForRubberbandConnection(rubber_ctx_t *rbnd, pcb_pad_t *Pad)
 {
 	pcb_coord_t half = Pad->Thickness / 2;
-	pcb_layergrp_id_t i, group;
+	pcb_layergrp_id_t group;
 	struct rubber_info info;
+	unsigned int flg;
 
 	info.box.X1 = MIN(Pad->Point1.X, Pad->Point2.X) - half;
 	info.box.Y1 = MIN(Pad->Point1.Y, Pad->Point2.Y) - half;
@@ -226,11 +241,12 @@ static void CheckPadForRubberbandConnection(rubber_ctx_t *rbnd, pcb_pad_t *Pad)
 	info.radius = 0;
 	info.line = NULL;
 	info.rbnd = rbnd;
-	i = PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, Pad) ? pcb_solder_silk_layer : pcb_component_silk_layer;
-	group = pcb_layer_get_group(i);
+	flg = PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, Pad) ? PCB_LYT_BOTTOM : PCB_LYT_TOP;
+	if (pcb_layer_group_list(flg | PCB_LYT_COPPER, &group, 1) < 1)
+		return;
 
 	/* check all visible layers in the same group */
-	GROUP_LOOP(PCB->Data, group);
+	PCB_COPPER_GROUP_LOOP(PCB->Data, group);
 	{
 		/* check all visible lines of the group member */
 		info.layer = layer;
@@ -296,10 +312,14 @@ static pcb_r_dir_t rat_callback(const pcb_box_t * box, void *cl)
 static void CheckPadForRat(rubber_ctx_t *rbnd, pcb_pad_t *Pad)
 {
 	struct rinfo info;
-	pcb_cardinal_t i;
+	unsigned int flg;
+	pcb_layergrp_id_t group;
+
+	flg = PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, Pad) ? PCB_LYT_BOTTOM : PCB_LYT_TOP;
+	if (pcb_layer_group_list(flg | PCB_LYT_COPPER, &group, 1) < 1)
+		return;
 
-	i = PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, Pad) ? pcb_solder_silk_layer : pcb_component_silk_layer;
-	info.group = pcb_layer_get_group(i);
+	info.group = group;
 	info.pad = Pad;
 	info.type = PCB_TYPE_PAD;
 	info.rbnd = rbnd;
@@ -357,9 +377,11 @@ static void CheckPinForRubberbandConnection(rubber_ctx_t *rbnd, pcb_pin_t *Pin)
 		info.Y = Pin->Y;
 	}
 
-	for (n = 0; n < pcb_max_copper_layer; n++) {
-		info.layer = LAYER_PTR(n);
-		pcb_r_search(info.layer->line_tree, &info.box, NULL, rubber_callback, &info, NULL);
+	for (n = 0; n < pcb_max_layer; n++) {
+		if (pcb_layer_flags(n) & PCB_LYT_COPPER) {
+			info.layer = LAYER_PTR(n);
+			pcb_r_search(info.layer->line_tree, &info.box, NULL, rubber_callback, &info, NULL);
+		}
 	}
 }
 
@@ -386,7 +408,7 @@ static void CheckLinePointForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_
 	info.Y = LinePoint->Y;
 
 	group = pcb_layer_get_group_(Layer);
-	GROUP_LOOP(PCB->Data, group);
+	PCB_COPPER_GROUP_LOOP(PCB->Data, group);
 	{
 		/* check all visible lines of the group member */
 		if (layer->On) {
@@ -422,7 +444,7 @@ static void CheckArcPointForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_t
 	info.Y = ey;
 
 	group = pcb_layer_get_group_(Layer);
-	GROUP_LOOP(PCB->Data, group);
+	PCB_COPPER_GROUP_LOOP(PCB->Data, group);
 	{
 		/* check all visible lines of the group member */
 		if (layer->On) {
@@ -434,6 +456,45 @@ static void CheckArcPointForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_t
 }
 
 /* ---------------------------------------------------------------------------
+ * checks all visible lines which belong to the same group as the passed arc.
+ * If one of the endpoints of the line is on either of the selected arcs ends,
+ * the scanned line is added to the 'rubberband' list.
+ */
+static void CheckArcForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_t *Layer, pcb_arc_t *Arc, pcb_bool Exact)
+{
+	pcb_layergrp_id_t group;
+	struct rubber_info info;
+	int which;
+	pcb_coord_t t = Arc->Thickness / 2, ex, ey;
+
+	for(which=0; which<=1; ++which) {
+		pcb_arc_get_end(Arc,which,&ex, &ey);
+
+		/* lookup layergroup and check all visible lines in this group */
+		info.radius = Exact ? -1 : MAX(Arc->Thickness / 2, 1);
+		info.box.X1 = ex - t;
+		info.box.X2 = ex + t;
+		info.box.Y1 = ey - t;
+		info.box.Y2 = ey + t;
+		info.line = NULL; /* used only to make sure the current object is not added - we are adding lines only and the current object is an arc */
+		info.rbnd = rbnd;
+		info.X = ex;
+		info.Y = ey;
+
+		group = pcb_layer_get_group_(Layer);
+		PCB_COPPER_GROUP_LOOP(PCB->Data, group);
+		{
+			/* check all visible lines of the group member */
+			if (layer->On) {
+				info.layer = layer;
+				pcb_r_search(layer->line_tree, &info.box, NULL, rubber_callback, &info, NULL);
+			}
+		}
+		PCB_END_LOOP;
+	}
+}
+
+/* ---------------------------------------------------------------------------
  * checks all visible lines which belong to the same group as the passed polygon.
  * If one of the endpoints of the line lays inside the passed polygon,
  * the scanned line is added to the 'rubberband' list
@@ -444,7 +505,7 @@ static void CheckPolygonForRubberbandConnection(rubber_ctx_t *rbnd, pcb_layer_t
 
 	/* lookup layergroup and check all visible lines in this group */
 	group = pcb_layer_get_group_(Layer);
-	GROUP_LOOP(PCB->Data, group);
+	PCB_COPPER_GROUP_LOOP(PCB->Data, group);
 	{
 		if (layer->On) {
 			pcb_coord_t thick;
@@ -509,7 +570,7 @@ static void pcb_rubber_band_lookup_lines(rubber_ctx_t *rbnd, int Type, void *Ptr
 		{
 			pcb_layer_t *layer = (pcb_layer_t *) Ptr1;
 			pcb_line_t *line = (pcb_line_t *) Ptr2;
-			if (pcb_layer_id(PCB->Data, layer) < pcb_max_copper_layer) {
+			if (pcb_layer_flags(pcb_layer_id(PCB->Data, layer)) & PCB_LYT_COPPER) {
 				CheckLinePointForRubberbandConnection(rbnd, layer, line, &line->Point1, pcb_false);
 				CheckLinePointForRubberbandConnection(rbnd, layer, line, &line->Point2, pcb_false);
 			}
@@ -517,21 +578,26 @@ static void pcb_rubber_band_lookup_lines(rubber_ctx_t *rbnd, int Type, void *Ptr
 		}
 
 	case PCB_TYPE_LINE_POINT:
-		if (pcb_layer_id(PCB->Data, (pcb_layer_t *) Ptr1) < pcb_max_copper_layer)
+		if (pcb_layer_flags(pcb_layer_id(PCB->Data, (pcb_layer_t *) Ptr1)) & PCB_LYT_COPPER)
 			CheckLinePointForRubberbandConnection(rbnd, (pcb_layer_t *) Ptr1, (pcb_line_t *) Ptr2, (pcb_point_t *) Ptr3, pcb_true);
 		break;
 
 	case PCB_TYPE_ARC_POINT:
-		if (pcb_layer_id(PCB->Data, (pcb_layer_t *) Ptr1) < pcb_max_copper_layer)
+		if (pcb_layer_flags(pcb_layer_id(PCB->Data, (pcb_layer_t *) Ptr1)) & PCB_LYT_COPPER)
 			CheckArcPointForRubberbandConnection(rbnd, (pcb_layer_t *) Ptr1, (pcb_arc_t *) Ptr2, (int *) Ptr3, pcb_true);
 		break;
 
+	case PCB_TYPE_ARC:
+		if (pcb_layer_flags(pcb_layer_id(PCB->Data, (pcb_layer_t *) Ptr1)) & PCB_LYT_COPPER)
+			CheckArcForRubberbandConnection(rbnd, (pcb_layer_t *) Ptr1, (pcb_arc_t *) Ptr2, pcb_true);
+		break;
+
 	case PCB_TYPE_VIA:
 		CheckPinForRubberbandConnection(rbnd, (pcb_pin_t *) Ptr1);
 		break;
 
 	case PCB_TYPE_POLYGON:
-		if (pcb_layer_id(PCB->Data, (pcb_layer_t *) Ptr1) < pcb_max_copper_layer)
+		if (pcb_layer_flags(pcb_layer_id(PCB->Data, (pcb_layer_t *) Ptr1)) & PCB_LYT_COPPER)
 			CheckPolygonForRubberbandConnection(rbnd, (pcb_layer_t *) Ptr1, (pcb_polygon_t *) Ptr2);
 		break;
 	}
@@ -680,26 +746,46 @@ static void rbe_draw(void *user_data, int argc, pcb_event_arg_t argv[])
 	i = rbnd->RubberbandN;
 	ptr = rbnd->Rubberband;
 	while (i) {
-		pcb_point_t *point1, *point2;
 
 		if (PCB_FLAG_TEST(PCB_FLAG_VIA, ptr->Line)) {
 			/* this is a rat going to a polygon.  do not draw for rubberband */ ;
 		}
-		else if (PCB_FLAG_TEST(PCB_FLAG_RUBBEREND, ptr->Line)) {
-			/* 'point1' is always the fix-point */
-			if (ptr->MovedPoint == &ptr->Line->Point1) {
-				point1 = &ptr->Line->Point2;
-				point2 = &ptr->Line->Point1;
+		else {
+			pcb_coord_t x1=0,y1=0,x2=0,y2=0;
+
+			if (PCB_FLAG_TEST(PCB_FLAG_RUBBEREND, ptr->Line)) {
+				/* 'point1' is always the fix-point */
+				if (ptr->MovedPoint == &ptr->Line->Point1) {
+					x1 = ptr->Line->Point2.X;
+					y1 = ptr->Line->Point2.Y;
+					x2 = ptr->Line->Point1.X + dx;
+					y2 = ptr->Line->Point1.Y + dy;
+				}
+				else {
+					x1 = ptr->Line->Point1.X;
+					y1 = ptr->Line->Point1.Y;
+					x2 = ptr->Line->Point2.X + dx;
+					y2 = ptr->Line->Point2.Y + dy;
+				}
 			}
-			else {
-				point1 = &ptr->Line->Point1;
-				point2 = &ptr->Line->Point2;
+			else if (ptr->MovedPoint == &ptr->Line->Point1)	{
+					x1 = ptr->Line->Point1.X + dx;
+					y1 = ptr->Line->Point1.Y + dy;
+					x2 = ptr->Line->Point2.X + dx;
+					y2 = ptr->Line->Point2.Y + dy;
 			}
-			XORDrawAttachedLine(point1->X, point1->Y, point2->X + dx, point2->Y + dy, ptr->Line->Thickness);
+
+			if ((x1 != x2) || (y1 != y2)) {
+				XORDrawAttachedLine(x1,y1,x2,y2, ptr->Line->Thickness);
+
+				/* Draw the DRC outline if it is enabled */
+				if (conf_core.editor.show_drc) {
+					pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.cross);
+ 					XORDrawAttachedLine(x1,y1,x2,y2,ptr->Line->Thickness + 2 * (PCB->Bloat + 1) );
+        	pcb_gui->set_color(pcb_crosshair.GC, conf_core.appearance.color.crosshair);
+				}
+      }
 		}
-		else if (ptr->MovedPoint == &ptr->Line->Point1)
-			XORDrawAttachedLine(ptr->Line->Point1.X + dx,
-													ptr->Line->Point1.Y + dy, ptr->Line->Point2.X + dx, ptr->Line->Point2.Y + dy, ptr->Line->Thickness);
 
 		ptr++;
 		i--;
diff --git a/src_plugins/teardrops/teardrops.c b/src_plugins/teardrops/teardrops.c
index 2cdcccd..4685586 100644
--- a/src_plugins/teardrops/teardrops.c
+++ b/src_plugins/teardrops/teardrops.c
@@ -214,8 +214,10 @@ static void check_pin(pcb_pin_t * _pin)
 					PCB_COORD_TO_MM(pin->X), PCB_COORD_TO_MM(pin->Y),
 					PCB_EMPTY(PCB_ELEM_NAME_REFDES(element)), PCB_EMPTY(PCB_ELEM_NAME_VALUE(element)), PCB_EMPTY(PCB_ELEM_NAME_DESCRIPTION(element)));
 
-	for (layer = 0; layer < pcb_max_copper_layer; layer++) {
+	for (layer = 0; layer < pcb_max_layer; layer++) {
 		pcb_layer_t *l = &(PCB->Data->Layer[layer]);
+		if (!(pcb_layer_flags(layer) & PCB_LYT_COPPER))
+			continue;
 		pcb_r_search(l->line_tree, &spot, NULL, check_line_callback, l, NULL);
 	}
 }
@@ -236,8 +238,10 @@ static void check_via(pcb_pin_t * _pin)
 
 	fprintf(stderr, "Via at %.6f, %.6f\n", PCB_COORD_TO_MM(pin->X), PCB_COORD_TO_MM(pin->Y));
 
-	for (layer = 0; layer < pcb_max_copper_layer; layer++) {
+	for (layer = 0; layer < pcb_max_layer; layer++) {
 		pcb_layer_t *l = &(PCB->Data->Layer[layer]);
+		if (!(pcb_layer_flags(layer) & PCB_LYT_COPPER))
+			continue;
 		pcb_r_search(l->line_tree, &spot, NULL, check_line_callback, l, NULL);
 	}
 }
@@ -272,8 +276,10 @@ static void check_pad(pcb_pad_t * _pad)
 	/*           PCB_EMPTY(PCB_ELEM_NAME_VALUE(element)), */
 	/*           PCB_EMPTY(PCB_ELEM_NAME_DESCRIPTION(element))); */
 
-	for (layer = 0; layer < pcb_max_copper_layer; layer++) {
+	for (layer = 0; layer < pcb_max_layer; layer++) {
 		pcb_layer_t *l = &(PCB->Data->Layer[layer]);
+		if (!(pcb_layer_flags(layer) & PCB_LYT_COPPER))
+			continue;
 		pcb_r_search(l->line_tree, &(pad->BoundingBox), NULL, check_line_callback, l, NULL);
 	}
 }
diff --git a/src_plugins/toporouter/Makefile b/src_plugins/toporouter/Makefile
deleted file mode 100644
index aee1245..0000000
--- a/src_plugins/toporouter/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-all:
-	cd ../../src && $(MAKE) mod_toporouter
-
-clean:
-	rm *.o *.so 2>/dev/null ; true
-
diff --git a/src_plugins/toporouter/Plug.tmpasm b/src_plugins/toporouter/Plug.tmpasm
deleted file mode 100644
index dec04f9..0000000
--- a/src_plugins/toporouter/Plug.tmpasm
+++ /dev/null
@@ -1,28 +0,0 @@
-put /local/pcb/mod {toporouter}
-put /local/pcb/mod/OBJS [@ $(PLUGDIR)/toporouter/toporouter.o @]
-
-
-put /local/pcb/toporouter_rules [@
-../src_3rd/gts/libgts.a:
-	cd ../src_3rd/gts && make
-@]
-
-switch /local/pcb/toporouter/controls
-	case {buildin}
-		append /local/pcb/CFLAGS          {-I../src_3rd/gts}
-		append /local/pcb/RULES           /local/pcb/toporouter_rules
-		append /local/pcb/LIBS            { ../src_3rd/gts/libgts.a }
-		append /local/pcb/EXEDEPS         { ../src_3rd/gts/libgts.a }
-		include /local/pcb/tmpasm/buildin
-		end;
-	case {plugin}
-		append /local/mod/CFLAGS          {-I../src_3rd/gts}
-		append /local/pcb/RULES           /local/pcb/toporouter_rules
-		append /local/pcb/toporouter/OBJS { ../src_3rd/gts/libgts.a }
-		include /local/pcb/tmpasm/plugin
-		end
-	case {disable}
-		put /local/pcb/mod/OBJS {}
-		include /local/pcb/tmpasm/disable
-		end
-end
diff --git a/src_plugins/toporouter/README b/src_plugins/toporouter/README
deleted file mode 100644
index 15ffcce..0000000
--- a/src_plugins/toporouter/README
+++ /dev/null
@@ -1,7 +0,0 @@
-Automatically route selected or all rats using a topological algorithm. This
-is the new autorouter from 2009.
-
-#state: fails
-#lstate: infinite loop in gts
-#default: disabled
-#implements: (feature)
diff --git a/src_plugins/toporouter/toporouter.c b/src_plugins/toporouter/toporouter.c
deleted file mode 100644
index 60f4e88..0000000
--- a/src_plugins/toporouter/toporouter.c
+++ /dev/null
@@ -1,8244 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  Topological Autorouter for 
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 2009 Anthony Blake
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Contact addresses for email:
- *  Anthony Blake, tonyb33 at gmail.com
- *
- *
- *
- *                 This is *EXPERIMENTAL* code.
- *
- *  As the code is experimental, the algorithms and code
- *  are likely to change. Which means it isn't documented  
- *  or optimized. If you would like to learn about Topological
- *  Autorouters, the following papers are good starting points: 
- *
- * This file implements a topological autorouter, and uses techniques from the
- * following publications:
- *
- * Dayan, T. and Dai, W.W.M., "Layer Assignment for a Rubber Band Router" Tech
- * Report UCSC-CRL-92-50, Univ. of California, Santa Cruz, 1992.
- *
- * Dai, W.W.M and Dayan, T. and Staepelaere, D., "Topological Routing in SURF:
- * Generating a Rubber-Band Sketch" Proc. 28th ACM/IEEE Design Automation
- * Conference, 1991, pp. 39-44.
- *
- * David Staepelaere, Jeffrey Jue, Tal Dayan, Wayne Wei-Ming Dai, "SURF:
- * Rubber-Band Routing System for Multichip Modules," IEEE Design and Test of
- * Computers ,vol. 10, no. 4,  pp. 18-26, October/December, 1993.
- *
- * Dayan, T., "Rubber-band based topological router" PhD Thesis, Univ. of
- * California, Santa Cruz, 1997.
- *
- * David Staepelaere, "Geometric transformations for a rubber-band sketch"
- * Master's thesis, Univ. of California, Santa Cruz, September 1992.
- *
- */
-
-#include "config.h"
-#include "toporouter.h"
-#include "pcb-printf.h"
-#include "compat_nls.h"
-
-static void toporouter_edge_init(toporouter_edge_t * edge)
-{
-	edge->routing = NULL;
-	edge->flags = 0;
-}
-
-toporouter_edge_class_t *toporouter_edge_class(void)
-{
-	static toporouter_edge_class_t *klass = NULL;
-
-	if (klass == NULL) {
-		GtsObjectClassInfo constraint_info = {
-			"toporouter_edge_t",
-			sizeof(toporouter_edge_t),
-			sizeof(toporouter_edge_class_t),
-			(GtsObjectClassInitFunc) NULL,
-			(GtsObjectInitFunc) toporouter_edge_init,
-			(GtsArgSetFunc) NULL,
-			(GtsArgGetFunc) NULL
-		};
-		klass = (toporouter_edge_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_edge_class()), &constraint_info);
-	}
-
-	return klass;
-}
-
-static void toporouter_bbox_init(toporouter_bbox_t * box)
-{
-	box->data = NULL;
-	box->type = OTHER;
-	box->constraints = NULL;
-	box->cluster = NULL;
-}
-
-toporouter_bbox_class_t *toporouter_bbox_class(void)
-{
-	static toporouter_bbox_class_t *klass = NULL;
-
-	if (klass == NULL) {
-		GtsObjectClassInfo constraint_info = {
-			"toporouter_bbox_t",
-			sizeof(toporouter_bbox_t),
-			sizeof(toporouter_bbox_class_t),
-			(GtsObjectClassInitFunc) NULL,
-			(GtsObjectInitFunc) toporouter_bbox_init,
-			(GtsArgSetFunc) NULL,
-			(GtsArgGetFunc) NULL
-		};
-		klass = (toporouter_bbox_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_bbox_class()), &constraint_info);
-	}
-
-	return klass;
-}
-
-static void toporouter_vertex_class_init(toporouter_vertex_class_t * klass)
-{
-
-}
-
-static void toporouter_vertex_init(toporouter_vertex_t * vertex)
-{
-	vertex->bbox = NULL;
-	vertex->parent = NULL;
-	vertex->child = NULL;
-	vertex->flags = 0;
-	vertex->routingedge = NULL;
-	vertex->arc = NULL;
-	vertex->oproute = NULL;
-	vertex->route = NULL;
-
-	vertex->gcost = 0.;
-	vertex->hcost = 0.;
-	vertex->gn = 0;
-}
-
-toporouter_vertex_class_t *toporouter_vertex_class(void)
-{
-	static toporouter_vertex_class_t *klass = NULL;
-
-	if (klass == NULL) {
-		GtsObjectClassInfo constraint_info = {
-			"toporouter_vertex_t",
-			sizeof(toporouter_vertex_t),
-			sizeof(toporouter_vertex_class_t),
-			(GtsObjectClassInitFunc) toporouter_vertex_class_init,
-			(GtsObjectInitFunc) toporouter_vertex_init,
-			(GtsArgSetFunc) NULL,
-			(GtsArgGetFunc) NULL
-		};
-		klass = (toporouter_vertex_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_vertex_class()), &constraint_info);
-	}
-
-	return klass;
-}
-
-static void toporouter_constraint_class_init(toporouter_constraint_class_t * klass)
-{
-
-}
-
-static void toporouter_constraint_init(toporouter_constraint_t * constraint)
-{
-	constraint->box = NULL;
-	constraint->routing = NULL;
-}
-
-toporouter_constraint_class_t *toporouter_constraint_class(void)
-{
-	static toporouter_constraint_class_t *klass = NULL;
-
-	if (klass == NULL) {
-		GtsObjectClassInfo constraint_info = {
-			"toporouter_constraint_t",
-			sizeof(toporouter_constraint_t),
-			sizeof(toporouter_constraint_class_t),
-			(GtsObjectClassInitFunc) toporouter_constraint_class_init,
-			(GtsObjectInitFunc) toporouter_constraint_init,
-			(GtsArgSetFunc) NULL,
-			(GtsArgGetFunc) NULL
-		};
-		klass = (toporouter_constraint_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_constraint_class()), &constraint_info);
-	}
-
-	return klass;
-}
-
-static void toporouter_arc_init(toporouter_arc_t * arc)
-{
-	arc->x0 = -1.;
-	arc->y0 = -1.;
-	arc->x1 = -1.;
-	arc->y1 = -1.;
-	arc->centre = NULL;
-	arc->v = NULL;
-	arc->v1 = NULL;
-	arc->v2 = NULL;
-	arc->r = -1.;
-	arc->dir = 31337;
-	arc->clearance = NULL;
-	arc->oproute = NULL;
-}
-
-toporouter_arc_class_t *toporouter_arc_class(void)
-{
-	static toporouter_arc_class_t *klass = NULL;
-
-	if (klass == NULL) {
-		GtsObjectClassInfo constraint_info = {
-			"toporouter_arc_t",
-			sizeof(toporouter_arc_t),
-			sizeof(toporouter_arc_class_t),
-			(GtsObjectClassInitFunc) NULL,
-			(GtsObjectInitFunc) toporouter_arc_init,
-			(GtsArgSetFunc) NULL,
-			(GtsArgGetFunc) NULL
-		};
-		klass = (toporouter_arc_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_constraint_class()), &constraint_info);
-	}
-
-	return klass;
-}
-
-#define MARGIN 10.0f
-
-drawing_context_t *toporouter_output_init(int w, int h, char *filename)
-{
-	drawing_context_t *dc;
-
-	dc = (drawing_context_t *) malloc(sizeof(drawing_context_t));
-
-	dc->iw = w;
-	dc->ih = h;
-	dc->filename = filename;
-
-	/* Calculate scaling to maintain aspect ratio */
-	if (PCB->MaxWidth > PCB->MaxHeight) {
-		/* Scale board width to match image width minus 2xMARGIN */
-		dc->s = ((double) dc->iw - (2 * MARGIN)) / (double) PCB->MaxWidth;
-		dc->ih = (double) PCB->MaxHeight * dc->s + (2 * MARGIN);
-	}
-	else {
-		/* Scale board height to match image height minus 2xMARGIN */
-		dc->s = ((double) dc->ih - (2 * MARGIN)) / (double) PCB->MaxHeight;
-		dc->iw = (double) PCB->MaxWidth * dc->s + (2 * MARGIN);
-	}
-
-#if TOPO_OUTPUT_ENABLED
-	dc->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dc->iw, dc->ih);
-	dc->cr = cairo_create(dc->surface);
-
-	cairo_rectangle(dc->cr, 0, 0, dc->iw, dc->ih);
-	cairo_set_source_rgb(dc->cr, 0, 0, 0);
-	cairo_fill(dc->cr);
-
-#endif
-
-	return dc;
-}
-
-void toporouter_output_close(drawing_context_t * dc)
-{
-#if TOPO_OUTPUT_ENABLED
-	cairo_surface_write_to_png(dc->surface, dc->filename);
-	cairo_destroy(dc->cr);
-	cairo_surface_destroy(dc->surface);
-#endif
-}
-
-gdouble lookup_clearance(char *name)
-{
-	if (name) {
-		int idx = pcb_route_style_lookup(&PCB->RouteStyle, 0, 0, 0, 0, menu->Style);
-		if (idx >= 0)
-			return PCB->RouteStyle.array[idx].Clearance;
-	}
-	return Settings.Clearance;
-}
-
-gdouble lookup_thickness(char *name)
-{
-	if (name) {
-		int idx = pcb_route_style_lookup(&PCB->RouteStyle, 0, 0, 0, 0, menu->Style);
-		if (idx >= 0)
-			return PCB->RouteStyle.array[idx].Thick;
-	}
-	return Settings.LineThickness;
-}
-
-static inline gdouble cluster_clearance(toporouter_cluster_t * cluster)
-{
-	if (cluster)
-		return lookup_clearance(cluster->netlist->style);
-	return lookup_clearance(NULL);
-}
-
-static inline gdouble cluster_thickness(toporouter_cluster_t * cluster)
-{
-	if (cluster)
-		return lookup_thickness(cluster->netlist->style);
-	return lookup_thickness(NULL);
-}
-
-gint toporouter_draw_vertex(gpointer item, gpointer data)
-{
-#if TOPO_OUTPUT_ENABLED
-	drawing_context_t *dc = (drawing_context_t *) data;
-	toporouter_vertex_t *tv;
-	pcb_pin_t *pin;
-	pcb_pad_t *pad;
-	gdouble blue;
-
-	if (TOPOROUTER_IS_VERTEX((GtsObject *) item)) {
-		tv = TOPOROUTER_VERTEX((GtsObject *) item);
-
-		if (tv->flags & VERTEX_FLAG_RED) {
-			cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f);
-			cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-			cairo_fill(dc->cr);
-
-		}
-		else if (tv->flags & VERTEX_FLAG_GREEN) {
-			cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f);
-			cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-			cairo_fill(dc->cr);
-
-		}
-		else if (tv->flags & VERTEX_FLAG_BLUE) {
-			cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f);
-			cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-			cairo_fill(dc->cr);
-
-
-		}
-		/* printf("tv->type = %d\n", tv->type); */
-		if (!dc->mode) {
-			if (tv->bbox) {
-				pin = (pcb_pin_t *) tv->bbox->data;
-				pad = (pcb_pad_t *) tv->bbox->data;
-
-				blue = 0.0f;
-				switch (tv->bbox->type) {
-				case PIN:
-					cairo_set_source_rgba(dc->cr, 1.0f, 0., 0.0f, 0.2f);
-					cairo_arc(dc->cr,
-										tv->v.p.x * dc->s + MARGIN,
-										tv->v.p.y * dc->s + MARGIN,
-										(((gdouble) pin->Thickness / 2.0f) + (gdouble) lookup_clearance(pin->Name)) * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-					cairo_set_source_rgba(dc->cr, 1.0f, 0., 0., 0.4f);
-					cairo_arc(dc->cr,
-										tv->v.p.x * dc->s + MARGIN,
-										tv->v.p.y * dc->s + MARGIN, (gdouble) (pin->Thickness) / 2.0f * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-					break;
-				case VIA:
-					cairo_set_source_rgba(dc->cr, 0.0f, 0., 1., 0.2f);
-					cairo_arc(dc->cr,
-										tv->v.p.x * dc->s + MARGIN,
-										tv->v.p.y * dc->s + MARGIN,
-										(((gdouble) pin->Thickness / 2.0f) + (gdouble) lookup_clearance(pin->Name)) * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-					cairo_set_source_rgba(dc->cr, 0.0f, 0., 1., 0.4f);
-					cairo_arc(dc->cr,
-										tv->v.p.x * dc->s + MARGIN,
-										tv->v.p.y * dc->s + MARGIN, (gdouble) (pin->Thickness) / 2.0f * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-					break;
-				case PAD:
-					cairo_set_source_rgba(dc->cr, 0.0f, 1., 0., 0.5f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 400. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-					break;
-				default:
-					break;
-				}
-			}
-		}
-		else {
-			if (tv->flags & VERTEX_FLAG_BLUE) {
-				cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f);
-				cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-				cairo_fill(dc->cr);
-			}
-			else if (tv->flags & VERTEX_FLAG_RED) {
-				cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f);
-				cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-				cairo_fill(dc->cr);
-
-			}
-			else if (tv->flags & VERTEX_FLAG_GREEN) {
-				cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f);
-				cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-				cairo_fill(dc->cr);
-			}
-
-		}
-	}
-	else {
-		fprintf(stderr, "Unknown data passed to toporouter_draw_vertex, aborting foreach\n");
-		return -1;
-	}
-	return 0;
-#else
-	return -1;
-#endif
-}
-
-gint toporouter_draw_edge(gpointer item, gpointer data)
-{
-#if TOPO_OUTPUT_ENABLED
-	drawing_context_t *dc = (drawing_context_t *) data;
-	toporouter_edge_t *te;
-	toporouter_constraint_t *tc;
-
-	if (TOPOROUTER_IS_EDGE((GtsObject *) item)) {
-		te = TOPOROUTER_EDGE((GtsObject *) item);
-		cairo_set_source_rgba(dc->cr, 1.0f, 1.0f, 1.0f, 0.5f);
-		cairo_move_to(dc->cr, te->e.segment.v1->p.x * dc->s + MARGIN, te->e.segment.v1->p.y * dc->s + MARGIN);
-		cairo_line_to(dc->cr, te->e.segment.v2->p.x * dc->s + MARGIN, te->e.segment.v2->p.y * dc->s + MARGIN);
-		cairo_stroke(dc->cr);
-	}
-	else if (TOPOROUTER_IS_CONSTRAINT((GtsObject *) item)) {
-		tc = TOPOROUTER_CONSTRAINT((GtsObject *) item);
-		if (tc->box) {
-			switch (tc->box->type) {
-			case BOARD:
-				cairo_set_source_rgba(dc->cr, 1.0f, 0.0f, 1.0f, 0.9f);
-				cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN);
-				cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN);
-				cairo_stroke(dc->cr);
-				break;
-			case PIN:
-			case PAD:
-				cairo_set_source_rgba(dc->cr, 1.0f, 0.0f, 0.0f, 0.9f);
-				cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN);
-				cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN);
-				cairo_stroke(dc->cr);
-				break;
-			case LINE:
-				cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.9f);
-				cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN);
-				cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN);
-				cairo_stroke(dc->cr);
-				break;
-
-			default:
-				cairo_set_source_rgba(dc->cr, 1.0f, 1.0f, 0.0f, 0.9f);
-				cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN);
-				cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN);
-				cairo_stroke(dc->cr);
-				break;
-			}
-		}
-		else {
-			printf("CONSTRAINT without box\n");
-
-		}
-	}
-	else {
-		fprintf(stderr, "Unknown data passed to toporouter_draw_edge, aborting foreach\n");
-		return -1;
-	}
-
-	return 0;
-#else
-	return -1;
-#endif
-}
-
-
-/*#define vertex_bbox(v) (v->bbox)*/
-toporouter_bbox_t *vertex_bbox(toporouter_vertex_t * v)
-{
-	return v ? v->bbox : NULL;
-}
-
-
-char *vertex_netlist(toporouter_vertex_t * v)
-{
-	toporouter_bbox_t *box = vertex_bbox(v);
-
-	if (box && box->cluster)
-		return box->cluster->netlist->netlist;
-
-	return NULL;
-}
-
-char *constraint_netlist(toporouter_constraint_t * c)
-{
-	toporouter_bbox_t *box = c->box;
-
-	if (box && box->cluster)
-		return box->cluster->netlist->netlist;
-
-	return NULL;
-}
-
-static inline guint epsilon_equals(gdouble a, gdouble b)
-{
-	if (a > b - EPSILON && a < b + EPSILON)
-		return 1;
-	return 0;
-}
-
-void print_bbox(toporouter_bbox_t * box)
-{
-	printf("[BBOX ");
-	switch (box->type) {
-	case PAD:
-		printf("PAD ");
-		break;
-	case PIN:
-		printf("PIN ");
-		break;
-	case VIA:
-		printf("VIA ");
-		break;
-	case LINE:
-		printf("LINE ");
-		break;
-	case BOARD:
-		printf("BOARD ");
-		break;
-	case POLYGON:
-		printf("POLYGON ");
-		break;
-	default:
-		printf("UNKNOWN ");
-		break;
-	}
-
-	if (box->point)
-		printf("P: %f,%f,%f ", vx(box->point), vy(box->point), vz(box->point));
-	else
-		printf("P: NONE ");
-
-	printf("LAYER: %d ", box->layer);
-	printf("CLUSTER: %d]\n", box->cluster ? box->cluster->c : -1);
-
-}
-
-void print_vertex(toporouter_vertex_t * v)
-{
-	if (v)
-		printf("[V %f,%f,%f ", vx(v), vy(v), vz(v));
-	else
-		printf("[V (null) ");
-
-	printf("%s ", vertex_netlist(v));
-	if (v->route && v->route->netlist)
-		printf("%s ", v->route->netlist->netlist);
-
-	if (v->routingedge) {
-		guint n = g_list_length(edge_routing(v->routingedge));
-		guint pos = g_list_index(edge_routing(v->routingedge), v);
-
-		if (TOPOROUTER_IS_CONSTRAINT(v->routingedge))
-			printf("[CONST ");
-		else
-			printf("[EDGE ");
-
-		printf("%d/%d] ", pos, n);
-
-	}
-
-
-	if (v->flags & VERTEX_FLAG_TEMP)
-		printf("TEMP ");
-	if (v->flags & VERTEX_FLAG_ROUTE)
-		printf("ROUTE ");
-	if (v->flags & VERTEX_FLAG_SPECCUT)
-		printf("SPECCUT ");
-	if (v->flags & VERTEX_FLAG_FAKE)
-		printf("FAKE ");
-
-	printf("]\n");
-
-}
-
-gdouble vertex_net_thickness(toporouter_vertex_t * v)
-{
-	toporouter_bbox_t *box = vertex_bbox(v);
-
-	if (!box) {
-
-		while (v && (v->flags & VERTEX_FLAG_TEMP || v->flags & VERTEX_FLAG_ROUTE)) {
-			v = v->parent;
-		}
-
-		box = vertex_bbox(v);
-
-	}
-	else {
-		if (box->type == PIN || box->type == VIA) {
-			pcb_pin_t *pin = (pcb_pin_t *) box->data;
-			if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pin) || PCB_FLAG_TEST(PCB_FLAG_OCTAGON, pin)) {
-				return 0.;
-			}
-/*      return ((pcb_pin_t *)box->data)->Thickness + 1.;*/
-			return ((pcb_pin_t *) box->data)->Thickness;
-		}
-		else if (box->type == PAD) {
-			pcb_pad_t *pad = (pcb_pad_t *) box->data;
-			if (pad->Point1.X == pad->Point2.X && pad->Point1.Y == pad->Point2.Y && !PCB_FLAG_TEST(PCB_FLAG_SQUARE, pad)) {
-				return pad->Thickness;
-			}
-			return 0.;
-		}
-		else if (box->type == BOARD) {
-			return 0.;
-		}
-		else if (box->type == LINE) {
-			pcb_line_t *line = (pcb_line_t *) box->data;
-			return line->Thickness;
-		}
-		else if (box->type == POLYGON) {
-			return 0.;
-		}
-
-		printf("Unrecognized type in thickness lookup..\n");
-	}
-
-/*  if(!box || !box->cluster) return Settings.LineThickness + 1.;*/
-	if (!box || !box->cluster)
-		return Settings.LineThickness;
-
-	return cluster_thickness(box->cluster);
-}
-
-gdouble vertex_net_clearance(toporouter_vertex_t * v)
-{
-	toporouter_bbox_t *box = vertex_bbox(v);
-	if (!box) {
-
-		while (v && (v->flags & VERTEX_FLAG_TEMP || v->flags & VERTEX_FLAG_ROUTE)) {
-			v = v->parent;
-		}
-		box = vertex_bbox(v);
-	}
-	else {
-		/*  if(box->type == PIN || box->type == VIA) 
-		   return ((pcb_pin_t *)box->data)->Clearance;
-		   else if(box->type == PAD)
-		   return ((pcb_pad_t *)box->data)->Clearance; */
-
-	}
-
-/*  if(!box || !box->cluster) return Settings.Clearance + 1.; */
-	if (!box || !box->cluster)
-		return Settings.Clearance;
-	return cluster_clearance(box->cluster);
-}
-
-/*
-void
-print_trace (void)
-{
-  void *array[10];
-  size_t size;
-  char **strings;
-  size_t i;
-
-  size = backtrace (array, 10);
-  strings = backtrace_symbols (array, size);
-
-  printf ("Obtained %zd stack frames.\n", size);
-
-  for (i = 0; i < size; i++)
-    printf ("%s\n", strings[i]);
-
-  free (strings);
-}
-*/
-/* fills in x and y with coordinates of point from a towards b of distance d */
-void point_from_point_to_point(toporouter_vertex_t * a, toporouter_vertex_t * b, gdouble d, gdouble * x, gdouble * y)
-{
-	gdouble dx = vx(b) - vx(a);
-	gdouble dy = vy(b) - vy(a);
-	gdouble theta = atan(fabs(dy / dx));
-
-/*#ifdef DEBUG_EXPORT  */
-	if (!finite(theta)) {
-/*    printf("!finte(theta): a = %f,%f b = %f,%f d = %f\n", vx(a), vy(a), vx(b), vy(b), d);
-      print_trace(); */
-		/*TODO: this shouldn't happen, fix the hack */
-		*x = vx(a);
-		*y = vy(a);
-		return;
-	}
-/*#endif*/
-
-	g_assert(finite(theta));
-
-	*x = vx(a);
-	*y = vy(a);
-
-	if (dx >= 0.) {
-
-		if (dy >= 0.) {
-			*x += d * cos(theta);
-			*y += d * sin(theta);
-		}
-		else {
-			*x += d * cos(theta);
-			*y -= d * sin(theta);
-		}
-
-	}
-	else {
-
-		if (dy >= 0.) {
-			*x -= d * cos(theta);
-			*y += d * sin(theta);
-		}
-		else {
-			*x -= d * cos(theta);
-			*y -= d * sin(theta);
-		}
-
-	}
-}
-
-
-static inline gint coord_wind(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy)
-{
-	gdouble rval, dx1, dx2, dy1, dy2;
-	dx1 = bx - ax;
-	dy1 = by - ay;
-	dx2 = cx - bx;
-	dy2 = cy - by;
-	rval = (dx1 * dy2) - (dy1 * dx2);
-	return (rval > EPSILON) ? 1 : ((rval < -EPSILON) ? -1 : 0);
-}
-
-/* wind_v:
- * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively.
- */
-int point_wind(GtsPoint * a, GtsPoint * b, GtsPoint * c)
-{
-	gdouble rval, dx1, dx2, dy1, dy2;
-	dx1 = b->x - a->x;
-	dy1 = b->y - a->y;
-	dx2 = c->x - b->x;
-	dy2 = c->y - b->y;
-	rval = (dx1 * dy2) - (dy1 * dx2);
-	return (rval > EPSILON) ? 1 : ((rval < -EPSILON) ? -1 : 0);
-}
-
-static inline int vertex_wind(GtsVertex * a, GtsVertex * b, GtsVertex * c)
-{
-	return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c));
-}
-
-static inline int tvertex_wind(toporouter_vertex_t * a, toporouter_vertex_t * b, toporouter_vertex_t * c)
-{
-	return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c));
-}
-
-int sloppy_point_wind(GtsPoint * a, GtsPoint * b, GtsPoint * c)
-{
-	gdouble rval, dx1, dx2, dy1, dy2;
-	dx1 = b->x - a->x;
-	dy1 = b->y - a->y;
-	dx2 = c->x - b->x;
-	dy2 = c->y - b->y;
-	rval = (dx1 * dy2) - (dy1 * dx2);
-	return (rval > 10.) ? 1 : ((rval < -10.) ? -1 : 0);
-}
-
-static inline int sloppy_vertex_wind(GtsVertex * a, GtsVertex * b, GtsVertex * c)
-{
-	return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c));
-}
-
-/* moves vertex v d units in the direction of vertex p */
-void coord_move_towards_coord_values(gdouble ax, gdouble ay, gdouble px, gdouble py, gdouble d, gdouble * x, gdouble * y)
-{
-	gdouble dx = px - ax;
-	gdouble dy = py - ay;
-	gdouble theta = atan(fabs(dy / dx));
-
-
-	if (!finite(theta)) {
-		printf("!finite(theta) a = %f,%f p = %f,%f d = %f\n", ax, ay, px, py, d);
-
-	}
-
-	g_assert(finite(theta));
-
-	if (dx >= 0.) {
-
-		if (dy >= 0.) {
-			*x = ax + (d * cos(theta));
-			*y = ay + (d * sin(theta));
-		}
-		else {
-			*x = ax + (d * cos(theta));
-			*y = ay - (d * sin(theta));
-		}
-
-	}
-	else {
-
-		if (dy >= 0.) {
-			*x = ax - (d * cos(theta));
-			*y = ay + (d * sin(theta));
-		}
-		else {
-			*x = ax - (d * cos(theta));
-			*y = ay - (d * sin(theta));
-		}
-
-	}
-
-}
-
-/* moves vertex v d units in the direction of vertex p */
-void vertex_move_towards_point_values(GtsVertex * v, gdouble px, gdouble py, gdouble d, gdouble * x, gdouble * y)
-{
-	gdouble dx = px - GTS_POINT(v)->x;
-	gdouble dy = py - GTS_POINT(v)->y;
-	gdouble theta = atan(fabs(dy / dx));
-
-	g_assert(finite(theta));
-
-	if (dx >= 0.) {
-
-		if (dy >= 0.) {
-			*x = GTS_POINT(v)->x + (d * cos(theta));
-			*y = GTS_POINT(v)->y + (d * sin(theta));
-		}
-		else {
-			*x = GTS_POINT(v)->x + (d * cos(theta));
-			*y = GTS_POINT(v)->y - (d * sin(theta));
-		}
-
-	}
-	else {
-
-		if (dy >= 0.) {
-			*x = GTS_POINT(v)->x - (d * cos(theta));
-			*y = GTS_POINT(v)->y + (d * sin(theta));
-		}
-		else {
-			*x = GTS_POINT(v)->x - (d * cos(theta));
-			*y = GTS_POINT(v)->y - (d * sin(theta));
-		}
-
-	}
-
-}
-
-/* moves vertex v d units in the direction of vertex p */
-void vertex_move_towards_vertex_values(GtsVertex * v, GtsVertex * p, gdouble d, gdouble * x, gdouble * y)
-{
-	gdouble dx = GTS_POINT(p)->x - GTS_POINT(v)->x;
-	gdouble dy = GTS_POINT(p)->y - GTS_POINT(v)->y;
-	gdouble theta = atan(fabs(dy / dx));
-
-	g_assert(finite(theta));
-
-	if (dx >= 0.) {
-
-		if (dy >= 0.) {
-			*x = GTS_POINT(v)->x + (d * cos(theta));
-			*y = GTS_POINT(v)->y + (d * sin(theta));
-		}
-		else {
-			*x = GTS_POINT(v)->x + (d * cos(theta));
-			*y = GTS_POINT(v)->y - (d * sin(theta));
-		}
-
-	}
-	else {
-
-		if (dy >= 0.) {
-			*x = GTS_POINT(v)->x - (d * cos(theta));
-			*y = GTS_POINT(v)->y + (d * sin(theta));
-		}
-		else {
-			*x = GTS_POINT(v)->x - (d * cos(theta));
-			*y = GTS_POINT(v)->y - (d * sin(theta));
-		}
-
-	}
-
-}
-
-#define tv_on_layer(v,l) (l == TOPOROUTER_BBOX(TOPOROUTER_VERTEX(v)->boxes->data)->layer)
-
-static inline gdouble min_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2)
-{
-
-	gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms;
-/*  toporouter_edge_t *e = v1->routingedge;*/
-
-	v1halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v1)) / 2.;
-	v2halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v2)) / 2.;
-
-	v1clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v1));
-	v2clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v2));
-
-	ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance);
-
-#ifdef SPACING_DEBUG
-	printf("v1halfthick = %f v2halfthick = %f v1clearance = %f v2clearance = %f ms = %f\n",
-				 v1halfthick, v2halfthick, v1clearance, v2clearance, ms);
-#endif
-
-	return ms;
-}
-
-/* v1 is a vertex in the CDT, and v2 is a net... other way around?*/
-static inline gdouble min_vertex_net_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2)
-{
-
-	gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms;
-
-	v1halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v1)) / 2.;
-	v2halfthick = cluster_thickness(vertex_bbox(v2)->cluster) / 2.;
-
-	v1clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v1));
-	v2clearance = cluster_clearance(vertex_bbox(v2)->cluster);
-
-	ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance);
-
-	return ms;
-}
-
-static inline gdouble min_oproute_vertex_spacing(toporouter_oproute_t * oproute, toporouter_vertex_t * v2)
-{
-
-	gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms;
-
-	v1halfthick = lookup_thickness(oproute->style) / 2.;
-	v2halfthick = vertex_net_thickness(v2) / 2.;
-
-	v1clearance = lookup_clearance(oproute->style);
-	v2clearance = vertex_net_clearance(v2);
-
-	ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance);
-
-	return ms;
-}
-
-gdouble min_oproute_net_spacing(toporouter_oproute_t * oproute, toporouter_vertex_t * v2)
-{
-
-	gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms;
-
-	v1halfthick = lookup_thickness(oproute->style) / 2.;
-	v2halfthick = cluster_thickness(v2->route->src) / 2.;
-
-	v1clearance = lookup_clearance(oproute->style);
-	v2clearance = cluster_clearance(v2->route->src);
-
-	ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance);
-
-	return ms;
-}
-
-gdouble min_net_net_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2)
-{
-
-	gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms;
-
-	v1halfthick = cluster_thickness(v1->route->src) / 2.;
-	v2halfthick = cluster_thickness(v2->route->src) / 2.;
-
-	v1clearance = cluster_clearance(v1->route->src);
-	v2clearance = cluster_clearance(v2->route->src);
-
-	ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance);
-
-	return ms;
-}
-
-void
-toporouter_draw_cluster(toporouter_t * r, drawing_context_t * dc, toporouter_cluster_t * cluster, gdouble red, gdouble green,
-												gdouble blue, guint layer)
-{
-#if TOPO_OUTPUT_ENABLED
-/*GList *i = cluster->i;
-
-  while(i) {
-    toporouter_bbox_t *box = TOPOROUTER_BBOX(i->data);
-
-    if(box->point && vz(box->point) == layer) {
-      cairo_set_source_rgba(dc->cr, red, green, blue, 0.8f);
-      cairo_arc(dc->cr, vx(box->point) * dc->s + MARGIN, vy(box->point) * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-      cairo_fill(dc->cr);
-    }
-
-    i = i->next;
-  }
-*/
-#endif
-}
-
-void
-toporouter_draw_surface(toporouter_t * r, GtsSurface * s, char *filename, int w, int h, int mode, GList * datas, int layer,
-												GList * candidatepoints)
-{
-#if TOPO_OUTPUT_ENABLED
-	drawing_context_t *dc;
-	GList *i;
-	toporouter_vertex_t *tv, *tv2 = NULL;
-
-	dc = toporouter_output_init(w, h, filename);
-	dc->mode = mode;
-	dc->data = NULL;
-
-	gts_surface_foreach_edge(s, toporouter_draw_edge, dc);
-	gts_surface_foreach_vertex(s, toporouter_draw_vertex, dc);
-
-	i = r->routednets;
-	while (i) {
-		GList *j = TOPOROUTER_ROUTE(i->data)->path;
-		tv2 = NULL;
-		while (j) {
-			tv = TOPOROUTER_VERTEX(j->data);
-			if (GTS_POINT(tv)->z == layer) {
-				if (tv && tv2) {
-					cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.8f);
-					cairo_move_to(dc->cr, GTS_POINT(tv)->x * dc->s + MARGIN, GTS_POINT(tv)->y * dc->s + MARGIN);
-					cairo_line_to(dc->cr, GTS_POINT(tv2)->x * dc->s + MARGIN, GTS_POINT(tv2)->y * dc->s + MARGIN);
-					cairo_stroke(dc->cr);
-				}
-
-				if (tv->flags & VERTEX_FLAG_RED) {
-					cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-				}
-				else if (tv->flags & VERTEX_FLAG_GREEN) {
-					cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-				}
-				else if (tv->flags & VERTEX_FLAG_BLUE) {
-					cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-				}
-				else {
-
-					cairo_set_source_rgba(dc->cr, 1., 1., 1., 0.8f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-
-				}
-
-				if (tv->routingedge && !TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) {
-					gdouble tempx, tempy, nms, pms;
-					GList *i = g_list_find(edge_routing(tv->routingedge), tv);
-					toporouter_vertex_t *nextv, *prevv;
-
-					nextv = edge_routing_next(tv->routingedge, i);
-					prevv = edge_routing_prev(tv->routingedge, i);
-
-					nms = min_spacing(tv, nextv);
-					pms = min_spacing(tv, prevv);
-
-					g_assert(finite(nms));
-					g_assert(finite(pms));
-
-					point_from_point_to_point(tv, nextv, nms, &tempx, &tempy);
-
-					cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 1.0f, 0.8f);
-					cairo_move_to(dc->cr, vx(tv) * dc->s + MARGIN, vy(tv) * dc->s + MARGIN);
-					cairo_line_to(dc->cr, tempx * dc->s + MARGIN, tempy * dc->s + MARGIN);
-					cairo_stroke(dc->cr);
-
-					point_from_point_to_point(tv, prevv, pms, &tempx, &tempy);
-
-					cairo_move_to(dc->cr, vx(tv) * dc->s + MARGIN, vy(tv) * dc->s + MARGIN);
-					cairo_line_to(dc->cr, tempx * dc->s + MARGIN, tempy * dc->s + MARGIN);
-					cairo_stroke(dc->cr);
-
-
-
-
-				}
-
-
-			}
-			tv2 = tv;
-			j = j->next;
-		}
-		i = i->next;
-	}
-
-	while (datas) {
-		toporouter_route_t *routedata = (toporouter_route_t *) datas->data;
-
-		GList *i;										/*, *k; */
-
-		toporouter_draw_cluster(r, dc, routedata->src, 1., 0., 0., layer);
-		toporouter_draw_cluster(r, dc, routedata->dest, 0., 0., 1., layer);
-
-		tv2 = NULL;
-		i = routedata->path;
-		while (i) {
-			tv = TOPOROUTER_VERTEX(i->data);
-			if (GTS_POINT(tv)->z == layer) {
-				if (tv && tv2) {
-					cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.8f);
-					cairo_move_to(dc->cr, GTS_POINT(tv)->x * dc->s + MARGIN, GTS_POINT(tv)->y * dc->s + MARGIN);
-					cairo_line_to(dc->cr, GTS_POINT(tv2)->x * dc->s + MARGIN, GTS_POINT(tv2)->y * dc->s + MARGIN);
-					cairo_stroke(dc->cr);
-				}
-			}
-			tv2 = tv;
-			i = i->next;
-		}
-
-
-		if (routedata->alltemppoints) {
-			GList *i, *j;
-			i = j = g_hash_table_get_keys(routedata->alltemppoints);
-			while (i) {
-				toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data);
-
-				if (GTS_POINT(tv)->z != layer) {
-					i = i->next;
-					continue;
-				}
-				if (tv->flags & VERTEX_FLAG_BLUE) {
-					cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-				}
-				else if (tv->flags & VERTEX_FLAG_RED) {
-					cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-
-				}
-				else if (tv->flags & VERTEX_FLAG_GREEN) {
-					cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-				}
-				else {
-					cairo_set_source_rgba(dc->cr, 1., 1., 1., 0.8f);
-					cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI);
-					cairo_fill(dc->cr);
-				}
-				i = i->next;
-			}
-			g_list_free(j);
-		}
-		datas = datas->next;
-	}
-	toporouter_output_close(dc);
-#endif
-}
-
-
-void toporouter_layer_free(toporouter_layer_t * l)
-{
-	g_list_free(l->vertices);
-	g_list_free(l->constraints);
-
-}
-
-guint groupcount(void)
-{
-	int group;
-	guint count = 0;
-
-	for (group = 0; group < pcb_max_group; group++) {
-		if (PCB->LayerGroups.Number[group] > 0)
-			count++;
-	}
-
-	return count;
-}
-
-void toporouter_free(toporouter_t * r)
-{
-	struct timeval endtime;
-	int secs, usecs;
-
-	int i;
-	for (i = 0; i < groupcount(); i++) {
-		toporouter_layer_free(&r->layers[i]);
-	}
-
-
-	gettimeofday(&endtime, NULL);
-
-	secs = (int) (endtime.tv_sec - r->starttime.tv_sec);
-	usecs = (int) ((endtime.tv_usec - r->starttime.tv_usec) / 1000);
-
-	if (usecs < 0) {
-		secs -= 1;
-		usecs += 1000;
-	}
-
-	pcb_message(PCB_MSG_INFO, _("Elapsed time: %d.%02d seconds\n"), secs, usecs);
-	free(r->layers);
-	free(r);
-
-}
-
-/* wind:
- * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively.
- */
-int wind(toporouter_spoint_t * p1, toporouter_spoint_t * p2, toporouter_spoint_t * p3)
-{
-	double rval, dx1, dx2, dy1, dy2;
-	dx1 = p2->x - p1->x;
-	dy1 = p2->y - p1->y;
-	dx2 = p3->x - p2->x;
-	dy2 = p3->y - p2->y;
-	rval = (dx1 * dy2) - (dy1 * dx2);
-	return (rval > 0.0001) ? 1 : ((rval < -0.0001) ? -1 : 0);
-}
-
-/* wind_double:
- * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively.
- */
-int wind_double(gdouble p1_x, gdouble p1_y, gdouble p2_x, gdouble p2_y, gdouble p3_x, gdouble p3_y)
-{
-	double rval, dx1, dx2, dy1, dy2;
-	dx1 = p2_x - p1_x;
-	dy1 = p2_y - p1_y;
-	dx2 = p3_x - p2_x;
-	dy2 = p3_y - p2_y;
-	rval = (dx1 * dy2) - (dy1 * dx2);
-	return (rval > 0.0001) ? 1 : ((rval < -0.0001) ? -1 : 0);
-}
-
-static inline void print_toporouter_constraint(toporouter_constraint_t * tc)
-{
-	printf("%f,%f -> %f,%f ",
-				 tc->c.edge.segment.v1->p.x, tc->c.edge.segment.v1->p.y, tc->c.edge.segment.v2->p.x, tc->c.edge.segment.v2->p.y);
-}
-
-static inline void print_toporouter_vertex(toporouter_vertex_t * tv)
-{
-	printf("%f,%f ", tv->v.p.x, tv->v.p.y);
-}
-
-
-/**
- * vertices_on_line:
- * Given vertex a, gradient m, and radius r: 
- *
- * Return vertices on line of a & m at r from a
- */
-void vertices_on_line(toporouter_spoint_t * a, gdouble m, gdouble r, toporouter_spoint_t * b0, toporouter_spoint_t * b1)
-{
-
-	gdouble c, temp;
-
-	if (m == INFINITY || m == -INFINITY) {
-		b0->y = a->y + r;
-		b1->y = a->y - r;
-
-		b0->x = a->x;
-		b1->x = a->x;
-
-		return;
-	}
-
-	c = a->y - (m * a->x);
-
-	temp = sqrt(pow(r, 2) / (1 + pow(m, 2)));
-
-	b0->x = a->x + temp;
-	b1->x = a->x - temp;
-
-	b0->y = b0->x * m + c;
-	b1->y = b1->x * m + c;
-
-}
-
-/**
- * vertices_on_line:
- * Given vertex a, gradient m, and radius r: 
- *
- * Return vertices on line of a & m at r from a
- */
-void coords_on_line(gdouble ax, gdouble ay, gdouble m, gdouble r, gdouble * b0x, gdouble * b0y, gdouble * b1x, gdouble * b1y)
-{
-
-	gdouble c, temp;
-
-	if (m == INFINITY || m == -INFINITY) {
-		*b0y = ay + r;
-		*b1y = ay - r;
-
-		*b0x = ax;
-		*b1x = ax;
-
-		return;
-	}
-
-	c = ay - (m * ax);
-
-	temp = sqrt(pow(r, 2) / (1 + pow(m, 2)));
-
-	*b0x = ax + temp;
-	*b1x = ax - temp;
-
-	*b0y = *b0x * m + c;
-	*b1y = *b1x * m + c;
-
-}
-
-/**
- * vertices_on_line:
- * Given vertex a, gradient m, and radius r: 
- *
- * Return vertices on line of a & m at r from a
- */
-void points_on_line(GtsPoint * a, gdouble m, gdouble r, GtsPoint * b0, GtsPoint * b1)
-{
-
-	gdouble c, temp;
-
-	if (m == INFINITY || m == -INFINITY) {
-		b0->y = a->y + r;
-		b1->y = a->y - r;
-
-		b0->x = a->x;
-		b1->x = a->x;
-
-		return;
-	}
-
-	c = a->y - (m * a->x);
-
-	temp = sqrt(pow(r, 2) / (1 + pow(m, 2)));
-
-	b0->x = a->x + temp;
-	b1->x = a->x - temp;
-
-	b0->y = b0->x * m + c;
-	b1->y = b1->x * m + c;
-
-}
-
-/*
- * Returns gradient of segment given by a & b
- */
-gdouble vertex_gradient(toporouter_spoint_t * a, toporouter_spoint_t * b)
-{
-	if (a->x == b->x)
-		return INFINITY;
-
-	return ((b->y - a->y) / (b->x - a->x));
-}
-
-/*
- * Returns gradient of segment given by (x0,y0) & (x1,y1)
- */
-static inline gdouble cartesian_gradient(gdouble x0, gdouble y0, gdouble x1, gdouble y1)
-{
-	if (epsilon_equals(x0, x1))
-		return INFINITY;
-
-	return ((y1 - y0) / (x1 - x0));
-}
-
-/*
- * Returns gradient of segment given by (x0,y0) & (x1,y1)
- */
-static inline gdouble point_gradient(GtsPoint * a, GtsPoint * b)
-{
-	return cartesian_gradient(a->x, a->y, b->x, b->y);
-}
-
-gdouble segment_gradient(GtsSegment * s)
-{
-	return cartesian_gradient(GTS_POINT(s->v1)->x, GTS_POINT(s->v1)->y, GTS_POINT(s->v2)->x, GTS_POINT(s->v2)->y);
-}
-
-/*
- * Returns gradient perpendicular to m
- */
-gdouble perpendicular_gradient(gdouble m)
-{
-	if (isinf(m))
-		return 0.0f;
-	if (m < EPSILON && m > -EPSILON)
-		return INFINITY;
-	return -1.0f / m;
-}
-
-/*
- * Returns the distance between two vertices in the x-y plane
- */
-gdouble vertices_plane_distance(toporouter_spoint_t * a, toporouter_spoint_t * b)
-{
-	return sqrt(pow(a->x - b->x, 2) + pow(a->y - b->y, 2));
-}
-
-/*
- * Finds the point p distance r away from a on the line segment of a & b 
- */
-static inline void vertex_outside_segment(toporouter_spoint_t * a, toporouter_spoint_t * b, gdouble r, toporouter_spoint_t * p)
-{
-	toporouter_spoint_t temp[2];
-
-	vertices_on_line(a, vertex_gradient(a, b), r, &temp[0], &temp[1]);
-
-	if (vertices_plane_distance(&temp[0], b) > vertices_plane_distance(&temp[1], b)) {
-		p->x = temp[0].x;
-		p->y = temp[0].y;
-	}
-	else {
-		p->x = temp[1].x;
-		p->y = temp[1].y;
-	}
-
-}
-
-/* proper intersection:
- * AB and CD must share a point interior to both segments.
- * returns TRUE if AB properly intersects CD.
- */
-gint coord_intersect_prop(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy, gdouble dx, gdouble dy)
-{
-	gint wind_abc = coord_wind(ax, ay, bx, by, cx, cy);
-	gint wind_abd = coord_wind(ax, ay, bx, by, dx, dy);
-	gint wind_cda = coord_wind(cx, cy, dx, dy, ax, ay);
-	gint wind_cdb = coord_wind(cx, cy, dx, dy, bx, by);
-
-	if (!wind_abc || !wind_abd || !wind_cda || !wind_cdb)
-		return 0;
-
-	return (wind_abc ^ wind_abd) && (wind_cda ^ wind_cdb);
-}
-
-/* proper intersection:
- * AB and CD must share a point interior to both segments.
- * returns TRUE if AB properly intersects CD.
- */
-int point_intersect_prop(GtsPoint * a, GtsPoint * b, GtsPoint * c, GtsPoint * d)
-{
-
-	if (point_wind(a, b, c) == 0 || point_wind(a, b, d) == 0 || point_wind(c, d, a) == 0 || point_wind(c, d, b) == 0)
-		return 0;
-
-	return (point_wind(a, b, c) ^ point_wind(a, b, d)) && (point_wind(c, d, a) ^ point_wind(c, d, b));
-}
-
-static inline int vertex_intersect_prop(GtsVertex * a, GtsVertex * b, GtsVertex * c, GtsVertex * d)
-{
-	return point_intersect_prop(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c), GTS_POINT(d));
-}
-
-static inline int
-tvertex_intersect_prop(toporouter_vertex_t * a, toporouter_vertex_t * b, toporouter_vertex_t * c, toporouter_vertex_t * d)
-{
-	return point_intersect_prop(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c), GTS_POINT(d));
-}
-
-/*
-static inline int
-tvertex_intersect(toporouter_vertex_t *a, toporouter_vertex_t *b, toporouter_vertex_t *c, toporouter_vertex_t *d) 
-{
-  if( !point_wind(GTS_POINT(a), GTS_POINT(d), GTS_POINT(b)) || !point_wind(GTS_POINT(a), GTS_POINT(c), GTS_POINT(b)) ) return 1;
-
-  return 
-    ( point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)) ^ point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(d)) ) && 
-    ( point_wind(GTS_POINT(c), GTS_POINT(d), GTS_POINT(a)) ^ point_wind(GTS_POINT(c), GTS_POINT(d), GTS_POINT(b)) );
-}
-*/
-
-/* intersection vertex:
- * AB and CD must share a point interior to both segments.
- * returns vertex at intersection of AB and CD.
- */
-GtsVertex *vertex_intersect(GtsVertex * a, GtsVertex * b, GtsVertex * c, GtsVertex * d)
-{
-	GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class());
-	GtsVertex *rval;
-	gdouble ua_top, ua_bot, ua, rx, ry;
-
-	/* TODO: this could be done more efficiently without duplicating computation */
-	if (!vertex_intersect_prop(a, b, c, d))
-		return NULL;
-
-	ua_top = ((d->p.x - c->p.x) * (a->p.y - c->p.y)) - ((d->p.y - c->p.y) * (a->p.x - c->p.x));
-	ua_bot = ((d->p.y - c->p.y) * (b->p.x - a->p.x)) - ((d->p.x - c->p.x) * (b->p.y - a->p.y));
-	ua = ua_top / ua_bot;
-	rx = a->p.x + (ua * (b->p.x - a->p.x));
-	ry = a->p.y + (ua * (b->p.y - a->p.y));
-
-	rval = gts_vertex_new(vertex_class, rx, ry, 0.0f);
-
-	return rval;
-}
-
-/* intersection vertex:
- * AB and CD must share a point interior to both segments.
- * returns vertex at intersection of AB and CD.
- */
-void
-coord_intersect(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy, gdouble dx, gdouble dy, gdouble * rx,
-								gdouble * ry)
-{
-	gdouble ua_top, ua_bot, ua;
-
-	ua_top = ((dx - cx) * (ay - cy)) - ((dy - cy) * (ax - cx));
-	ua_bot = ((dy - cy) * (bx - ax)) - ((dx - cx) * (by - ay));
-	ua = ua_top / ua_bot;
-	*rx = ax + (ua * (bx - ax));
-	*ry = ay + (ua * (by - ay));
-
-}
-
-
-/*
- * returns true if c is between a and b 
- */
-int point_between(GtsPoint * a, GtsPoint * b, GtsPoint * c)
-{
-	if (point_wind(a, b, c) != 0)
-		return 0;
-
-	if (a->x != b->x) {
-		return ((a->x <= c->x) && (c->x <= b->x)) || ((a->x >= c->x) && (c->x >= b->x));
-	}
-	return ((a->y <= c->y) && (c->y <= b->y)) || ((a->y >= c->y) && (c->y >= b->y));
-}
-
-static inline int vertex_between(GtsVertex * a, GtsVertex * b, GtsVertex * c)
-{
-	return point_between(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c));
-}
-
-void delaunay_create_from_vertices(GList * vertices, GtsSurface ** surface, GtsTriangle ** t)
-{
-	GList *i = vertices;
-	GtsVertex *v1, *v2, *v3;
-	GSList *vertices_slist = NULL;
-
-	while (i) {
-		vertices_slist = g_slist_prepend(vertices_slist, i->data);
-		i = i->next;
-	}
-
-	/* TODO: just work this out from the board outline */
-	*t = gts_triangle_enclosing(gts_triangle_class(), vertices_slist, 100000.0f);
-	gts_triangle_vertices(*t, &v1, &v2, &v3);
-
-	*surface = gts_surface_new(gts_surface_class(), gts_face_class(),
-														 GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX_CLASS(toporouter_vertex_class()));
-
-	gts_surface_add_face(*surface, gts_face_new(gts_face_class(), (*t)->e1, (*t)->e2, (*t)->e3));
-
-	i = vertices;
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(gts_delaunay_add_vertex(*surface, (GtsVertex *) i->data, NULL));
-
-		if (v) {
-			printf("ERROR: vertex could not be added to CDT ");
-			print_vertex(v);
-		}
-
-		i = i->next;
-	}
-
-	gts_allow_floating_vertices = TRUE;
-	gts_object_destroy(GTS_OBJECT(v1));
-	gts_object_destroy(GTS_OBJECT(v2));
-	gts_object_destroy(GTS_OBJECT(v3));
-	gts_allow_floating_vertices = FALSE;
-
-	g_slist_free(vertices_slist);
-/*  return surface;*/
-}
-
-GSList *list_to_slist(GList * i)
-{
-	GSList *rval = NULL;
-	while (i) {
-		rval = g_slist_prepend(rval, i->data);
-		i = i->next;
-	}
-	return rval;
-}
-
-toporouter_bbox_t *toporouter_bbox_create_from_points(int layer, GList * vertices, toporouter_term_t type, gpointer data)
-{
-	toporouter_bbox_t *bbox;
-	GSList *vertices_slist = list_to_slist(vertices);
-
-/*  delaunay_create_from_vertices(vertices, &s, &t);*/
-	bbox = TOPOROUTER_BBOX(gts_bbox_points(GTS_BBOX_CLASS(toporouter_bbox_class()), vertices_slist));
-	bbox->type = type;
-	bbox->data = data;
-
-	bbox->surface = NULL;
-	bbox->enclosing = NULL;
-
-	bbox->layer = layer;
-
-	bbox->point = NULL;
-	bbox->realpoint = NULL;
-
-	g_slist_free(vertices_slist);
-	return bbox;
-}
-
-toporouter_bbox_t *toporouter_bbox_create(int layer, GList * vertices, toporouter_term_t type, gpointer data)
-{
-	toporouter_bbox_t *bbox;
-	GtsSurface *s;
-	GtsTriangle *t;
-
-	delaunay_create_from_vertices(vertices, &s, &t);
-	bbox = TOPOROUTER_BBOX(gts_bbox_surface(GTS_BBOX_CLASS(toporouter_bbox_class()), s));
-	bbox->type = type;
-	bbox->data = data;
-
-	bbox->surface = s;
-	bbox->enclosing = t;
-
-	bbox->layer = layer;
-
-	return bbox;
-}
-
-GtsVertex *insert_vertex(toporouter_t * r, toporouter_layer_t * l, gdouble x, gdouble y, toporouter_bbox_t * box)
-{
-	GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class());
-	GtsVertex *v;
-	GList *i;
-
-	i = l->vertices;
-	while (i) {
-		v = (GtsVertex *) i->data;
-		if (v->p.x == x && v->p.y == y) {
-			TOPOROUTER_VERTEX(v)->bbox = box;
-			return v;
-		}
-		i = i->next;
-	}
-
-	v = gts_vertex_new(vertex_class, x, y, l - r->layers);
-	TOPOROUTER_VERTEX(v)->bbox = box;
-	l->vertices = g_list_prepend(l->vertices, v);
-
-	return v;
-}
-
-GList *insert_constraint_edge(toporouter_t * r, toporouter_layer_t * l, gdouble x1, gdouble y1, guint flags1,
-															gdouble x2, gdouble y2, guint flags2, toporouter_bbox_t * box)
-{
-	GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class());
-	GtsEdgeClass *edge_class = GTS_EDGE_CLASS(toporouter_constraint_class());
-	GtsVertex *p[2];
-	GtsVertex *v;
-	GList *i;
-	GtsEdge *e;
-
-	p[0] = p[1] = NULL;
-
-	/* insert or find points */
-
-	i = l->vertices;
-	while (i) {
-		v = (GtsVertex *) i->data;
-		if (v->p.x == x1 && v->p.y == y1)
-			p[0] = v;
-		if (v->p.x == x2 && v->p.y == y2)
-			p[1] = v;
-		i = i->next;
-	}
-
-	if (p[0] == NULL) {
-		p[0] = gts_vertex_new(vertex_class, x1, y1, l - r->layers);
-		TOPOROUTER_VERTEX(p[0])->bbox = box;
-		l->vertices = g_list_prepend(l->vertices, p[0]);
-	}
-	if (p[1] == NULL) {
-		p[1] = gts_vertex_new(vertex_class, x2, y2, l - r->layers);
-		TOPOROUTER_VERTEX(p[1])->bbox = box;
-		l->vertices = g_list_prepend(l->vertices, p[1]);
-	}
-
-	TOPOROUTER_VERTEX(p[0])->flags = flags1;
-	TOPOROUTER_VERTEX(p[1])->flags = flags2;
-
-	e = gts_edge_new(edge_class, p[0], p[1]);
-	TOPOROUTER_CONSTRAINT(e)->box = box;
-	l->constraints = g_list_prepend(l->constraints, e);
-/*  return insert_constraint_edge_rec(r, l, p, box);*/
-	return g_list_prepend(NULL, e);
-
-}
-
-void insert_constraints_from_list(toporouter_t * r, toporouter_layer_t * l, GList * vlist, toporouter_bbox_t * box)
-{
-	GList *i = vlist;
-	toporouter_vertex_t *pv = NULL, *v;
-
-	while (i) {
-		v = TOPOROUTER_VERTEX(i->data);
-
-		if (pv) {
-			box->constraints =
-				g_list_concat(box->constraints, insert_constraint_edge(r, l, vx(v), vy(v), v->flags, vx(pv), vy(pv), pv->flags, box));
-		}
-
-		pv = v;
-		i = i->next;
-	}
-
-	v = TOPOROUTER_VERTEX(vlist->data);
-	box->constraints =
-		g_list_concat(box->constraints, insert_constraint_edge(r, l, vx(v), vy(v), v->flags, vx(pv), vy(pv), pv->flags, box));
-
-}
-
-void insert_centre_point(toporouter_t * r, toporouter_layer_t * l, gdouble x, gdouble y)
-{
-	GList *i;
-	GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class());
-
-	i = l->vertices;
-	while (i) {
-		GtsPoint *p = GTS_POINT(i->data);
-		if (p->x == x && p->y == y)
-			return;
-		i = i->next;
-	}
-
-	l->vertices = g_list_prepend(l->vertices, gts_vertex_new(vertex_class, x, y, 0.0f));
-}
-
-GtsPoint *midpoint(GtsPoint * a, GtsPoint * b)
-{
-	return gts_point_new(gts_point_class(), (a->x + b->x) / 2., (a->y + b->y) / 2., 0.);
-}
-
-static inline gdouble pad_rad(pcb_pad_t * pad)
-{
-	return (lookup_thickness(pad->Name) / 2.) + lookup_clearance(pad->Name);
-}
-
-static inline gdouble pin_rad(pcb_pin_t * pin)
-{
-	return (lookup_thickness(pin->Name) / 2.) + lookup_clearance(pin->Name);
-}
-
-GList *rect_with_attachments(gdouble rad,
-														 gdouble x0, gdouble y0,
-														 gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, gdouble z)
-{
-	GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class());
-	GList *r = NULL, *rr = NULL, *i;
-	toporouter_vertex_t *curpoint, *temppoint;
-
-
-	curpoint = TOPOROUTER_VERTEX(gts_vertex_new(vertex_class, x0, y0, z));
-
-	r = g_list_prepend(NULL, curpoint);
-	r = g_list_prepend(r, gts_vertex_new(vertex_class, x1, y1, z));
-	r = g_list_prepend(r, gts_vertex_new(vertex_class, x2, y2, z));
-	r = g_list_prepend(r, gts_vertex_new(vertex_class, x3, y3, z));
-
-	i = r;
-	while (i) {
-		temppoint = TOPOROUTER_VERTEX(i->data);
-		rr = g_list_prepend(rr, curpoint);
-
-		curpoint = temppoint;
-		i = i->next;
-	}
-
-	g_list_free(r);
-
-	return rr;
-}
-
-#define VERTEX_CENTRE(x) TOPOROUTER_VERTEX( vertex_bbox(x)->point )
-
-/*
- * Read pad data from layer into toporouter_layer_t struct
- *
- * Inserts points and constraints into GLists
- */
-int read_pads(toporouter_t * r, toporouter_layer_t * l, guint layer)
-{
-	toporouter_spoint_t p[2], rv[5];
-	gdouble x[2], y[2], t, m;
-
-	GList *vlist = NULL;
-	toporouter_bbox_t *bbox = NULL;
-
-	pcb_layergrp_id_t front = pcb_layer_get_group(pcb_component_silk_layer);
-	pcb_layergrp_id_t back = pcb_layer_get_group(pcb_solder_silk_layer);
-
-/*  printf("read_pads: front = %d back = %d layer = %d\n", 
-       front, back, layer);*/
-
-	/* If its not the top or bottom layer, there are no pads to read */
-	if (l - r->layers != front && l - r->layers != back)
-		return 0;
-
-	PCB_ELEMENT_LOOP(PCB->Data);
-	{
-		PCB_PAD_LOOP(element);
-		{
-			if ((l - r->layers == back && PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, pad)) || (l - r->layers == front && !PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, pad))) {
-
-				t = (gdouble) pad->Thickness / 2.0f;
-				x[0] = pad->Point1.X;
-				x[1] = pad->Point2.X;
-				y[0] = pad->Point1.Y;
-				y[1] = pad->Point2.Y;
-
-
-				if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pad)) {
-					/* Square or oblong pad. Four points and four constraint edges are
-					 * used */
-
-					if (x[0] == x[1] && y[0] == y[1]) {
-						/* Pad is square */
-
-/*            vlist = g_list_prepend(NULL, gts_vertex_new (vertex_class, x[0]-t, y[0]-t, 0.));
-              vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]-t, y[0]+t, 0.));
-              vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]+t, y[0]+t, 0.));
-              vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]+t, y[0]-t, 0.)); */
-						vlist = rect_with_attachments(pad_rad(pad),
-																					x[0] - t, y[0] - t,
-																					x[0] - t, y[0] + t, x[0] + t, y[0] + t, x[0] + t, y[0] - t, l - r->layers);
-						bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad);
-						r->bboxes = g_slist_prepend(r->bboxes, bbox);
-						insert_constraints_from_list(r, l, vlist, bbox);
-						g_list_free(vlist);
-
-						/*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, x[0], y[0], 0.) ); */
-						bbox->point = GTS_POINT(insert_vertex(r, l, x[0], y[0], bbox));
-						g_assert(TOPOROUTER_VERTEX(bbox->point)->bbox == bbox);
-					}
-					else {
-						/* Pad is diagonal oblong or othogonal oblong */
-
-						m = cartesian_gradient(x[0], y[0], x[1], y[1]);
-
-						p[0].x = x[0];
-						p[0].y = y[0];
-						p[1].x = x[1];
-						p[1].y = y[1];
-
-						vertex_outside_segment(&p[0], &p[1], t, &rv[0]);
-						vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[1], &rv[2]);
-
-						vertex_outside_segment(&p[1], &p[0], t, &rv[0]);
-						vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[3], &rv[4]);
-
-						if (wind(&rv[1], &rv[2], &rv[3]) != wind(&rv[2], &rv[3], &rv[4])) {
-							rv[0].x = rv[3].x;
-							rv[0].y = rv[3].y;
-							rv[3].x = rv[4].x;
-							rv[3].y = rv[4].y;
-							rv[4].x = rv[0].x;
-							rv[4].y = rv[0].y;
-						}
-
-/*            vlist = g_list_prepend(NULL,  gts_vertex_new (vertex_class, rv[1].x, rv[1].y, 0.));
-              vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[2].x, rv[2].y, 0.));
-              vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[3].x, rv[3].y, 0.));
-              vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[4].x, rv[4].y, 0.));*/
-						vlist = rect_with_attachments(pad_rad(pad),
-																					rv[1].x, rv[1].y,
-																					rv[2].x, rv[2].y, rv[3].x, rv[3].y, rv[4].x, rv[4].y, l - r->layers);
-						bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad);
-						r->bboxes = g_slist_prepend(r->bboxes, bbox);
-						insert_constraints_from_list(r, l, vlist, bbox);
-						g_list_free(vlist);
-
-						/*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., 0.) ); */
-						bbox->point = GTS_POINT(insert_vertex(r, l, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., bbox));
-						g_assert(TOPOROUTER_VERTEX(bbox->point)->bbox == bbox);
-
-					}
-
-				}
-				else {
-					/* Either round pad or pad with curved edges */
-
-					if (x[0] == x[1] && y[0] == y[1]) {
-						/* One point */
-
-						/* bounding box same as square pad */
-						vlist = rect_with_attachments(pad_rad(pad),
-																					x[0] - t, y[0] - t,
-																					x[0] - t, y[0] + t, x[0] + t, y[0] + t, x[0] + t, y[0] - t, l - r->layers);
-						bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad);
-						r->bboxes = g_slist_prepend(r->bboxes, bbox);
-						g_list_free(vlist);
-
-						/*bbox->point = GTS_POINT( insert_vertex(r, l, x[0], y[0], bbox) ); */
-						bbox->point = GTS_POINT(insert_vertex(r, l, x[0], y[0], bbox));
-
-					}
-					else {
-						/* Two points and one constraint edge */
-
-						/* the rest is just for bounding box */
-						m = cartesian_gradient(x[0], y[0], x[1], y[1]);
-
-						p[0].x = x[0];
-						p[0].y = y[0];
-						p[1].x = x[1];
-						p[1].y = y[1];
-
-						vertex_outside_segment(&p[0], &p[1], t, &rv[0]);
-						vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[1], &rv[2]);
-
-						vertex_outside_segment(&p[1], &p[0], t, &rv[0]);
-						vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[3], &rv[4]);
-
-						if (wind(&rv[1], &rv[2], &rv[3]) != wind(&rv[2], &rv[3], &rv[4])) {
-							rv[0].x = rv[3].x;
-							rv[0].y = rv[3].y;
-							rv[3].x = rv[4].x;
-							rv[3].y = rv[4].y;
-							rv[4].x = rv[0].x;
-							rv[4].y = rv[0].y;
-						}
-
-						vlist = rect_with_attachments(pad_rad(pad),
-																					rv[1].x, rv[1].y,
-																					rv[2].x, rv[2].y, rv[3].x, rv[3].y, rv[4].x, rv[4].y, l - r->layers);
-						bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad);
-						r->bboxes = g_slist_prepend(r->bboxes, bbox);
-						insert_constraints_from_list(r, l, vlist, bbox);
-						g_list_free(vlist);
-
-						/*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., 0.) ); */
-						bbox->point = GTS_POINT(insert_vertex(r, l, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., bbox));
-
-						/*bbox->constraints = g_list_concat(bbox->constraints, insert_constraint_edge(r, l, x[0], y[0], x[1], y[1], bbox)); */
-
-					}
-
-
-				}
-
-			}
-		}
-		PCB_END_LOOP;
-	}
-	PCB_END_LOOP;
-
-	return 0;
-}
-
-/*
- * Read points data (all layers) into GList
- *
- * Inserts pin and via points
- */
-int read_points(toporouter_t * r, toporouter_layer_t * l, int layer)
-{
-	gdouble x, y, t;
-
-	GList *vlist = NULL;
-	toporouter_bbox_t *bbox = NULL;
-
-	PCB_ELEMENT_LOOP(PCB->Data);
-	{
-		PCB_PIN_LOOP(element);
-		{
-
-			t = (gdouble) pin->Thickness / 2.0f;
-			x = pin->X;
-			y = pin->Y;
-
-			if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pin)) {
-
-				vlist = rect_with_attachments(pin_rad(pin), x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers);
-				bbox = toporouter_bbox_create(l - r->layers, vlist, PIN, pin);
-				r->bboxes = g_slist_prepend(r->bboxes, bbox);
-				insert_constraints_from_list(r, l, vlist, bbox);
-				g_list_free(vlist);
-				bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox));
-
-			}
-			else if (PCB_FLAG_TEST(PCB_FLAG_OCTAGON, pin)) {
-				/* TODO: Handle octagon pins */
-				fprintf(stderr, "No support for octagon pins yet\n");
-			}
-			else {
-				vlist = rect_with_attachments(pin_rad(pin), x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers);
-				bbox = toporouter_bbox_create(l - r->layers, vlist, PIN, pin);
-				r->bboxes = g_slist_prepend(r->bboxes, bbox);
-				g_list_free(vlist);
-				bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox));
-			}
-		}
-		PCB_END_LOOP;
-	}
-	PCB_END_LOOP;
-
-	PCB_VIA_LOOP(PCB->Data);
-	{
-
-		t = (gdouble) via->Thickness / 2.0f;
-		x = via->X;
-		y = via->Y;
-
-		if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, via)) {
-
-			vlist = rect_with_attachments(pin_rad((pcb_pin_t *) via),
-																		x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers);
-			bbox = toporouter_bbox_create(l - r->layers, vlist, VIA, via);
-			r->bboxes = g_slist_prepend(r->bboxes, bbox);
-			insert_constraints_from_list(r, l, vlist, bbox);
-			g_list_free(vlist);
-			bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox));
-
-		}
-		else if (PCB_FLAG_TEST(PCB_FLAG_OCTAGON, via)) {
-			/* TODO: Handle octagon vias */
-			fprintf(stderr, "No support for octagon vias yet\n");
-		}
-		else {
-
-			vlist = rect_with_attachments(pin_rad((pcb_pin_t *) via),
-																		x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers);
-			bbox = toporouter_bbox_create(l - r->layers, vlist, VIA, via);
-			r->bboxes = g_slist_prepend(r->bboxes, bbox);
-			g_list_free(vlist);
-
-			bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox));
-
-		}
-	}
-	PCB_END_LOOP;
-	return 0;
-}
-
-/*
- * Read line data from layer into toporouter_layer_t struct
- *
- * Inserts points and constraints into GLists
- */
-int read_lines(toporouter_t * r, toporouter_layer_t * l, pcb_layer_t * layer, int ln)
-{
-	gdouble xs[2], ys[2];
-
-	GList *vlist = NULL;
-	toporouter_bbox_t *bbox = NULL;
-
-	GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class());
-
-	PCB_LINE_LOOP(layer);
-	{
-		xs[0] = line->Point1.X;
-		xs[1] = line->Point2.X;
-		ys[0] = line->Point1.Y;
-		ys[1] = line->Point2.Y;
-		if (!(xs[0] == xs[1] && ys[0] == ys[1])) {
-			vlist = g_list_prepend(NULL, gts_vertex_new(vertex_class, xs[0], ys[0], l - r->layers));
-			vlist = g_list_prepend(vlist, gts_vertex_new(vertex_class, xs[1], ys[1], l - r->layers));
-			/* TODO: replace this with surface version */
-			bbox = toporouter_bbox_create_from_points(pcb_layer_get_group(ln), vlist, LINE, line);
-			r->bboxes = g_slist_prepend(r->bboxes, bbox);
-			/*new;;
-			   //insert_constraints_from_list(r, l, vlist, bbox); */
-			g_list_free(vlist);
-/*      bbox->point = GTS_POINT( insert_vertex(r, l, (xs[0]+xs[1])/2., (ys[0]+ys[1])/2., bbox) );*/
-
-			bbox->constraints =
-				g_list_concat(bbox->constraints, insert_constraint_edge(r, l, xs[0], ys[0], 0, xs[1], ys[1], 0, bbox));
-		}
-	}
-	PCB_END_LOOP;
-
-	return 0;
-}
-
-void create_board_edge(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble max, gint layer, GList ** vlist)
-{
-	GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class());
-	gdouble d = sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2));
-	guint n = d / max, count = 1;
-	gdouble inc = n ? d / n : d;
-	gdouble x = x0, y = y0;
-
-	*vlist = g_list_prepend(*vlist, gts_vertex_new(vertex_class, x0, y0, layer));
-
-	while (count < n) {
-		coord_move_towards_coord_values(x0, y0, x1, y1, inc, &x, &y);
-		*vlist = g_list_prepend(*vlist, gts_vertex_new(vertex_class, x, y, layer));
-
-		x0 = x;
-		y0 = y;
-		count++;
-	}
-
-}
-
-
-int read_board_constraints(toporouter_t * r, toporouter_layer_t * l, int layer)
-{
-/*  GtsVertexClass *vertex_class = GTS_VERTEX_CLASS (toporouter_vertex_class ());*/
-	GList *vlist = NULL;
-	toporouter_bbox_t *bbox = NULL;
-
-	/* Add points for corners of board, and constrain those edges */
-/*  vlist = g_list_prepend(NULL, gts_vertex_new (vertex_class, 0., 0., layer));
-    vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, PCB->MaxWidth, 0., layer));
-    vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, PCB->MaxWidth, PCB->MaxHeight, layer));
-    vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, 0., PCB->MaxHeight, layer));*/
-
-	create_board_edge(0., 0., PCB->MaxWidth, 0., 10000., layer, &vlist);
-	create_board_edge(PCB->MaxWidth, 0., PCB->MaxWidth, PCB->MaxHeight, 10000., layer, &vlist);
-	create_board_edge(PCB->MaxWidth, PCB->MaxHeight, 0., PCB->MaxHeight, 10000., layer, &vlist);
-	create_board_edge(0., PCB->MaxHeight, 0., 0., 10000., layer, &vlist);
-
-	bbox = toporouter_bbox_create(layer, vlist, BOARD, NULL);
-	r->bboxes = g_slist_prepend(r->bboxes, bbox);
-	insert_constraints_from_list(r, l, vlist, bbox);
-	g_list_free(vlist);
-
-	return 0;
-}
-
-gdouble triangle_cost(GtsTriangle * t, gpointer * data)
-{
-
-	gdouble *min_quality = (gdouble *) data[0];
-	gdouble *max_area = (gdouble *) data[1];
-	gdouble quality = gts_triangle_quality(t);
-	gdouble area = gts_triangle_area(t);
-
-	if (quality < *min_quality || area > *max_area)
-		return quality;
-	return 0.0;
-}
-
-
-void print_constraint(toporouter_constraint_t * e)
-{
-	printf("CONSTRAINT:\n");
-	print_vertex(tedge_v1(e));
-	print_vertex(tedge_v2(e));
-}
-
-void print_edge(toporouter_edge_t * e)
-{
-	GList *i = edge_routing(e);
-
-	printf("EDGE:\n");
-
-	print_vertex(tedge_v1(e));
-
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-		print_vertex(v);
-		i = i->next;
-	}
-
-	print_vertex(tedge_v2(e));
-}
-
-static void pick_first_face(GtsFace * f, GtsFace ** first)
-{
-	if (*first == NULL)
-		*first = f;
-}
-
-void unconstrain(toporouter_layer_t * l, toporouter_constraint_t * c)
-{
-	toporouter_edge_t *e;
-
-	gts_allow_floating_vertices = TRUE;
-	e = TOPOROUTER_EDGE(gts_edge_new(GTS_EDGE_CLASS(toporouter_edge_class()), GTS_SEGMENT(c)->v1, GTS_SEGMENT(c)->v2));
-	gts_edge_replace(GTS_EDGE(c), GTS_EDGE(e));
-	l->constraints = g_list_remove(l->constraints, c);
-	c->box->constraints = g_list_remove(c->box->constraints, c);
-	c->box = NULL;
-	gts_object_destroy(GTS_OBJECT(c));
-	gts_allow_floating_vertices = FALSE;
-}
-
-void build_cdt(toporouter_t * r, toporouter_layer_t * l)
-{
-	/* TODO: generalize into surface *cdt_create(vertices, constraints) */
-	GList *i;
-	/*GtsEdge *temp;
-	   GtsVertex *v; */
-	GtsTriangle *t;
-	GtsVertex *v1, *v2, *v3;
-	GSList *vertices_slist;
-
-	vertices_slist = list_to_slist(l->vertices);
-
-	if (l->surface) {
-		GtsFace *first = NULL;
-		gts_surface_foreach_face(l->surface, (GtsFunc) pick_first_face, &first);
-		gts_surface_traverse_destroy(gts_surface_traverse_new(l->surface, first));
-	}
-
-	t = gts_triangle_enclosing(gts_triangle_class(), vertices_slist, 1000.0f);
-	gts_triangle_vertices(t, &v1, &v2, &v3);
-
-	g_slist_free(vertices_slist);
-
-	l->surface = gts_surface_new(gts_surface_class(), gts_face_class(),
-															 GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX_CLASS(toporouter_vertex_class()));
-
-	gts_surface_add_face(l->surface, gts_face_new(gts_face_class(), t->e1, t->e2, t->e3));
-
-
-/*  fprintf(stderr, "ADDED VERTICES\n");*/
-/*
-  GtsFace *debugface;
-
-  if((debugface = gts_delaunay_check(l->surface))) {
-    fprintf(stderr, "WARNING: Delaunay check failed\n");
-    fprintf(stderr, "\tViolating triangle:\n");
-    fprintf(stderr, "\t%f,%f %f,%f\n",
-        debugface->triangle.e1->segment.v1->p.x,
-        debugface->triangle.e1->segment.v1->p.y,
-        debugface->triangle.e1->segment.v2->p.x,
-        debugface->triangle.e1->segment.v2->p.y
-        );
-    fprintf(stderr, "\t%f,%f %f,%f\n",
-        debugface->triangle.e2->segment.v1->p.x,
-        debugface->triangle.e2->segment.v1->p.y,
-        debugface->triangle.e2->segment.v2->p.x,
-        debugface->triangle.e2->segment.v2->p.y
-        );
-    fprintf(stderr, "\t%f,%f %f,%f\n",
-        debugface->triangle.e3->segment.v1->p.x,
-        debugface->triangle.e3->segment.v1->p.y,
-        debugface->triangle.e3->segment.v2->p.x,
-        debugface->triangle.e3->segment.v2->p.y
-        );
-/*    toporouter_draw_surface(r, l->surface, "debug.png", 4096, 4096); */
-	{
-		int i;
-		for (i = 0; i < groupcount(); i++) {
-			char buffer[256];
-			sprintf(buffer, "debug-%d.png", i);
-			toporouter_draw_surface(r, r->layers[i].surface, buffer, 2048, 2048, 2, NULL, i, NULL);
-		}
-	}
-
-/*  }*/
-
-check_cons_continuation:
-	i = l->constraints;
-	while (i) {
-		toporouter_constraint_t *c1 = TOPOROUTER_CONSTRAINT(i->data);
-		GList *j = i->next;
-		/* printf("adding cons: "); print_constraint(c1); */
-
-		while (j) {
-			toporouter_constraint_t *c2 = TOPOROUTER_CONSTRAINT(j->data);
-			guint rem = 0;
-			GList *temp;
-
-			/*  printf("\tconflict: "); print_constraint(c2); */
-			toporouter_bbox_t *c1box = c1->box, *c2box = c2->box;
-			toporouter_vertex_t *c1v1 = tedge_v1(c1);
-			toporouter_vertex_t *c1v2 = tedge_v2(c1);
-			toporouter_vertex_t *c2v1 = tedge_v1(c2);
-			toporouter_vertex_t *c2v2 = tedge_v2(c2);
-
-			if (gts_segments_are_intersecting(GTS_SEGMENT(c1), GTS_SEGMENT(c2)) == GTS_IN) {
-				toporouter_vertex_t *v;
-				unconstrain(l, c1);
-				unconstrain(l, c2);
-				rem = 1;
-				/* proper intersection */
-				v = TOPOROUTER_VERTEX(vertex_intersect(GTS_VERTEX(c1v1), GTS_VERTEX(c1v2), GTS_VERTEX(c2v1), GTS_VERTEX(c2v2)));
-
-				/* remove both constraints
-				   replace with 4x constraints
-				   insert new intersection vertex */
-				GTS_POINT(v)->z = vz(c1v1);
-
-				l->vertices = g_list_prepend(l->vertices, v);
-/*        gts_delaunay_add_vertex (l->surface, GTS_VERTEX(v), NULL); */
-
-				v->bbox = c1box;
-
-				temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(v), vy(v), 0, c1box);
-				c1box->constraints = g_list_concat(c1box->constraints, temp);
-
-				temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(v), vy(v), 0, c1box);
-				c1box->constraints = g_list_concat(c1box->constraints, temp);
-
-				temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(v), vy(v), 0, c2box);
-				c2box->constraints = g_list_concat(c2box->constraints, temp);
-
-				temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(v), vy(v), 0, c2box);
-				c2box->constraints = g_list_concat(c2box->constraints, temp);
-
-			}
-			else if (gts_segments_are_intersecting(GTS_SEGMENT(c1), GTS_SEGMENT(c2)) == GTS_ON ||
-							 gts_segments_are_intersecting(GTS_SEGMENT(c2), GTS_SEGMENT(c1)) == GTS_ON) {
-
-				if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v1(c1)) && vertex_between(edge_v1(c2), edge_v2(c2), edge_v2(c1))) {
-					unconstrain(l, c1);
-					unconstrain(l, c2);
-					rem = 1;
-					/* remove c1 */
-					temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box);
-					c2box->constraints = g_list_concat(c2box->constraints, temp);
-
-				}
-				else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2))) {
-					unconstrain(l, c1);
-					unconstrain(l, c2);
-					rem = 1;
-					/* remove c2 */
-					temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box);
-					c1box->constraints = g_list_concat(c1box->constraints, temp);
-
-					/*}else if(!vertex_wind(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && !vertex_wind(edge_v1(c1), edge_v2(c1), edge_v2(c2))) { */
-					/*     }else if(vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) || vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2))) {
-					   unconstrain(l, c1); unconstrain(l, c2); 
-					   rem = 1;
-					   printf("all colinear\n");
-					   //   exit(1);
-					   temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box);
-					   c1box->constraints = g_list_concat(c1box->constraints, temp);
-
-					   if(vertex_between(GTS_VERTEX(c1v1), GTS_VERTEX(c1v2), GTS_VERTEX(c2v2))) {
-					   // v2 of c2 is inner
-					   if(vertex_between(GTS_VERTEX(c2v1), GTS_VERTEX(c2v2), GTS_VERTEX(c1v2))) {
-					   // v2 of c1 is inner
-					   // c2 = c1.v2 -> c2.v1
-					   temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v1), vy(c2v1), 0, c2box);
-					   c2box->constraints = g_list_concat(c2box->constraints, temp);
-					   }else{
-					   // v1 of c1 is inner
-					   // c2 = c1.v1 -> c2.v1
-					   temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v1), vy(c2v1), 0, c2box);
-					   c2box->constraints = g_list_concat(c2box->constraints, temp);
-					   }
-					   }else{
-					   // v1 of c2 is inner
-					   if(vertex_between(GTS_VERTEX(c2v1), GTS_VERTEX(c2v2), GTS_VERTEX(c1v2))) {
-					   // v2 of c1 is inner
-					   // c2 = c1.v2 -> c2.v2
-					   temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v2), vy(c2v2), 0, c2box);
-					   c2box->constraints = g_list_concat(c2box->constraints, temp);
-					   }else{
-					   // v1 of c1 is inner
-					   // c2 = c1.v1 -> c2.v2
-					   temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v2), vy(c2v2), 0, c2box);
-					   c2box->constraints = g_list_concat(c2box->constraints, temp);
-					   }
-					   } */
-				}
-				else if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v1(c1)) && c1v1 != c2v1 && c1v1 != c2v2) {
-					unconstrain(l, c1);
-					unconstrain(l, c2);
-					rem = 1;
-					/*v1 of c1 is on c2 */
-					printf("v1 of c1 on c2\n");
-
-					/* replace with 2x constraints */
-					temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c1v1), vy(c1v1), 0, c2box);
-					c2box->constraints = g_list_concat(c2box->constraints, temp);
-					temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(c1v1), vy(c1v1), 0, c2box);
-					c2box->constraints = g_list_concat(c2box->constraints, temp);
-
-					temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box);
-					c1box->constraints = g_list_concat(c1box->constraints, temp);
-
-					/* restore c1
-					   temp = insert_constraint_edge(r, l, vx(tedge_v2(c1)), vy(tedge_v2(c1)), 0, vx(tedge_v1(c1)), vy(tedge_v1(c1)), 0, c1->box);
-					   c2->box->constraints = g_list_concat(c2->box->constraints, temp); */
-
-				}
-				else if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v2(c1)) && c1v2 != c2v1 && c1v2 != c2v2) {
-					unconstrain(l, c1);
-					unconstrain(l, c2);
-					rem = 1;
-					/*v2 of c1 is on c2 */
-					printf("v2 of c1 on c2\n");
-
-					/* replace with 2x constraints */
-					temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c1v2), vy(c1v2), 0, c2box);
-					c2box->constraints = g_list_concat(c2box->constraints, temp);
-					temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(c1v2), vy(c1v2), 0, c2box);
-					c2box->constraints = g_list_concat(c2box->constraints, temp);
-
-					temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box);
-					c1box->constraints = g_list_concat(c1box->constraints, temp);
-
-				}
-				else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && c2v1 != c1v1 && c2v1 != c1v2) {
-					unconstrain(l, c1);
-					unconstrain(l, c2);
-					rem = 1;
-					/*v1 of c2 is on c1 */
-					printf("v1 of c2 on c1\n");
-
-					/* replace with 2x constraints */
-					temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v1), vy(c2v1), 0, c1box);
-					c1box->constraints = g_list_concat(c1box->constraints, temp);
-					temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v1), vy(c2v1), 0, c1box);
-					c1box->constraints = g_list_concat(c1box->constraints, temp);
-
-					temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box);
-					c2box->constraints = g_list_concat(c2box->constraints, temp);
-				}
-				else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2)) && c2v2 != c1v1 && c2v2 != c1v2) {
-					unconstrain(l, c1);
-					unconstrain(l, c2);
-					rem = 1;
-					/*v2 of c2 is on c1 */
-					printf("v2 of c2 on c1\n");
-
-					/* replace with 2x constraints */
-					temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v2), vy(c2v2), 0, c1box);
-					c1box->constraints = g_list_concat(c1box->constraints, temp);
-					temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v2), vy(c2v2), 0, c1box);
-					c1box->constraints = g_list_concat(c1box->constraints, temp);
-
-					temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box);
-					c2box->constraints = g_list_concat(c2box->constraints, temp);
-				}
-			}
-			if (rem)
-				goto check_cons_continuation;
-
-			j = j->next;
-		}
-
-		i = i->next;
-	}
-
-	i = l->vertices;
-	while (i) {
-		/*v = i->data;
-		   if(r->flags & TOPOROUTER_FLAG_DEBUG_CDTS) 
-		   fprintf(stderr, "\tadding vertex %f,%f\n", v->p.x, v->p.y); */
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(gts_delaunay_add_vertex(l->surface, (GtsVertex *) i->data, NULL));
-		if (v) {
-			printf("conflict: ");
-			print_vertex(v);
-		}
-
-		i = i->next;
-	}
-	i = l->constraints;
-	while (i) {
-
-		/* toporouter_constraint_t *c1 = TOPOROUTER_CONSTRAINT(i->data);
-		   printf("adding cons: "); print_constraint(c1); */
-
-		GSList *conflicts = gts_delaunay_add_constraint(l->surface, (GtsConstraint *) i->data);
-		GSList *j = conflicts;
-		while (j) {
-			if (TOPOROUTER_IS_CONSTRAINT(j->data)) {
-				toporouter_constraint_t *c2 = TOPOROUTER_CONSTRAINT(j->data);
-
-				printf("\tconflict: ");
-				print_constraint(c2);
-
-			}
-			j = j->next;
-		}
-		g_slist_free(conflicts);
-
-		i = i->next;
-	}
-
-/*  if(rerun) 
-          goto build_cdt_continuation;
-    fprintf(stderr, "ADDED CONSTRAINTS\n");*/
-	gts_allow_floating_vertices = TRUE;
-	gts_object_destroy(GTS_OBJECT(v1));
-	gts_object_destroy(GTS_OBJECT(v2));
-	gts_object_destroy(GTS_OBJECT(v3));
-	gts_allow_floating_vertices = FALSE;
-
-/*
-  {
-    gpointer data[2];
-    gdouble quality = 0.50, area = G_MAXDOUBLE;
-    guint num = gts_delaunay_conform(l->surface, -1, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL);
-
-    if (num == 0){
-      data[0] = &quality;
-      data[1] = &area;
-      num = gts_delaunay_refine(l->surface, -1, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL, (GtsKeyFunc) triangle_cost, data);
-    }
-  }
-*/
-#ifdef DEBUG_IMPORT
-	gts_surface_print_stats(l->surface, stderr);
-#endif
-
-#if 0
-	{
-		char buffer[64];
-		FILE *fout2;
-		sprintf(buffer, "surface%d.gts", l - r->layers);
-		fout2 = fopen(buffer, "w");
-		gts_surface_write(l->surface, fout2);
-	}
-#endif
-
-}
-
-gint visited_cmp(gconstpointer a, gconstpointer b)
-{
-	if (a < b)
-		return -1;
-	if (a > b)
-		return 1;
-	return 0;
-}
-
-gdouble coord_xangle(gdouble ax, gdouble ay, gdouble bx, gdouble by)
-{
-	gdouble dx, dy, theta;
-
-	dx = fabs(ax - bx);
-	dy = fabs(ay - by);
-
-	if (dx < EPSILON) {
-		theta = M_PI / 2.;
-	}
-	else
-		theta = atan(dy / dx);
-
-	if (by <= ay) {
-		if (bx < ax)
-			theta = M_PI - theta;
-	}
-	else {
-		if (bx < ax)
-			theta += M_PI;
-		else
-			theta = (2 * M_PI) - theta;
-	}
-
-	return theta;
-}
-
-gdouble point_xangle(GtsPoint * a, GtsPoint * b)
-{
-	gdouble dx, dy, theta;
-
-	dx = fabs(a->x - b->x);
-	dy = fabs(a->y - b->y);
-
-	if (dx < EPSILON) {
-		theta = M_PI / 2.;
-	}
-	else
-		theta = atan(dy / dx);
-
-	if (b->y >= a->y) {
-		if (b->x < a->x)
-			theta = M_PI - theta;
-	}
-	else {
-		if (b->x < a->x)
-			theta += M_PI;
-		else
-			theta = (2 * M_PI) - theta;
-	}
-
-	return theta;
-}
-
-
-GList *cluster_vertices(toporouter_t * r, toporouter_cluster_t * c)
-{
-	GList *rval = NULL;
-
-	if (!c)
-		return NULL;
-
-	FOREACH_CLUSTER(c->netlist->clusters) {
-		if ((r->flags & TOPOROUTER_FLAG_AFTERRUBIX && cluster->c == c->c)
-				|| (!(r->flags & TOPOROUTER_FLAG_AFTERRUBIX) && cluster == c)) {
-			FOREACH_BBOX(cluster->boxes) {
-				if (box->type == LINE) {
-					g_assert(box->constraints->data);
-					rval = g_list_prepend(rval, tedge_v1(box->constraints->data));
-					rval = g_list_prepend(rval, tedge_v2(box->constraints->data));
-				}
-				else if (box->point) {
-					rval = g_list_prepend(rval, TOPOROUTER_VERTEX(box->point));
-					/*g_assert(vertex_bbox(TOPOROUTER_VERTEX(box->point)) == box); */
-				}
-				else {
-					printf("WARNING: cluster_vertices: unhandled bbox type\n");
-				}
-
-			}
-			FOREACH_END;
-
-
-		}
-
-	}
-	FOREACH_END;
-
-	return rval;
-}
-
-void print_cluster(toporouter_cluster_t * c)
-{
-
-	if (!c) {
-		printf("[CLUSTER (NULL)]\n");
-		return;
-	}
-
-	printf("CLUSTER %d: NETLIST = %s STYLE = %s\n", c->c, c->netlist->netlist, c->netlist->style);
-
-	FOREACH_BBOX(c->boxes) {
-		print_bbox(box);
-	}
-	FOREACH_END;
-}
-
-
-toporouter_cluster_t *cluster_create(toporouter_t * r, toporouter_netlist_t * netlist)
-{
-	toporouter_cluster_t *c = (toporouter_cluster_t *) malloc(sizeof(toporouter_cluster_t));
-
-	c->c = c->pc = netlist->clusters->len;
-	g_ptr_array_add(netlist->clusters, c);
-	c->netlist = netlist;
-	c->boxes = g_ptr_array_new();
-
-	return c;
-}
-
-toporouter_bbox_t *toporouter_bbox_locate(toporouter_t * r, toporouter_term_t type, void *data, gdouble x, gdouble y,
-																					guint layergroup)
-{
-	GtsPoint *p = gts_point_new(gts_point_class(), x, y, layergroup);
-	GSList *boxes = gts_bb_tree_stabbed(r->bboxtree, p), *i = boxes;
-
-	gts_object_destroy(GTS_OBJECT(p));
-
-	while (i) {
-		toporouter_bbox_t *box = TOPOROUTER_BBOX(i->data);
-
-		if (box->type == type && box->data == data) {
-			g_slist_free(boxes);
-			return box;
-		}
-
-		i = i->next;
-	}
-
-	g_slist_free(boxes);
-	return NULL;
-}
-
-void cluster_join_bbox(toporouter_cluster_t * cluster, toporouter_bbox_t * box)
-{
-	if (box) {
-		g_ptr_array_add(cluster->boxes, box);
-		box->cluster = cluster;
-	}
-}
-
-toporouter_netlist_t *netlist_create(toporouter_t * r, char *netlist, char *style)
-{
-	toporouter_netlist_t *nl = (toporouter_netlist_t *) malloc(sizeof(toporouter_netlist_t));
-	nl->netlist = netlist;
-	nl->style = style;
-	nl->clusters = g_ptr_array_new();
-	nl->routes = g_ptr_array_new();
-	nl->routed = NULL;
-	nl->pair = NULL;
-	g_ptr_array_add(r->netlists, nl);
-	return nl;
-}
-
-void import_clusters(toporouter_t * r)
-{
-	pcb_netlist_list_t nets;
-	pcb_reset_conns(pcb_false);
-	nets = pcb_rat_collect_subnets(pcb_false);
-	PCB_NETLIST_LOOP(&nets);
-	{
-		if (netlist->NetN > 0) {
-			toporouter_netlist_t *nl = netlist_create(r, netlist->Net->Connection->menu->Name, netlist->Net->Connection->menu->Style);
-
-			PCB_NET_LOOP(netlist);
-			{
-
-				toporouter_cluster_t *cluster = cluster_create(r, nl);
-#ifdef DEBUG_MERGING
-				printf("NET:\n");
-#endif
-				PCB_CONNECTION_LOOP(net);
-				{
-
-					if (connection->type == PCB_TYPE_LINE) {
-						pcb_line_t *line = (pcb_line_t *) connection->ptr2;
-						toporouter_bbox_t *box = toporouter_bbox_locate(r, LINE, line, connection->X, connection->Y, connection->group);
-						cluster_join_bbox(cluster, box);
-
-#ifdef DEBUG_MERGING
-						pcb_printf("\tLINE %#mD\n", connection->X, connection->Y);
-#endif
-					}
-					else if (connection->type == PCB_TYPE_PAD) {
-						pcb_pad_t *pad = (pcb_pad_t *) connection->ptr2;
-						toporouter_bbox_t *box = toporouter_bbox_locate(r, PAD, pad, connection->X, connection->Y, connection->group);
-						cluster_join_bbox(cluster, box);
-
-#ifdef DEBUG_MERGING
-						pcb_printf("\tPAD %#mD\n", connection->X, connection->Y);
-#endif
-					}
-					else if (connection->type == PCB_TYPE_PIN) {
-						guint m;
-						for (m = 0; m < groupcount(); m++) {
-							pcb_pin_t *pin = (pcb_pin_t *) connection->ptr2;
-							toporouter_bbox_t *box = toporouter_bbox_locate(r, PIN, pin, connection->X, connection->Y, m);
-							cluster_join_bbox(cluster, box);
-						}
-
-#ifdef DEBUG_MERGING
-						pcb_printf("\tPIN %#mD\n", connection->X, connection->Y);
-#endif
-					}
-					else if (connection->type == PCB_TYPE_VIA) {
-						guint m;
-						for (m = 0; m < groupcount(); m++) {
-							pcb_pin_t *pin = (pcb_pin_t *) connection->ptr2;
-							toporouter_bbox_t *box = toporouter_bbox_locate(r, VIA, pin, connection->X, connection->Y, m);
-							cluster_join_bbox(cluster, box);
-						}
-
-#ifdef DEBUG_MERGING
-						pcb_printf("\tVIA %#mD\n", connection->X, connection->Y);
-#endif
-					}
-					else if (connection->type == PCB_TYPE_POLYGON) {
-						pcb_polygon_t *polygon = (pcb_polygon_t *) connection->ptr2;
-						toporouter_bbox_t *box =
-							toporouter_bbox_locate(r, POLYGON, polygon, connection->X, connection->Y, connection->group);
-						cluster_join_bbox(cluster, box);
-
-#ifdef DEBUG_MERGING
-						pcb_printf("\tPOLYGON %#mD\n", connection->X, connection->Y);
-#endif
-
-					}
-				}
-				PCB_END_LOOP;
-#ifdef DEBUG_MERGING
-				printf("\n");
-#endif
-			}
-			PCB_END_LOOP;
-
-		}
-	}
-	PCB_END_LOOP;
-	pcb_netlist_list_free(&nets);
-}
-
-void import_geometry(toporouter_t * r)
-{
-	toporouter_layer_t *cur_layer;
-
-	int group;
-
-#ifdef DEBUG_IMPORT
-	for (group = 0; group < pcb_max_group; group++) {
-		printf("Group %d: Number %d:\n", group, PCB->LayerGroups.Number[group]);
-
-		for (int entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) {
-			printf("\tEntry %d\n", PCB->LayerGroups.Entries[group][entry]);
-		}
-	}
-#endif
-	/* Allocate space for per layer struct */
-	cur_layer = r->layers = (toporouter_layer_t *) malloc(groupcount() * sizeof(toporouter_layer_t));
-
-	/* Foreach layer, read in pad vertices and constraints, and build CDT */
-	for (group = 0; group < pcb_max_group; group++) {
-#ifdef DEBUG_IMPORT
-		printf("*** LAYER GROUP %d ***\n", group);
-#endif
-		if (PCB->LayerGroups.Number[group] > 0) {
-			cur_layer->vertices = NULL;
-			cur_layer->constraints = NULL;
-
-#ifdef DEBUG_IMPORT
-			printf("reading board constraints from layer %d into group %d\n", PCB->LayerGroups.Entries[group][0], group);
-#endif
-			read_board_constraints(r, cur_layer, PCB->LayerGroups.Entries[group][0]);
-#ifdef DEBUG_IMPORT
-			printf("reading points from layer %d into group %d \n", PCB->LayerGroups.Entries[group][0], group);
-#endif
-			read_points(r, cur_layer, PCB->LayerGroups.Entries[group][0]);
-
-/*#ifdef DEBUG_IMPORT    
-        printf("reading pads from layer %d into group %d\n", number, group);
-  #endif*/
-			read_pads(r, cur_layer, group);
-
-			GROUP_LOOP(PCB->Data, group) {
-
-#ifdef DEBUG_IMPORT
-				printf("reading lines from layer %d into group %d\n", number, group);
-#endif
-				read_lines(r, cur_layer, layer, number);
-
-			}
-			PCB_END_LOOP;
-
-
-
-#ifdef DEBUG_IMPORT
-			printf("building CDT\n");
-#endif
-			build_cdt(r, cur_layer);
-			printf("finished\n");
-/*      {
-    int i;
-    for(i=0;i<groupcount();i++) {
-      char buffer[256];
-      sprintf(buffer, "build%d.png", i);
-      toporouter_draw_surface(r, r->layers[i].surface, buffer, 2048, 2048, 2, NULL, i, NULL);
-    }
-  }*/
-#ifdef DEBUG_IMPORT
-			printf("finished building CDT\n");
-#endif
-			cur_layer++;
-		}
-	}
-
-	r->bboxtree = gts_bb_tree_new(r->bboxes);
-
-	import_clusters(r);
-
-#ifdef DEBUG_IMPORT
-	printf("finished import!\n");
-#endif
-}
-
-
-gint compare_points(gconstpointer a, gconstpointer b)
-{
-	GtsPoint *i = GTS_POINT(a);
-	GtsPoint *j = GTS_POINT(b);
-
-	if (i->x == j->x) {
-		if (i->y == j->y)
-			return 0;
-		if (i->y < j->y)
-			return -1;
-		return 1;
-	}
-	if (i->x < j->x)
-		return -1;
-	return 1;
-}
-
-gint compare_segments(gconstpointer a, gconstpointer b)
-{
-	if (a == b)
-		return 0;
-	if (a < b)
-		return -1;
-	return 1;
-}
-
-#define DEBUG_CLUSTER_FIND 1
-toporouter_cluster_t *cluster_find(toporouter_t * r, gdouble x, gdouble y, gdouble z)
-{
-	GtsPoint *p = gts_point_new(gts_point_class(), x, y, z);
-	GSList *hits = gts_bb_tree_stabbed(r->bboxtree, p);
-	toporouter_cluster_t *rval = NULL;
-
-#ifdef DEBUG_CLUSTER_FIND
-	printf("FINDING %f,%f,%f\n\n", x, y, z);
-#endif
-
-	while (hits) {
-		toporouter_bbox_t *box = TOPOROUTER_BBOX(hits->data);
-
-#ifdef DEBUG_CLUSTER_FIND
-		printf("HIT BOX: ");
-		print_bbox(box);
-#endif
-
-		if (box->layer == (int) z) {
-			if (box->type != BOARD) {
-				if (box->type == LINE) {
-					pcb_line_t *line = (pcb_line_t *) box->data;
-					gint linewind = coord_wind(line->Point1.X, line->Point1.Y, x, y, line->Point2.X, line->Point2.Y);
-
-					if (line->Point1.X > x - EPSILON && line->Point1.X < x + EPSILON &&
-							line->Point1.Y > y - EPSILON && line->Point1.Y < y + EPSILON) {
-						rval = box->cluster;
-						/*  break; */
-					}
-					if (line->Point2.X > x - EPSILON && line->Point2.X < x + EPSILON &&
-							line->Point2.Y > y - EPSILON && line->Point2.Y < y + EPSILON) {
-						rval = box->cluster;
-						/*  break; */
-					}
-					if (!linewind) {
-						rval = box->cluster;
-						/*  break; */
-					}
-
-				}
-				else if (box->surface) {
-
-					if (gts_point_locate(p, box->surface, NULL)) {
-						rval = box->cluster;
-						break;
-					}
-
-				}
-			}
-		}
-		hits = hits->next;
-	}
-
-	gts_object_destroy(GTS_OBJECT(p));
-
-
-#ifdef DEBUG_CLUSTER_FIND
-	printf("cluster_find: %f,%f,%f: ", x, y, z);
-	print_cluster(rval);
-#endif
-
-	return rval;
-}
-
-gdouble simple_h_cost(toporouter_t * r, toporouter_vertex_t * curpoint, toporouter_vertex_t * destpoint)
-{
-	gdouble layerpenalty = (vz(curpoint) == vz(destpoint)) ? 0. : r->viacost;
-
-	return gts_point_distance(GTS_POINT(curpoint), GTS_POINT(destpoint)) + layerpenalty;
-}
-
-#define FCOST(x) (x->gcost + x->hcost)
-gdouble route_heap_cmp(gpointer item, gpointer data)
-{
-	return FCOST(TOPOROUTER_VERTEX(item));
-}
-
-#define closelist_insert(p) closelist = g_list_prepend(closelist, p)
-
-typedef struct {
-	toporouter_vertex_t *key;
-	toporouter_vertex_t *result;
-} toporouter_heap_search_data_t;
-
-void toporouter_heap_search(gpointer data, gpointer user_data)
-{
-	toporouter_vertex_t *v = TOPOROUTER_VERTEX(data);
-	toporouter_heap_search_data_t *heap_search_data = (toporouter_heap_search_data_t *) user_data;
-	if (v == heap_search_data->key)
-		heap_search_data->result = v;
-}
-
-/*
-void 
-toporouter_heap_color(gpointer data, gpointer user_data)
-{
-  toporouter_vertex_t *v = TOPOROUTER_VERTEX(data);
-  v->flags |= (guint) user_data;
-}
-*/
-static inline gdouble angle_span(gdouble a1, gdouble a2)
-{
-	if (a1 > a2)
-		return ((2 * M_PI) - a1 + a2);
-	return a2 - a1;
-}
-
-gdouble region_span(toporouter_vertex_region_t * region)
-{
-	gdouble a1, a2;
-
-	g_assert(region->v1 != NULL);
-	g_assert(region->v2 != NULL);
-	g_assert(region->origin != NULL);
-
-	a1 = point_xangle(GTS_POINT(region->origin), GTS_POINT(region->v1));
-	a2 = point_xangle(GTS_POINT(region->origin), GTS_POINT(region->v2));
-
-	return angle_span(a1, a2);
-}
-
-gdouble edge_capacity(toporouter_edge_t * e)
-{
-	return gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e)));
-}
-
-gdouble edge_flow(toporouter_edge_t * e, toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_vertex_t * dest)
-{
-	GList *i = edge_routing(e);
-	toporouter_vertex_t *pv = tedge_v1(e), *v = NULL;
-	gdouble flow = 0.;
-	guint waiting = 1;
-
-	if ((pv == v1 || pv == v2) && waiting) {
-		flow += min_vertex_net_spacing(pv, dest);
-		pv = dest;
-		waiting = 0;
-	}
-
-	g_assert(v1 != v2);
-
-	while (i) {
-		v = TOPOROUTER_VERTEX(i->data);
-
-
-		if (pv == dest)
-			flow += min_vertex_net_spacing(v, pv);
-		else
-			flow += min_spacing(v, pv);
-
-		if ((v == v1 || v == v2) && waiting) {
-			flow += min_vertex_net_spacing(v, dest);
-			pv = dest;
-			waiting = 0;
-		}
-		else {
-			pv = v;
-		}
-		i = i->next;
-	}
-
-	if (pv == dest)
-		flow += min_vertex_net_spacing(tedge_v2(e), pv);
-	else
-		flow += min_spacing(tedge_v2(e), pv);
-
-	return flow;
-}
-
-void print_path(GList * path)
-{
-	GList *i = path;
-
-	printf("PATH:\n");
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-/*    printf("[V %f,%f,%f]\n", vx(v), vy(v), vz(v));*/
-		print_vertex(v);
-
-		if (v->child && !g_list_find(path, v->child))
-			printf("\t CHILD NOT IN LIST\n");
-		if (v->parent && !g_list_find(path, v->parent))
-			printf("\t parent NOT IN LIST\n");
-		i = i->next;
-	}
-
-
-}
-
-GList *split_path(GList * path)
-{
-	toporouter_vertex_t *pv = NULL;
-	GList *curpath = NULL, *i, *paths = NULL;
-#ifdef DEBUG_ROUTE
-	printf("PATH:\n");
-#endif
-	i = path;
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-
-#ifdef DEBUG_ROUTE
-		printf("v = %f,%f ", vx(v), vy(v));
-		if (v->parent)
-			printf("parent = %f,%f ", vx(v->parent), vy(v->parent));
-		if (v->child)
-			printf("child = %f,%f ", vx(v->child), vy(v->child));
-		printf("\n");
-#endif
-/*    printf("***\n");
-      if(v) printf("v = %f,%f\n", GTS_POINT(v)->x, GTS_POINT(v)->y);
-      if(pv) printf("pv = %f,%f\n", GTS_POINT(pv)->x, GTS_POINT(pv)->y);*/
-
-
-		if (pv)
-			if (GTS_POINT(v)->x == GTS_POINT(pv)->x && GTS_POINT(v)->y == GTS_POINT(pv)->y) {
-				if (g_list_length(curpath) > 1)
-					paths = g_list_prepend(paths, curpath);
-				curpath = NULL;
-
-				pv->child = NULL;
-				v->parent = NULL;
-			}
-
-		curpath = g_list_append(curpath, v);
-
-		pv = v;
-		i = i->next;
-	}
-
-	if (g_list_length(curpath) > 1)
-		paths = g_list_prepend(paths, curpath);
-
-	return paths;
-}
-
-
-
-#define edge_gradient(e) (cartesian_gradient(GTS_POINT(GTS_SEGMENT(e)->v1)->x, GTS_POINT(GTS_SEGMENT(e)->v1)->y, \
-    GTS_POINT(GTS_SEGMENT(e)->v2)->x, GTS_POINT(GTS_SEGMENT(e)->v2)->y))
-
-
-/* sorting into ascending distance from v1 */
-gint routing_edge_insert(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-	GtsPoint *v1 = GTS_POINT(edge_v1(user_data));
-
-	if (gts_point_distance2(v1, GTS_POINT(a)) < gts_point_distance2(v1, GTS_POINT(b)) - EPSILON)
-		return -1;
-	if (gts_point_distance2(v1, GTS_POINT(a)) > gts_point_distance2(v1, GTS_POINT(b)) + EPSILON)
-		return 1;
-/*
-  printf("a = %x b = %x\n", (int) a, (int) b);
-
-  printf("WARNING: routing_edge_insert() with same points..\n \
-      v1 @ %f,%f\n\
-      a  @ %f,%f\n\
-      b  @ %f,%f\n", 
-      v1->x, v1->y,
-      vx(a), vy(a),
-      vx(a), vy(b));
-  printf("A: "); print_vertex(TOPOROUTER_VERTEX(a));
-  printf("B: "); print_vertex(TOPOROUTER_VERTEX(b));
-
-  TOPOROUTER_VERTEX(a)->flags |= VERTEX_FLAG_RED;
-  TOPOROUTER_VERTEX(b)->flags |= VERTEX_FLAG_RED;
-*/
-	return 0;
-}
-
-
-toporouter_vertex_t *new_temp_toporoutervertex(gdouble x, gdouble y, toporouter_edge_t * e)
-{
-	GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class());
-	GList *i = edge_routing(e);
-	toporouter_vertex_t *r;
-
-	while (i) {
-		r = TOPOROUTER_VERTEX(i->data);
-		if (epsilon_equals(vx(r), x) && epsilon_equals(vy(r), y)) {
-			if (r->flags & VERTEX_FLAG_TEMP)
-				return r;
-		}
-		i = i->next;
-	}
-
-	r = TOPOROUTER_VERTEX(gts_vertex_new(vertex_class, x, y, vz(edge_v1(e))));
-	r->flags |= VERTEX_FLAG_TEMP;
-	r->routingedge = e;
-
-	if (TOPOROUTER_IS_CONSTRAINT(e))
-		TOPOROUTER_CONSTRAINT(e)->routing = g_list_insert_sorted_with_data(edge_routing(e), r, routing_edge_insert, e);
-	else
-		e->routing = g_list_insert_sorted_with_data(edge_routing(e), r, routing_edge_insert, e);
-
-	return r;
-}
-
-
-/* create vertex on edge e at radius r from v, closest to ref */
-toporouter_vertex_t *new_temp_toporoutervertex_in_segment(toporouter_edge_t * e, toporouter_vertex_t * v, gdouble r,
-																													toporouter_vertex_t * ref)
-{
-	gdouble m = edge_gradient(e);
-	toporouter_spoint_t p, np1, np2;
-/*  toporouter_vertex_t *b = TOPOROUTER_VERTEX((GTS_VERTEX(v) == edge_v1(e)) ? edge_v2(e) : edge_v1(e)); */
-	toporouter_vertex_t *rval = NULL;
-	p.x = vx(v);
-	p.y = vy(v);
-
-	vertices_on_line(&p, m, r, &np1, &np2);
-
-	if ((pow(np1.x - vx(ref), 2) + pow(np1.y - vy(ref), 2)) < (pow(np2.x - vx(ref), 2) + pow(np2.y - vy(ref), 2)))
-		rval = new_temp_toporoutervertex(np1.x, np1.y, e);
-	else
-		rval = new_temp_toporoutervertex(np2.x, np2.y, e);
-
-	return rval;
-}
-
-gint vertex_keepout_test(toporouter_t * r, toporouter_vertex_t * v)
-{
-	GList *i = r->keepoutlayers;
-	while (i) {
-		gdouble keepout = *((double *) i->data);
-		if (vz(v) == keepout)
-			return 1;
-		i = i->next;
-	}
-	return 0;
-}
-
-void
-closest_cluster_pair(toporouter_t * r, GList * src_vertices, GList * dest_vertices, toporouter_vertex_t ** a,
-										 toporouter_vertex_t ** b)
-{
-	GList *i = src_vertices, *j = dest_vertices;
-
-	gdouble min = 0.;
-	*a = NULL;
-	*b = NULL;
-
-	i = src_vertices;
-	while (i) {
-		toporouter_vertex_t *v1 = TOPOROUTER_VERTEX(i->data);
-
-		if (vertex_keepout_test(r, v1)) {
-			i = i->next;
-			continue;
-		}
-
-		j = dest_vertices;
-		while (j) {
-			toporouter_vertex_t *v2 = TOPOROUTER_VERTEX(j->data);
-			if (vertex_keepout_test(r, v2) || vz(v2) != vz(v1)) {
-				j = j->next;
-				continue;
-			}
-
-			if (!*a) {
-				*a = v1;
-				*b = v2;
-				min = simple_h_cost(r, *a, *b);
-			}
-			else {
-				gdouble tempd = simple_h_cost(r, v1, v2);
-				if (r->flags & TOPOROUTER_FLAG_GOFAR && tempd > min) {
-					*a = v1;
-					*b = v2;
-					min = tempd;
-				}
-				else if (tempd < min) {
-					*a = v1;
-					*b = v2;
-					min = tempd;
-				}
-			}
-
-			j = j->next;
-		}
-
-		i = i->next;
-	}
-
-/*  g_list_free(src_vertices);
-    g_list_free(dest_vertices);*/
-}
-
-
-toporouter_vertex_t *closest_dest_vertex(toporouter_t * r, toporouter_vertex_t * v, toporouter_route_t * routedata)
-{
-	GList													/* *vertices = cluster_vertices(r, routedata->dest),  */
-		* i = routedata->destvertices;
-	toporouter_vertex_t *closest = NULL;
-	gdouble closest_distance = 0.;
-
-/*  if(routedata->flags & TOPOROUTER_FLAG_FLEX) i = r->destboxes; */
-
-	while (i) {
-		toporouter_vertex_t *cv = TOPOROUTER_VERTEX(i->data);
-
-		if (vz(cv) != vz(v)) {
-			i = i->next;
-			continue;
-		}
-
-		if (!closest) {
-			closest = cv;
-			closest_distance = simple_h_cost(r, v, closest);
-		}
-		else {
-			gdouble tempd = simple_h_cost(r, v, cv);
-			if (r->flags & TOPOROUTER_FLAG_GOFAR && tempd > closest_distance) {
-				closest = cv;
-				closest_distance = tempd;
-			}
-			else if (tempd < closest_distance) {
-				closest = cv;
-				closest_distance = tempd;
-			}
-		}
-		i = i->next;
-	}
-
-/*  g_list_free(vertices); */
-
-#ifdef DEBUG_ROUTE
-	printf("CLOSEST = %f,%f,%f\n", vx(closest), vy(closest), vz(closest));
-#endif
-	return closest;
-}
-
-#define toporouter_edge_gradient(e) (cartesian_gradient(vx(edge_v1(e)), vy(edge_v1(e)), vx(edge_v2(e)), vy(edge_v2(e))))
-
-
-/* returns the capacity of the triangle cut through v */
-gdouble triangle_interior_capacity(GtsTriangle * t, toporouter_vertex_t * v)
-{
-	toporouter_edge_t *e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v)));
-	gdouble x, y, m1, m2, c2, c1;
-#ifdef DEBUG_ROUTE
-	gdouble len;
-#endif
-
-	g_assert(e);
-
-	m1 = toporouter_edge_gradient(e);
-	m2 = perpendicular_gradient(m1);
-	c2 = (isinf(m2)) ? vx(v) : vy(v) - (m2 * vx(v));
-	c1 = (isinf(m1)) ? vx(edge_v1(e)) : vy(edge_v1(e)) - (m1 * vx(edge_v1(e)));
-
-	if (isinf(m2))
-		x = vx(v);
-	else if (isinf(m1))
-		x = vx(edge_v1(e));
-	else
-		x = (c2 - c1) / (m1 - m2);
-
-	y = (isinf(m2)) ? vy(edge_v1(e)) : (m2 * x) + c2;
-
-#ifdef DEBUG_ROUTE
-	len = gts_point_distance2(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e)));
-	printf("%f,%f len = %f v = %f,%f\n", x, y, len, vx(v), vy(v));
-#endif
-
-	if (epsilon_equals(x, vx(edge_v1(e))) && epsilon_equals(y, vy(edge_v1(e))))
-		return INFINITY;
-	if (epsilon_equals(x, vx(edge_v2(e))) && epsilon_equals(y, vy(edge_v2(e))))
-		return INFINITY;
-
-	if (x >= MIN(vx(edge_v1(e)), vx(edge_v2(e))) &&
-			x <= MAX(vx(edge_v1(e)), vx(edge_v2(e))) &&
-			y >= MIN(vy(edge_v1(e)), vy(edge_v2(e))) && y <= MAX(vy(edge_v1(e)), vy(edge_v2(e))))
-
-/*  if( (pow(vx(edge_v1(e)) - x, 2) + pow(vy(edge_v1(e)) - y, 2)) < len && (pow(vx(edge_v2(e)) - x, 2) + pow(vy(edge_v2(e)) - y, 2)) < len ) */
-		return sqrt(pow(vx(v) - x, 2) + pow(vy(v) - y, 2));
-
-	return INFINITY;
-}
-
-static inline toporouter_vertex_t *segment_common_vertex(GtsSegment * s1, GtsSegment * s2)
-{
-	if (!s1 || !s2)
-		return NULL;
-	if (s1->v1 == s2->v1)
-		return TOPOROUTER_VERTEX(s1->v1);
-	if (s1->v2 == s2->v1)
-		return TOPOROUTER_VERTEX(s1->v2);
-	if (s1->v1 == s2->v2)
-		return TOPOROUTER_VERTEX(s1->v1);
-	if (s1->v2 == s2->v2)
-		return TOPOROUTER_VERTEX(s1->v2);
-	return NULL;
-}
-
-static inline toporouter_vertex_t *route_vertices_common_vertex(toporouter_vertex_t * v1, toporouter_vertex_t * v2)
-{
-	return segment_common_vertex(GTS_SEGMENT(v1->routingedge), GTS_SEGMENT(v2->routingedge));
-}
-
-
-static inline guint edges_third_edge(GtsSegment * s1, GtsSegment * s2, toporouter_vertex_t ** v1, toporouter_vertex_t ** v2)
-{
-	if (!s1 || !s2)
-		return 0;
-	if (s1->v1 == s2->v1) {
-		*v1 = TOPOROUTER_VERTEX(s1->v2);
-		*v2 = TOPOROUTER_VERTEX(s2->v2);
-		return 1;
-	}
-	if (s1->v2 == s2->v1) {
-		*v1 = TOPOROUTER_VERTEX(s1->v1);
-		*v2 = TOPOROUTER_VERTEX(s2->v2);
-		return 1;
-	}
-	if (s1->v1 == s2->v2) {
-		*v1 = TOPOROUTER_VERTEX(s1->v2);
-		*v2 = TOPOROUTER_VERTEX(s2->v1);
-		return 1;
-	}
-	if (s1->v2 == s2->v2) {
-		*v1 = TOPOROUTER_VERTEX(s1->v1);
-		*v2 = TOPOROUTER_VERTEX(s2->v1);
-		return 1;
-	}
-	return 0;
-}
-
-/* returns the flow from e1 to e2, and the flow from the vertex oppisate e1 to
- * e1 and the vertex oppisate e2 to e2 */
-gdouble
-flow_from_edge_to_edge(GtsTriangle * t, toporouter_edge_t * e1, toporouter_edge_t * e2,
-											 toporouter_vertex_t * common_v, toporouter_vertex_t * curpoint)
-{
-	gdouble r = 0.;
-	toporouter_vertex_t *pv = common_v, *v;
-	toporouter_edge_t *op_edge;
-
-	GList *i = edge_routing(e1);
-	while (i) {
-		v = TOPOROUTER_VERTEX(i->data);
-
-		if (v == curpoint) {
-			r += min_spacing(v, pv);
-			pv = v;
-			i = i->next;
-			continue;
-		}
-/*    if(!(v->flags & VERTEX_FLAG_TEMP)) { */
-		if ((v->flags & VERTEX_FLAG_ROUTE)) {
-			if (v->parent)
-				if (v->parent->routingedge == e2) {
-					r += min_spacing(v, pv);
-					pv = v;
-					i = i->next;
-					continue;
-				}
-
-			if (v->child)
-				if (v->child->routingedge == e2) {
-					r += min_spacing(v, pv);
-					pv = v;
-					i = i->next;
-					continue;
-				}
-		}
-		i = i->next;
-	}
-
-	op_edge = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(common_v)));
-
-	g_assert(op_edge);
-	g_assert(e1);
-	g_assert(e2);
-
-	v = segment_common_vertex(GTS_SEGMENT(e2), GTS_SEGMENT(op_edge));
-	g_assert(v);
-
-	/*v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e1))); */
-	if (v->flags & VERTEX_FLAG_ROUTE && v->parent && v->parent->routingedge) {
-		if (v->parent->routingedge == e1)
-			r += min_spacing(v, pv);
-	}
-
-	v = segment_common_vertex(GTS_SEGMENT(e1), GTS_SEGMENT(op_edge));
-	g_assert(v);
-
-	/*v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e2))); */
-	if (v->flags & VERTEX_FLAG_ROUTE && v->parent && v->parent->routingedge) {
-		if (v->parent->routingedge == e1)
-			r += min_spacing(v, pv);
-	}
-
-	if (TOPOROUTER_IS_CONSTRAINT(op_edge)) {
-		toporouter_bbox_t *box = vertex_bbox(TOPOROUTER_VERTEX(edge_v1(op_edge)));
-		r += vertex_net_thickness(v) / 2.;
-		if (box) {
-			r += MAX(vertex_net_clearance(v), cluster_clearance(box->cluster));
-			r += cluster_thickness(box->cluster) / 2.;
-		}
-		else {
-			r += vertex_net_clearance(v);
-
-		}
-	}
-
-	return r;
-}
-
-
-
-guint
-check_triangle_interior_capacity(GtsTriangle * t, toporouter_vertex_t * v, toporouter_vertex_t * curpoint,
-																 toporouter_edge_t * op_edge, toporouter_edge_t * adj_edge1, toporouter_edge_t * adj_edge2)
-{
-	gdouble ic = triangle_interior_capacity(t, v);
-	gdouble flow = flow_from_edge_to_edge(t, adj_edge1, adj_edge2, v, curpoint);
-
-	if (TOPOROUTER_IS_CONSTRAINT(adj_edge1) || TOPOROUTER_IS_CONSTRAINT(adj_edge2))
-		return 1;
-
-
-	if (flow > ic) {
-#ifdef DEBUG_ROUTE
-		printf("fail interior capacity flow = %f ic = %f\n", flow, ic);
-#endif
-		return 0;
-	}
-
-	return 1;
-}
-
-toporouter_vertex_t *edge_routing_next_not_temp(toporouter_edge_t * e, GList * list)
-{
-	if (!TOPOROUTER_IS_CONSTRAINT(e)) {
-		while (list) {
-			toporouter_vertex_t *v = TOPOROUTER_VERTEX(list->data);
-			if (!(v->flags & VERTEX_FLAG_TEMP))
-				return v;
-
-			list = list->next;
-		}
-	}
-	return tedge_v2(e);
-}
-
-toporouter_vertex_t *edge_routing_prev_not_temp(toporouter_edge_t * e, GList * list)
-{
-	if (!TOPOROUTER_IS_CONSTRAINT(e)) {
-		while (list) {
-			toporouter_vertex_t *v = TOPOROUTER_VERTEX(list->data);
-			if (!(v->flags & VERTEX_FLAG_TEMP))
-				return v;
-
-			list = list->prev;
-		}
-	}
-	return tedge_v1(e);
-}
-
-void
-edge_adjacent_vertices(toporouter_edge_t * e, toporouter_vertex_t * v, toporouter_vertex_t ** v1, toporouter_vertex_t ** v2)
-{
-	GList *r = g_list_find(edge_routing(e), v);
-
-	if (v == tedge_v1(e)) {
-		*v1 = NULL;
-		*v2 = edge_routing_next_not_temp(e, edge_routing(e));
-	}
-	else if (v == tedge_v2(e)) {
-		*v1 = edge_routing_prev_not_temp(e, g_list_last(edge_routing(e)));
-		*v2 = NULL;
-	}
-	else {
-/*    r = g_list_find(r, v);*/
-		*v1 = edge_routing_prev_not_temp(e, r);
-		*v2 = edge_routing_next_not_temp(e, r);
-
-	}
-
-}
-
-
-GList *candidate_vertices(toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_vertex_t * dest, toporouter_edge_t * e)
-{
-	gdouble totald, v1ms, v2ms, flow, capacity, ms;
-	GList *vs = NULL;
-
-	g_assert(v1);
-	g_assert(v2);
-	g_assert(dest);
-
-	g_assert(!(v1->flags & VERTEX_FLAG_TEMP));
-	g_assert(!(v2->flags & VERTEX_FLAG_TEMP));
-#ifdef DEBUG_ROUTE
-	printf("starting candidate vertices\n");
-	printf("v1 = %f,%f v2 = %f,%f dest = %f,%f\n", vx(v1), vy(v1), vx(v2), vy(v2), vx(dest), vy(dest));
-#endif
-	totald = gts_point_distance(GTS_POINT(v1), GTS_POINT(v2));
-	v1ms = min_spacing(v1, dest);
-	v2ms = min_spacing(v2, dest);
-	ms = min_spacing(dest, dest);
-	flow = TOPOROUTER_IS_CONSTRAINT(e) ? 0. : edge_flow(e, v1, v2, dest);
-	capacity = edge_capacity(e);
-
-#ifdef DEBUG_ROUTE
-	g_assert(totald > 0);
-
-	printf("v1ms = %f v2ms = %f totald = %f ms = %f capacity = %f flow = %f\n", v1ms, v2ms, totald, ms, capacity, flow);
-#endif
-
-	if (flow >= capacity)
-		return NULL;
-
-
-	if (v1ms + v2ms + ms >= totald) {
-		vs = g_list_prepend(vs, new_temp_toporoutervertex((vx(v1) + vx(v2)) / 2., (vy(v1) + vy(v2)) / 2., e));
-	}
-	else {
-		gdouble x0, y0, x1, y1, d;
-
-		vertex_move_towards_vertex_values(GTS_VERTEX(v1), GTS_VERTEX(v2), v1ms, &x0, &y0);
-
-		vs = g_list_prepend(vs, new_temp_toporoutervertex(x0, y0, e));
-
-		vertex_move_towards_vertex_values(GTS_VERTEX(v2), GTS_VERTEX(v1), v2ms, &x1, &y1);
-
-		vs = g_list_prepend(vs, new_temp_toporoutervertex(x1, y1, e));
-
-		d = sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2));
-
-		if (ms < d) {
-/*      guint nint = d / ms;
-        gdouble dif = d / (nint + 1); */
-			gdouble dif = d / 2;
-
-/*      for(guint j=0;j<nint;j++) {*/
-			gdouble x, y;
-
-/*        coord_move_towards_coord_values(x0, y0, x1, y1, dif * j, &x, &y);*/
-			coord_move_towards_coord_values(x0, y0, x1, y1, dif, &x, &y);
-
-			vs = g_list_prepend(vs, new_temp_toporoutervertex(x, y, e));
-
-/*      } */
-
-		}
-
-	}
-#ifdef DEBUG_ROUTE
-	printf("candidate vertices returning %d\n", g_list_length(vs));
-#endif
-	return vs;
-}
-
-GList *edge_routing_first_not_temp(toporouter_edge_t * e)
-{
-	GList *i = edge_routing(e);
-	toporouter_vertex_t *v;
-
-	while (i) {
-		v = TOPOROUTER_VERTEX(i->data);
-		if (!(v->flags & VERTEX_FLAG_TEMP))
-			return i;
-
-		i = i->next;
-	}
-
-	return NULL;
-}
-
-GList *edge_routing_last_not_temp(toporouter_edge_t * e)
-{
-	GList *i = edge_routing(e), *last = NULL;
-	toporouter_vertex_t *v;
-
-	while (i) {
-		v = TOPOROUTER_VERTEX(i->data);
-		if (!(v->flags & VERTEX_FLAG_TEMP))
-			last = i;
-
-		i = i->next;
-	}
-
-	return last;
-}
-
-void delete_vertex(toporouter_vertex_t * v)
-{
-
-	if (v->flags & VERTEX_FLAG_TEMP) {
-		if (v->routingedge) {
-			if (TOPOROUTER_IS_CONSTRAINT(v->routingedge))
-				TOPOROUTER_CONSTRAINT(v->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v);
-			else
-				v->routingedge->routing = g_list_remove(v->routingedge->routing, v);
-		}
-
-		gts_object_destroy(GTS_OBJECT(v));
-	}
-}
-
-#define edge_is_blocked(e) (TOPOROUTER_IS_EDGE(e) ? (e->flags & EDGE_FLAG_DIRECTCONNECTION) : 0)
-
-GList *triangle_candidate_points_from_vertex(GtsTriangle * t, toporouter_vertex_t * v, toporouter_vertex_t * dest,
-																						 toporouter_route_t * routedata)
-{
-	toporouter_edge_t *op_e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v)));
-	toporouter_vertex_t *vv1, *vv2, *constraintv = NULL;
-	toporouter_edge_t *e1, *e2;
-	GList *i;
-	GList *rval = NULL;
-
-#ifdef DEBUG_ROUTE
-	printf("\tTRIANGLE CAND POINT FROM VERTEX\n");
-
-	g_assert(op_e);
-#endif
-
-	e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), edge_v1(op_e)));
-	e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), edge_v2(op_e)));
-
-
-	if (TOPOROUTER_IS_CONSTRAINT(op_e)) {
-		if (TOPOROUTER_CONSTRAINT(op_e)->box->type == BOARD) {
-#ifdef DEBUG_ROUTE
-			printf("BOARD constraint\n");
-#endif
-			return NULL;
-		}
-		if (constraint_netlist(TOPOROUTER_CONSTRAINT(op_e)) != vertex_netlist(dest)) {	/* || TOPOROUTER_CONSTRAINT(op_e)->routing) { */
-#ifdef DEBUG_ROUTE
-			printf("op_e routing:\n");
-			print_edge(op_e);
-#endif
-			return NULL;
-		}
-#ifdef DEBUG_ROUTE
-		printf("RETURNING CONSTRAINT POING\n");
-#endif
-		constraintv = new_temp_toporoutervertex_in_segment(op_e, TOPOROUTER_VERTEX(edge_v1(op_e)),
-																											 gts_point_distance(GTS_POINT(edge_v1(op_e)),
-																																					GTS_POINT(edge_v2(op_e))) / 2.,
-																											 TOPOROUTER_VERTEX(edge_v2(op_e)));
-/*    return g_list_prepend(NULL, vv1); */
-
-
-	}
-
-	if (edge_is_blocked(op_e)) {
-		goto triangle_candidate_points_from_vertex_exit;
-	}
-/*  v1 = tedge_v1(op_e); 
-    v2 = tedge_v2(op_e);*/
-
-	if (v == tedge_v1(e1)) {
-		i = edge_routing_first_not_temp(e1);
-	}
-	else {
-		i = edge_routing_last_not_temp(e1);
-	}
-
-	if (i) {
-		toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data);
-
-		if (temp->parent == tedge_v2(op_e) || temp->child == tedge_v2(op_e)) {
-#ifdef DEBUG_ROUTE
-			printf("temp -> op_e->v2\n");
-#endif
-			goto triangle_candidate_points_from_vertex_exit;
-		}
-		if (temp->parent->routingedge == op_e) {
-			vv1 = temp->parent;
-#ifdef DEBUG_ROUTE
-			printf("vv1->parent\n");
-#endif
-
-		}
-		else if (temp->child->routingedge == op_e) {
-			vv1 = temp->child;
-#ifdef DEBUG_ROUTE
-			printf("vv1->child\n");
-#endif
-
-		}
-		else {
-			/* must be to e2 */
-#ifdef DEBUG_ROUTE
-			printf("temp -> e2?\n");
-			printf("op_e = %f,%f\t\t%f,%f\n", vx(edge_v1(op_e)), vy(edge_v1(op_e)), vx(edge_v2(op_e)), vy(edge_v2(op_e)));
-			if (temp->parent->routingedge)
-				printf("temp->parent->routingedge = %f,%f \t\t %f,%f\n",
-							 vx(edge_v1(temp->parent->routingedge)), vy(edge_v1(temp->parent->routingedge)),
-							 vx(edge_v2(temp->parent->routingedge)), vy(edge_v2(temp->parent->routingedge))
-					);
-			else
-				printf("temp->parent->routingedge = NULL\n");
-
-			if (temp->child->routingedge)
-				printf("temp->child->routingedge = %f,%f \t\t %f,%f\n",
-							 vx(edge_v1(temp->child->routingedge)), vy(edge_v1(temp->child->routingedge)),
-							 vx(edge_v2(temp->child->routingedge)), vy(edge_v2(temp->child->routingedge))
-					);
-			else
-				printf("temp->child->routingedge = NULL\n");
-#endif
-			goto triangle_candidate_points_from_vertex_exit;
-		}
-
-	}
-	else {
-		vv1 = tedge_v1(op_e);
-#ifdef DEBUG_ROUTE
-		printf("nothing on e1\n");
-#endif
-	}
-
-	if (v == tedge_v1(e2)) {
-		i = edge_routing_first_not_temp(e2);
-	}
-	else {
-		i = edge_routing_last_not_temp(e2);
-	}
-
-	if (i) {
-		toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data);
-
-		if (temp->parent == tedge_v1(op_e) || temp->child == tedge_v1(op_e)) {
-#ifdef DEBUG_ROUTE
-			printf("temp -> op_e->v2\n");
-#endif
-			goto triangle_candidate_points_from_vertex_exit;
-		}
-
-		if (temp->parent->routingedge == op_e) {
-			vv2 = temp->parent;
-#ifdef DEBUG_ROUTE
-			printf("vv2->parent\n");
-#endif
-		}
-		else if (temp->child->routingedge == op_e) {
-			vv2 = temp->child;
-#ifdef DEBUG_ROUTE
-			printf("vv2->child\n");
-#endif
-
-		}
-		else {
-			/* must be to e1 */
-#ifdef DEBUG_ROUTE
-			printf("temp -> e1?\n");
-			printf("op_e = %f,%f\t\t%f,%f\n", vx(edge_v1(op_e)), vy(edge_v1(op_e)), vx(edge_v2(op_e)), vy(edge_v2(op_e)));
-			if (temp->parent->routingedge)
-				printf("temp->parent->routingedge = %f,%f \t\t %f,%f\n",
-							 vx(edge_v1(temp->parent->routingedge)), vy(edge_v1(temp->parent->routingedge)),
-							 vx(edge_v2(temp->parent->routingedge)), vy(edge_v2(temp->parent->routingedge))
-					);
-			else
-				printf("temp->parent->routingedge = NULL\n");
-
-			if (temp->child->routingedge)
-				printf("temp->child->routingedge = %f,%f \t\t %f,%f\n",
-							 vx(edge_v1(temp->child->routingedge)), vy(edge_v1(temp->child->routingedge)),
-							 vx(edge_v2(temp->child->routingedge)), vy(edge_v2(temp->child->routingedge))
-					);
-			else
-				printf("temp->child->routingedge = NULL\n");
-#endif
-			goto triangle_candidate_points_from_vertex_exit;
-		}
-
-	}
-	else {
-		vv2 = tedge_v2(op_e);
-#ifdef DEBUG_ROUTE
-		printf("nothing on e2\n");
-#endif
-	}
-
-#ifdef DEBUG_ROUTE
-	printf("size of e1 routing = %d e2 routing = %d op_e routing = %d\n",
-				 g_list_length(edge_routing(e1)), g_list_length(edge_routing(e2)), g_list_length(edge_routing(op_e)));
-#endif
-
-	if (constraintv) {
-#ifdef DEBUG_ROUTE
-		print_vertex(constraintv);
-		printf("constraintv %f,%f returning\n", vx(constraintv), vy(constraintv));
-#endif
-		return g_list_prepend(NULL, constraintv);
-	}
-
-	i = edge_routing(op_e);
-	while (i) {
-		toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data);
-
-		if (temp->parent == v || temp->child == v) {
-			rval = g_list_concat(rval, candidate_vertices(vv1, temp, dest, op_e));
-			vv1 = temp;
-		}
-
-		i = i->next;
-	}
-
-	rval = g_list_concat(rval, candidate_vertices(vv1, vv2, dest, op_e));
-
-	return rval;
-
-
-
-triangle_candidate_points_from_vertex_exit:
-	if (constraintv)							/*delete_vertex(constraintv);     */
-		g_hash_table_insert(routedata->alltemppoints, constraintv, constraintv);
-
-	g_list_free(rval);
-
-	return NULL;
-}
-
-void routedata_insert_temppoints(toporouter_route_t * data, GList * temppoints)
-{
-	GList *j = temppoints;
-	while (j) {
-		g_hash_table_insert(data->alltemppoints, j->data, j->data);
-		j = j->next;
-	}
-}
-
-
-static inline gint constraint_route_test(toporouter_constraint_t * c, toporouter_route_t * routedata)
-{
-	if (c->box->cluster && c->box->cluster->netlist == routedata->src->netlist) {
-		if (c->box->cluster->c == routedata->dest->c || c->box->cluster->c == routedata->src->c)
-			return 1;
-	}
-	return 0;
-}
-
-GList *all_candidates_on_edge(toporouter_edge_t * e, toporouter_route_t * routedata)
-{
-	GList *rval = NULL;
-	if (edge_is_blocked(e))
-		return NULL;
-
-	if (!TOPOROUTER_IS_CONSTRAINT(e)) {
-		GList *i = edge_routing(e);
-		toporouter_vertex_t *pv = tedge_v1(e);
-
-		while (i) {
-			toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-			if (!(v->flags & VERTEX_FLAG_TEMP)) {
-				rval = g_list_concat(rval, candidate_vertices(pv, v, TOPOROUTER_VERTEX(routedata->destvertices->data), e));
-				pv = v;
-			}
-			i = i->next;
-		}
-
-		rval = g_list_concat(rval, candidate_vertices(pv, tedge_v2(e), TOPOROUTER_VERTEX(routedata->destvertices->data), e));
-	}
-	else if (TOPOROUTER_CONSTRAINT(e)->box->type == BOARD) {
-		return NULL;
-	}
-	else if (constraint_route_test(TOPOROUTER_CONSTRAINT(e), routedata)) {
-		toporouter_vertex_t *consv =
-			new_temp_toporoutervertex_in_segment(e, tedge_v1(e), tvdistance(tedge_v1(e), tedge_v2(e)) / 2., tedge_v2(e));
-		rval = g_list_prepend(rval, consv);
-/*    g_hash_table_insert(routedata->alltemppoints, consv, consv);  */
-	}
-
-	return rval;
-}
-
-GList *triangle_all_candidate_points_from_vertex(GtsTriangle * t, toporouter_vertex_t * v, toporouter_route_t * routedata)
-{
-	toporouter_edge_t *op_e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v)));
-	return all_candidates_on_edge(op_e, routedata);
-}
-
-GList *triangle_all_candidate_points_from_edge(toporouter_t * r, GtsTriangle * t, toporouter_edge_t * e,
-																							 toporouter_route_t * routedata, toporouter_vertex_t ** dest,
-																							 toporouter_vertex_t * curpoint)
-{
-	toporouter_vertex_t *op_v;
-	toporouter_edge_t *e1, *e2;
-	GList *i, *rval = NULL, *rval2 = NULL;
-	toporouter_vertex_t *boxpoint = NULL;
-	guint e1intcap, e2intcap;
-
-	op_v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e)));
-
-
-	if (vertex_bbox(op_v))
-		boxpoint = TOPOROUTER_VERTEX(vertex_bbox(op_v)->point);
-
-	if (g_list_find(routedata->destvertices, op_v)) {
-		rval = g_list_prepend(rval, op_v);
-		*dest = op_v;
-		return rval;
-	}
-	else if (g_list_find(routedata->destvertices, boxpoint)) {
-		*dest = boxpoint;
-	}
-	else if (g_list_find(routedata->srcvertices, op_v)) {
-		rval = g_list_prepend(rval, op_v);
-	}
-
-	e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v1(e)));
-	e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v2(e)));
-
-	rval = g_list_concat(rval, all_candidates_on_edge(e1, routedata));
-	rval = g_list_concat(rval, all_candidates_on_edge(e2, routedata));
-
-	e1intcap = check_triangle_interior_capacity(t, tedge_v1(e), curpoint, e2, e, e1);
-	e2intcap = check_triangle_interior_capacity(t, tedge_v2(e), curpoint, e1, e, e2);
-
-	i = rval;
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-
-		if (!v->routingedge)
-			rval2 = g_list_prepend(rval2, v);
-		else if (v->routingedge == e1 && !(!TOPOROUTER_IS_CONSTRAINT(e1) && !e1intcap))
-			rval2 = g_list_prepend(rval2, v);
-		else if (v->routingedge == e2 && !(!TOPOROUTER_IS_CONSTRAINT(e2) && !e2intcap))
-			rval2 = g_list_prepend(rval2, v);
-
-		i = i->next;
-	}
-	g_list_free(rval);
-
-	return rval2;
-}
-
-GList *triangle_candidate_points_from_edge(toporouter_t * r, GtsTriangle * t, toporouter_edge_t * e, toporouter_vertex_t * v,
-																					 toporouter_vertex_t ** dest, toporouter_route_t * routedata)
-{
-	toporouter_vertex_t *v1, *v2, *op_v, *vv = NULL, *e1constraintv = NULL, *e2constraintv = NULL;
-	toporouter_edge_t *e1, *e2;
-	GList *e1cands = NULL, *e2cands = NULL, *rval = NULL;
-	guint noe1 = 0, noe2 = 0;
-
-	op_v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e)));
-
-	e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v1(e)));
-	e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v2(e)));
-
-	g_assert(*dest);
-
-	/* v1 is prev dir, v2 is next dir */
-	edge_adjacent_vertices(e, v, &v1, &v2);
-
-	if (TOPOROUTER_IS_CONSTRAINT(e1)) {
-		GList *i = edge_routing(e1);
-
-		if (TOPOROUTER_CONSTRAINT(e1)->box->type == BOARD) {
-			noe1 = 1;
-		}
-		else if (!constraint_route_test(TOPOROUTER_CONSTRAINT(e1), routedata)) {
-			noe1 = 1;
-#ifdef DEBUG_ROUTE
-			printf("noe1 netlist\n");
-#endif
-		}
-		else
-		 if (v1 == tedge_v1(e) ||
-					 (v1->parent->routingedge && v1->parent->routingedge == e1) ||
-					 (v1->child->routingedge && v1->child->routingedge == e1)) {
-			e1constraintv =
-				new_temp_toporoutervertex_in_segment(e1, tedge_v1(e1),
-																						 gts_point_distance(GTS_POINT(edge_v1(e1)), GTS_POINT(edge_v2(e1))) / 2.,
-																						 tedge_v2(e1));
-		}
-
-		while (i) {
-			toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data);
-
-			if ((temp->child == tedge_v2(e) || temp->parent == tedge_v2(e)) && !(temp->flags & VERTEX_FLAG_TEMP))
-				noe2 = 1;
-
-			i = i->next;
-		}
-
-		goto triangle_candidate_points_e2;
-	}
-
-	if (edge_is_blocked(e1)) {
-		noe1 = 1;
-		goto triangle_candidate_points_e2;
-	}
-
-	if (v1 == tedge_v1(e)) {
-		/* continue up e1 */
-		toporouter_vertex_t *vv1, *vv2;
-		edge_adjacent_vertices(e1, v1, &vv1, &vv2);
-
-#ifdef DEBUG_ROUTE
-		printf("v1 == e->v1\n");
-#endif
-
-		if (vv1) {
-			/* candidates from v1 until vv1  */
-			vv = vv1;
-		}
-		else {
-			/* candidates from v1 until vv2 */
-			vv = vv2;
-		}
-
-		if (!e1constraintv)
-			e1cands = candidate_vertices(v1, vv, *dest, e1);
-
-		if (vv != op_v) {
-			if (vv->parent == tedge_v2(e) || vv->child == tedge_v2(e)) {
-#ifdef DEBUG_ROUTE
-				printf("noe2 0\n");
-#endif
-				noe2 = 1;
-			}
-		}
-
-	}
-	else if (v1->parent != op_v && v1->child != op_v) {
-		toporouter_vertex_t *vv1 = NULL, *vv2 = NULL;
-
-#ifdef DEBUG_ROUTE
-		printf("v1 != e->v1\n");
-#endif
-
-		if (v1->parent->routingedge == e1) {
-			vv1 = v1->parent;
-#ifdef DEBUG_ROUTE
-			printf("v1 parent = e1\n");
-#endif
-			if (op_v == tedge_v1(e1)) {
-				/* candidates from v1->parent until prev vertex  */
-				vv2 = edge_routing_prev_not_temp(e1, g_list_find(edge_routing(e1), v1->parent)->prev);
-			}
-			else {
-				/* candidates from v1->parent until next vertex  */
-				vv2 = edge_routing_next_not_temp(e1, g_list_find(edge_routing(e1), v1->parent)->next);
-			}
-
-		}
-		else if (v1->child->routingedge == e1) {
-			vv1 = v1->child;
-#ifdef DEBUG_ROUTE
-			printf("v1 child = e1\n");
-#endif
-			if (op_v == tedge_v1(e1)) {
-				/* candidates from v1->child until prev vertex  */
-				vv2 = edge_routing_prev_not_temp(e1, g_list_find(edge_routing(e1), v1->child)->prev);
-			}
-			else {
-				/* candidates from v1->child until next vertex */
-				vv2 = edge_routing_next_not_temp(e1, g_list_find(edge_routing(e1), v1->child)->next);
-			}
-
-		}
-		else {
-#ifdef DEBUG_ROUTE
-			printf("v1 ? \n");
-#endif
-			goto triangle_candidate_points_e2;
-		}
-
-		if (vv1 && vv2) {
-			if (vv2->parent == tedge_v2(e) || vv2->child == tedge_v2(e)) {
-#ifdef DEBUG_ROUTE
-				printf("noe2 1\n");
-#endif
-				noe2 = 1;
-			}
-
-			if (!e1constraintv)
-				e1cands = candidate_vertices(vv1, vv2, *dest, e1);
-
-			vv = vv2;
-		}
-	}
-
-	if (vv && vv == op_v) {
-		toporouter_vertex_t *boxpoint = NULL;
-
-		if (vertex_bbox(op_v))
-			boxpoint = TOPOROUTER_VERTEX(vertex_bbox(op_v)->point);
-
-		if (g_list_find(routedata->destvertices, op_v)) {
-			rval = g_list_prepend(rval, op_v);
-			*dest = op_v;
-		}
-		else if (g_list_find(routedata->destvertices, boxpoint)) {
-			*dest = boxpoint;
-		}
-		else if (g_list_find(routedata->srcvertices, op_v)) {
-			rval = g_list_prepend(rval, op_v);
-		}
-	}
-
-triangle_candidate_points_e2:
-
-	if (noe2) {
-/*    printf("noe2\n"); */
-		goto triangle_candidate_points_finish;
-	}
-
-	if (TOPOROUTER_IS_CONSTRAINT(e2)) {
-		GList *i = edge_routing(e2);
-
-		if (TOPOROUTER_CONSTRAINT(e2)->box->type == BOARD) {
-			noe2 = 1;
-/*      goto triangle_candidate_points_finish; */
-		}
-		else if (!constraint_route_test(TOPOROUTER_CONSTRAINT(e2), routedata)) {
-#ifdef DEBUG_ROUTE
-			printf("noe2 netlist\n");
-#endif
-			noe2 = 1;
-/*      goto triangle_candidate_points_finish; */
-		}
-		else if (v2 == tedge_v2(e) ||
-						 (v2->parent->routingedge && v2->parent->routingedge == e2) ||
-						 (v2->child->routingedge && v2->child->routingedge == e2)) {
-
-			e2constraintv =
-				new_temp_toporoutervertex_in_segment(e2, tedge_v1(e2),
-																						 gts_point_distance(GTS_POINT(edge_v1(e2)), GTS_POINT(edge_v2(e2))) / 2.,
-																						 tedge_v2(e2));
-
-		}
-
-		while (i) {
-			toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data);
-
-			if ((temp->child == tedge_v1(e) || temp->parent == tedge_v1(e)) && !(temp->flags & VERTEX_FLAG_TEMP))
-				noe1 = 1;
-
-			i = i->next;
-		}
-
-
-
-		goto triangle_candidate_points_finish;
-	}
-
-	if (edge_is_blocked(e2)) {
-		noe2 = 1;
-		goto triangle_candidate_points_finish;
-	}
-
-	if (v2 == tedge_v2(e)) {
-		/* continue up e2 */
-		toporouter_vertex_t *vv1 = NULL, *vv2 = NULL;
-		edge_adjacent_vertices(e2, v2, &vv1, &vv2);
-
-#ifdef DEBUG_ROUTE
-		printf("v2 == e->v2\n");
-#endif
-
-		if (vv1) {
-			/* candidates from v2 until vv1 */
-			vv = vv1;
-		}
-		else {
-			/* candidates from v2 until vv2 */
-			vv = vv2;
-		}
-
-		if (!e2constraintv)
-			e2cands = candidate_vertices(v2, vv, *dest, e2);
-
-		if (vv != op_v) {
-			if (vv->parent == tedge_v1(e) || vv->child == tedge_v1(e)) {
-#ifdef DEBUG_ROUTE
-				printf("noe1 0\n");
-#endif
-				noe1 = 1;
-			}
-		}
-
-	}
-	else if (v2->parent != op_v && v2->child != op_v) {
-		toporouter_vertex_t *vv1 = NULL, *vv2 = NULL;
-
-#ifdef DEBUG_ROUTE
-		printf("v2 == e->v2\n");
-#endif
-
-		if (v2->parent->routingedge == e2) {
-			vv1 = v2->parent;
-			if (op_v == tedge_v1(e2)) {
-				/* candidates from v2->parent until prev vertex  */
-				vv2 = edge_routing_prev_not_temp(e2, g_list_find(edge_routing(e2), vv1)->prev);
-			}
-			else {
-				/* candidates from v2->parent until next vertex  */
-				vv2 = edge_routing_next_not_temp(e2, g_list_find(edge_routing(e2), vv1)->next);
-			}
-
-		}
-		else if (v2->child->routingedge == e2) {
-			vv1 = v2->child;
-			if (op_v == tedge_v1(e2)) {
-				/* candidates from v2->child until prev vertex  */
-				vv2 = edge_routing_prev_not_temp(e2, g_list_find(edge_routing(e2), vv1)->prev);
-			}
-			else {
-				/* candidates from v2->child until next vertex  */
-				vv2 = edge_routing_next_not_temp(e2, g_list_find(edge_routing(e2), vv1)->next);
-			}
-
-		}
-		else {
-			goto triangle_candidate_points_finish;
-		}
-
-		if (vv1 && vv2) {
-			if (vv2->parent == tedge_v1(e) || vv2->child == tedge_v1(e)) {
-#ifdef DEBUG_ROUTE
-				printf("noe1 1\n");
-#endif
-				noe1 = 1;
-			}
-
-			if (!e2constraintv)
-				e2cands = candidate_vertices(vv1, vv2, *dest, e2);
-		}
-	}
-
-triangle_candidate_points_finish:
-
-	v1 = segment_common_vertex(GTS_SEGMENT(e), GTS_SEGMENT(e1));
-	v2 = segment_common_vertex(GTS_SEGMENT(e), GTS_SEGMENT(e2));
-
-	if (noe1 || !check_triangle_interior_capacity(t, v1, v, e2, e, e1)) {
-#ifdef DEBUG_ROUTE
-		printf("freeing e1cands\n");
-#endif
-		routedata_insert_temppoints(routedata, e1cands);
-		g_list_free(e1cands);
-		e1cands = NULL;
-	}
-
-	if (noe2 || !check_triangle_interior_capacity(t, v2, v, e1, e, e2)) {
-#ifdef DEBUG_ROUTE
-		printf("freeing e2cands\n");
-#endif
-		routedata_insert_temppoints(routedata, e2cands);
-		g_list_free(e2cands);
-		e2cands = NULL;
-	}
-
-	if (!noe1 && e1constraintv) {
-		e1cands = g_list_prepend(e1cands, e1constraintv);
-	}
-	else if (e1constraintv) {
-		g_hash_table_insert(routedata->alltemppoints, e1constraintv, e1constraintv);
-/*    delete_vertex(e1constraintv); */
-	}
-
-	if (!noe2 && e2constraintv) {
-		e2cands = g_list_prepend(e2cands, e2constraintv);
-	}
-	else if (e2constraintv) {
-		g_hash_table_insert(routedata->alltemppoints, e2constraintv, e2constraintv);
-/*    delete_vertex(e2constraintv); */
-	}
-
-	if (!noe1 && !noe2)
-		return g_list_concat(rval, g_list_concat(e1cands, e2cands));
-
-	return g_list_concat(e1cands, e2cands);
-}
-
-GList *compute_candidate_points(toporouter_t * tr, toporouter_layer_t * l, toporouter_vertex_t * curpoint,
-																toporouter_route_t * data, toporouter_vertex_t ** closestdest)
-{
-	GList *r = NULL, *j;
-	toporouter_edge_t *edge = curpoint->routingedge, *tempedge;
-
-	if (vertex_keepout_test(tr, curpoint))
-		goto compute_candidate_points_finish;
-
-	/* direct connection */
-/*  if(curpoint == TOPOROUTER_VERTEX(data->src->point)) */
-	if ((tempedge = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(curpoint), GTS_VERTEX(*closestdest))))) {
-
-		if (TOPOROUTER_IS_CONSTRAINT(tempedge)) {
-			goto compute_candidate_points_finish;
-		}
-		else {
-			if (!tempedge->routing) {
-				r = g_list_prepend(NULL, *closestdest);
-				tempedge->flags |= EDGE_FLAG_DIRECTCONNECTION;
-				goto compute_candidate_points_finish;
-			}
-			else {
-#ifdef DEBUG_ROUTE
-				printf("Direct connection, but has routing\n");
-#endif
-			}
-
-		}
-		/* if we get to here, there is routing blocking the direct connection,
-		 * continue as per normal */
-	}
-
-	/* a real point origin */
-	if (!(curpoint->flags & VERTEX_FLAG_TEMP)) {
-		GSList *triangles, *i;
-		i = triangles = gts_vertex_triangles(GTS_VERTEX(curpoint), NULL);
-#ifdef DEBUG_ROUTE
-		printf("triangle count = %d\n", g_slist_length(triangles));
-#endif
-		while (i) {
-			GtsTriangle *t = GTS_TRIANGLE(i->data);
-			GList *temppoints;
-
-			if (tr->flags & TOPOROUTER_FLAG_LEASTINVALID)
-				temppoints = triangle_all_candidate_points_from_vertex(t, curpoint, data);
-			else
-				temppoints = triangle_candidate_points_from_vertex(t, curpoint, *closestdest, data);
-
-#ifdef DEBUG_ROUTE
-			printf("\treturned %d points\n", g_list_length(temppoints));
-#endif
-			routedata_insert_temppoints(data, temppoints);
-
-			r = g_list_concat(r, temppoints);
-			i = i->next;
-		}
-		g_slist_free(triangles);
-	}
-	else {												/* a temp point */
-
-		int prevwind = vertex_wind(GTS_SEGMENT(edge)->v1, GTS_SEGMENT(edge)->v2, GTS_VERTEX(curpoint->parent));
-/*    printf("tempoint\n"); */
-
-		GSList *i = GTS_EDGE(edge)->triangles;
-
-		while (i) {
-			GtsVertex *oppv = gts_triangle_vertex_opposite(GTS_TRIANGLE(i->data), GTS_EDGE(edge));
-			if (prevwind != vertex_wind(GTS_SEGMENT(edge)->v1, GTS_SEGMENT(edge)->v2, oppv)) {
-				GList *temppoints;
-
-				if (tr->flags & TOPOROUTER_FLAG_LEASTINVALID)
-					temppoints = triangle_all_candidate_points_from_edge(tr, GTS_TRIANGLE(i->data), edge, data, closestdest, curpoint);
-				else
-					temppoints = triangle_candidate_points_from_edge(tr, GTS_TRIANGLE(i->data), edge, curpoint, closestdest, data);
-
-				j = temppoints;
-				while (j) {
-					toporouter_vertex_t *tempj = TOPOROUTER_VERTEX(j->data);
-					if (tempj->flags & VERTEX_FLAG_TEMP)
-						g_hash_table_insert(data->alltemppoints, j->data, j->data);
-#ifdef DEBUG_ROUTE
-					else
-						printf("got cand not a temp\n");
-#endif
-					j = j->next;
-				}
-				r = g_list_concat(r, temppoints);
-
-				break;
-			}
-			i = i->next;
-		}
-	}
-
-compute_candidate_points_finish:
-
-	if (vertex_bbox(curpoint) && vertex_bbox(curpoint)->cluster) {
-		if (vertex_bbox(curpoint)->cluster->c == data->src->c) {
-			r = g_list_concat(r, g_list_copy(data->srcvertices));
-		}
-	}
-
-	return r;
-}
-
-gboolean temp_point_clean(gpointer key, gpointer value, gpointer user_data)
-{
-	toporouter_vertex_t *tv = TOPOROUTER_VERTEX(value);
-	if (tv->flags & VERTEX_FLAG_TEMP) {
-		if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge))
-			TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv);
-		else
-			tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv);
-		gts_object_destroy(GTS_OBJECT(tv));
-	}
-	return TRUE;
-}
-
-void clean_routing_edges(toporouter_t * r, toporouter_route_t * data)
-{
-	g_hash_table_foreach_remove(data->alltemppoints, temp_point_clean, NULL);
-	g_hash_table_destroy(data->alltemppoints);
-	data->alltemppoints = NULL;
-}
-
-gdouble path_score(toporouter_t * r, GList * path)
-{
-	gdouble score = 0.;
-	toporouter_vertex_t *pv = NULL;
-	toporouter_vertex_t *v0 = NULL;
-
-	if (!path)
-		return INFINITY;
-
-	v0 = TOPOROUTER_VERTEX(path->data);
-
-	while (path) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(path->data);
-
-		if (pv) {
-			score += gts_point_distance(GTS_POINT(pv), GTS_POINT(v));
-			if (pv != v0 && vz(pv) != vz(v))
-				if (path->next)
-					score += r->viacost;
-
-		}
-
-		pv = v;
-		path = path->next;
-	}
-
-	return score;
-}
-
-void print_vertices(GList * vertices)
-{
-	while (vertices) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(vertices->data);
-		print_vertex(v);
-		print_bbox(vertex_bbox(v));
-		if (vertex_bbox(v)) {
-			printf("has bbox\n");
-			if (vertex_bbox(v)->cluster)
-				printf("has cluster\n");
-			else
-				printf("no cluster\n");
-		}
-		else
-			printf("no bbox\n");
-		vertices = vertices->next;
-	}
-}
-
-gint space_edge(gpointer item, gpointer data)
-{
-	toporouter_edge_t *e = TOPOROUTER_EDGE(item);
-	GList *i;
-	gdouble *forces;
-	guint j;
-
-	if (TOPOROUTER_IS_CONSTRAINT(e))
-		return 0;
-
-	if (!edge_routing(e) || !g_list_length(edge_routing(e)))
-		return 0;
-
-	forces = (gdouble *) malloc(sizeof(double) * g_list_length(edge_routing(e)));
-
-	for (j = 0; j < 100; j++) {
-		guint k = 0;
-		guint equilibrium = 1;
-
-		i = edge_routing(e);
-		while (i) {
-			toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-			gdouble ms, d;
-
-			if (i->prev) {
-/*        ms = min_net_net_spacing(TOPOROUTER_VERTEX(i->prev->data), v); */
-				ms = min_spacing(TOPOROUTER_VERTEX(i->prev->data), v);
-				d = gts_point_distance(GTS_POINT(i->prev->data), GTS_POINT(v));
-			}
-			else {
-/*        ms = min_vertex_net_spacing(v, tedge_v1(e)); */
-				ms = min_spacing(v, tedge_v1(e));
-				d = gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(v));
-			}
-
-			if (d < ms)
-				forces[k] = ms - d;
-			else
-				forces[k] = 0.;
-
-			if (i->next) {
-/*        ms = min_net_net_spacing(TOPOROUTER_VERTEX(i->next->data), v); */
-				ms = min_spacing(TOPOROUTER_VERTEX(i->next->data), v);
-				d = gts_point_distance(GTS_POINT(i->next->data), GTS_POINT(v));
-			}
-			else {
-/*        ms = min_vertex_net_spacing(v, tedge_v2(e)); */
-				ms = min_spacing(v, tedge_v2(e));
-				d = gts_point_distance(GTS_POINT(edge_v2(e)), GTS_POINT(v));
-			}
-
-			if (d < ms)
-				forces[k] += d - ms;
-
-			k++;
-			i = i->next;
-		}
-
-		k = 0;
-		i = edge_routing(e);
-		while (i) {
-			toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-			if (forces[k] > EPSILON || forces[k] < -EPSILON)
-				equilibrium = 0;
-			vertex_move_towards_vertex_values(GTS_VERTEX(v), edge_v2(e), forces[k] * 0.1, &(GTS_POINT(v)->x), &(GTS_POINT(v)->y));
-			k++;
-			i = i->next;
-		}
-
-		if (equilibrium) {
-/*      printf("reached equilibriium at %d\n", j); */
-			break;
-		}
-
-	}
-
-	free(forces);
-	return 0;
-}
-
-void swap_vertices(toporouter_vertex_t ** v1, toporouter_vertex_t ** v2)
-{
-	toporouter_vertex_t *tempv = *v1;
-	*v1 = *v2;
-	*v2 = tempv;
-}
-
-void split_edge_routing(toporouter_vertex_t * v, GList ** l1, GList ** l2)
-{
-	GList *base, *i;
-
-	g_assert(v);
-	g_assert(v->routingedge);
-
-	base = g_list_find(vrouting(v), v);
-
-	*l1 = g_list_prepend(*l1, tedge_v1(v->routingedge));
-	*l2 = g_list_prepend(*l2, tedge_v2(v->routingedge));
-
-	g_assert(base);
-
-	i = base->next;
-	while (i) {
-		if (!(TOPOROUTER_VERTEX(i->data)->flags & VERTEX_FLAG_TEMP))
-			*l2 = g_list_prepend(*l2, i->data);
-		i = i->next;
-	}
-
-	i = base->prev;
-	while (i) {
-		if (!(TOPOROUTER_VERTEX(i->data)->flags & VERTEX_FLAG_TEMP))
-			*l1 = g_list_prepend(*l1, i->data);
-		i = i->prev;
-	}
-}
-
-GList *vertices_routing_conflicts(toporouter_vertex_t * v, toporouter_vertex_t * pv)
-{
-	toporouter_edge_t *e;
-	GList *rval = NULL, *l1 = NULL, *l2 = NULL, *i;
-
-	if (vz(v) != vz(pv))
-		return NULL;
-	g_assert(v != pv);
-
-	if (!v->routingedge && !pv->routingedge) {
-		e = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), GTS_VERTEX(pv)));
-		if (!e)
-			return NULL;
-		i = edge_routing(e);
-		while (i) {
-			rval = g_list_prepend(rval, TOPOROUTER_VERTEX(i->data)->route);
-			i = i->next;
-		}
-		return rval;
-	}
-
-	if (TOPOROUTER_IS_CONSTRAINT(v->routingedge) && TOPOROUTER_IS_CONSTRAINT(pv->routingedge))
-		return NULL;
-
-	if (TOPOROUTER_IS_CONSTRAINT(pv->routingedge))
-		swap_vertices(&pv, &v);
-
-	if (!v->routingedge)
-		swap_vertices(&pv, &v);
-
-	e = v->routingedge;
-
-	split_edge_routing(v, &l1, &l2);
-	g_assert(l2);
-	g_assert(l1);
-
-	if (!pv->routingedge) {
-		toporouter_edge_t *e1, *e2;
-		e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(pv), edge_v1(e)));
-		e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(pv), edge_v2(e)));
-
-		l1 = g_list_concat(l1, g_list_copy(edge_routing(e1)));
-		l2 = g_list_concat(l2, g_list_copy(edge_routing(e2)));
-
-	}
-	else {
-		GList *pvlist1 = NULL, *pvlist2 = NULL;
-		toporouter_vertex_t *commonv = route_vertices_common_vertex(v, pv);
-
-		g_assert(commonv);
-
-		split_edge_routing(pv, &pvlist1, &pvlist2);
-
-		if (commonv == tedge_v1(e)) {
-			toporouter_edge_t *ope;
-
-			if (commonv == tedge_v1(pv->routingedge)) {
-				l1 = g_list_concat(l1, pvlist1);
-				l2 = g_list_concat(l2, pvlist2);
-				ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v2(e), edge_v2(pv->routingedge)));
-			}
-			else {
-				l1 = g_list_concat(l1, pvlist2);
-				l2 = g_list_concat(l2, pvlist1);
-				ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v2(e), edge_v1(pv->routingedge)));
-			}
-			g_assert(ope);
-			l2 = g_list_concat(l2, g_list_copy(edge_routing(ope)));
-
-		}
-		else {
-			toporouter_edge_t *ope;
-			if (commonv == tedge_v1(pv->routingedge)) {
-				l1 = g_list_concat(l1, pvlist2);
-				l2 = g_list_concat(l2, pvlist1);
-				ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v1(e), edge_v2(pv->routingedge)));
-			}
-			else {
-				l1 = g_list_concat(l1, pvlist1);
-				l2 = g_list_concat(l2, pvlist2);
-				ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v1(e), edge_v1(pv->routingedge)));
-			}
-			g_assert(ope);
-			l1 = g_list_concat(l1, g_list_copy(edge_routing(ope)));
-		}
-	}
-
-	i = l1;
-	while (i) {
-		toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data);
-
-		if (curv->flags & VERTEX_FLAG_ROUTE && (g_list_find(l2, curv->parent) || g_list_find(l2, curv->child))) {
-			if (!g_list_find(rval, curv->route))
-				rval = g_list_prepend(rval, curv->route);
-		}
-		i = i->next;
-	}
-	i = l2;
-	while (i) {
-		toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data);
-
-		if (curv->flags & VERTEX_FLAG_ROUTE && (g_list_find(l1, curv->parent) || g_list_find(l1, curv->child))) {
-			if (!g_list_find(rval, curv->route))
-				rval = g_list_prepend(rval, curv->route);
-		}
-		i = i->next;
-	}
-
-	g_list_free(l1);
-	g_list_free(l2);
-
-	return rval;
-}
-
-gdouble vertices_routing_conflict_cost(toporouter_t * r, toporouter_vertex_t * v, toporouter_vertex_t * pv, guint * n)
-{
-	GList *conflicts = vertices_routing_conflicts(v, pv), *i;
-	gdouble penalty = 0.;
-
-	i = conflicts;
-	while (i) {
-		(*n) += 1;
-		penalty += TOPOROUTER_ROUTE(i->data)->score;
-		i = i->next;
-	}
-	g_list_free(conflicts);
-/*  if(penalty > 0.) printf("conflict penalty of %f with %f,%f %f,%f\n", penalty, vx(v), vy(v), vx(pv), vy(pv)); */
-	return penalty;
-}
-
-gdouble
-gcost(toporouter_t * r, toporouter_route_t * data, toporouter_vertex_t * srcv, toporouter_vertex_t * v,
-			toporouter_vertex_t * pv, guint * n, toporouter_netlist_t * pair)
-{
-	gdouble cost = 0., segcost;
-
-	*n = pv->gn;
-
-	if (g_list_find(data->srcvertices, v))
-		return 0.;
-
-	segcost = tvdistance(pv, v);
-
-	if (pair && !TOPOROUTER_IS_CONSTRAINT(v->routingedge) && v->routingedge) {
-		GList *list = g_list_find(v->routingedge->routing, v);
-		toporouter_vertex_t *pv = edge_routing_prev_not_temp(v->routingedge, list);
-		toporouter_vertex_t *nv = edge_routing_next_not_temp(v->routingedge, list);
-
-		if (pv->route && pv->route->netlist == pair) {
-		}
-		else if (nv->route && nv->route->netlist == pair) {
-		}
-		else {
-			segcost *= 10.;
-		}
-	}
-
-	cost = pv->gcost + segcost;
-
-	if (r->flags & TOPOROUTER_FLAG_LEASTINVALID) {
-		gdouble conflictcost = 0.;
-
-		if (pv && v != pv && vz(v) == vz(pv))
-			conflictcost = vertices_routing_conflict_cost(r, v, pv, n);
-
-		if (!(r->flags & TOPOROUTER_FLAG_DETOUR && *n == 1)) {
-			cost += conflictcost * (pow(*n, 2));
-		}
-	}
-
-	return cost;
-}
-
-#define vlayer(x) (&r->layers[(int)vz(x)])
-
-guint candidate_is_available(toporouter_vertex_t * pv, toporouter_vertex_t * v)
-{
-	/* TODO: still needed?   */
-	while (pv) {
-		if (pv == v)
-			return 0;
-		pv = pv->parent;
-	}
-
-	return 1;
-}
-
-GList *route(toporouter_t * r, toporouter_route_t * data, guint debug)
-{
-	GtsEHeap *openlist = gts_eheap_new(route_heap_cmp, NULL);
-	GList *closelist = NULL;
-	GList *i, *rval = NULL;
-	toporouter_netlist_t *pair = NULL;
-	gint count = 0;
-
-	toporouter_vertex_t *srcv = NULL, *destv = NULL, *curpoint = NULL;
-	toporouter_layer_t *cur_layer;	/*, *dest_layer; */
-
-	g_assert(data->src->c != data->dest->c);
-
-	if (data->destvertices)
-		g_list_free(data->destvertices);
-	if (data->srcvertices)
-		g_list_free(data->srcvertices);
-
-	data->destvertices = cluster_vertices(r, data->dest);
-	data->srcvertices = cluster_vertices(r, data->src);
-
-	closest_cluster_pair(r, data->srcvertices, data->destvertices, &curpoint, &destv);
-
-	if (!curpoint || !destv)
-		goto routing_return;
-
-	srcv = curpoint;
-	cur_layer = vlayer(curpoint);
-	/*dest_layer = vlayer(destv); */
-
-	data->path = NULL;
-
-	data->alltemppoints = g_hash_table_new(g_direct_hash, g_direct_equal);
-
-	curpoint->parent = NULL;
-	curpoint->child = NULL;
-	curpoint->gcost = 0.;
-	curpoint->gn = 0;
-	curpoint->hcost = simple_h_cost(r, curpoint, destv);
-
-	if (data->netlist && data->netlist->pair) {
-		GList *i = r->routednets;
-		while (i) {
-			toporouter_route_t *curroute = TOPOROUTER_ROUTE(i->data);
-			if (curroute->netlist == data->netlist->pair) {
-				pair = data->netlist->pair;
-				break;
-			}
-			i = i->next;
-		}
-	}
-
-	gts_epcb_heap_insert(openlist, curpoint);
-
-	while (gts_epcb_heap_size(openlist) > 0) {
-		GList *candidatepoints;
-		data->curpoint = curpoint;
-		/*draw_route_status(r, closelist, openlist, curpoint, data, count++); */
-
-		curpoint = TOPOROUTER_VERTEX(gts_eheap_remove_top(openlist, NULL));
-		if (curpoint->parent && !(curpoint->flags & VERTEX_FLAG_TEMP)) {
-			if (vz(curpoint) != vz(destv)) {
-				toporouter_vertex_t *tempv;
-				cur_layer = vlayer(curpoint);	/*&r->layers[(int)vz(curpoint)]; */
-				tempv = closest_dest_vertex(r, curpoint, data);
-				if (tempv) {
-					destv = tempv;
-					/*dest_layer = vlayer(destv);//&r->layers[(int)vz(destv)]; */
-
-				}
-			}
-		}
-
-/*    destpoint = closest_dest_vertex(r, curpoint, data);
-      dest_layer = &r->layers[(int)vz(destpoint)];*/
-
-		if (g_list_find(data->destvertices, curpoint)) {
-			toporouter_vertex_t *temppoint = curpoint;
-			srcv = NULL;
-			destv = curpoint;
-
-			data->path = NULL;
-
-			while (temppoint) {
-				data->path = g_list_prepend(data->path, temppoint);
-				if (g_list_find(data->srcvertices, temppoint)) {
-					srcv = temppoint;
-					if (r->flags & TOPOROUTER_FLAG_AFTERORDER)
-						break;
-				}
-				temppoint = temppoint->parent;
-			}
-			rval = data->path;
-			data->score = path_score(r, data->path);
-#ifdef DEBUG_ROUTE
-			printf("ROUTE: path score = %f computation cost = %d\n", data->score, count);
-#endif
-
-			if (srcv->bbox->cluster != data->src) {
-				data->src = srcv->bbox->cluster;
-			}
-
-			if (destv->bbox->cluster != data->dest) {
-				data->dest = destv->bbox->cluster;
-			}
-			goto route_finish;
-		}
-		closelist_insert(curpoint);
-#ifdef DEBUG_ROUTE
-		printf("\n\n\n*** ROUTE COUNT = %d\n", count);
-#endif
-		candidatepoints = compute_candidate_points(r, cur_layer, curpoint, data, &destv);
-
-/*#ifdef DEBUG_ROUTE    */
-		/*********************
-    if(debug && !strcmp(data->dest->netlist, "  unnamed_net2")) 
-    {
-      unsigned int mask = ~(VERTEX_FLAG_RED | VERTEX_FLAG_GREEN | VERTEX_FLAG_BLUE); 
-      char buffer[256];
-      int j;
-
-      for(j=0;j<groupcount();j++) {
-        i = r->layers[j].vertices;
-        while(i) {
-          TOPOROUTER_VERTEX(i->data)->flags &= mask;
-          i = i->next;
-        }
-      }
-      
-      i = candidatepoints;
-      while(i) {
-        TOPOROUTER_VERTEX(i->data)->flags |= VERTEX_FLAG_GREEN;
-//        printf("flagged a candpoint @ %f,%f\n",
-//            vx(i->data), vy(i->data));
-        i = i->next;
-      }
-      
-      curpoint->flags |= VERTEX_FLAG_BLUE;
-      if(curpoint->parent) 
-        curpoint->parent->flags |= VERTEX_FLAG_RED;
-
-
-      for(j=0;j<groupcount();j++) {
-        GList *datas = g_list_prepend(NULL, data);
-        sprintf(buffer, "route-%d-%05d.png", j, count);
-        toporouter_draw_surface(r, r->layers[j].surface, buffer, 1024, 1024, 2, datas, j, candidatepoints);
-        g_list_free(datas);
-      }
-    }
-//#endif    
-    *********************/
-		count++;
-/*    if(count > 100) exit(0);*/
-		i = candidatepoints;
-		while (i) {
-			toporouter_vertex_t *temppoint = TOPOROUTER_VERTEX(i->data);
-			if (!g_list_find(closelist, temppoint) && candidate_is_available(curpoint, temppoint)) {	/*&& temppoint != curpoint) { */
-				toporouter_heap_search_data_t heap_search_data = { temppoint, NULL };
-
-				guint temp_gn;
-				gdouble temp_g_cost = gcost(r, data, srcv, temppoint, curpoint, &temp_gn, pair);
-
-
-				gts_eheap_foreach(openlist, toporouter_heap_search, &heap_search_data);
-
-				if (heap_search_data.result) {
-					if (temp_g_cost < temppoint->gcost) {
-
-						temppoint->gcost = temp_g_cost;
-						temppoint->gn = temp_gn;
-
-						temppoint->parent = curpoint;
-						curpoint->child = temppoint;
-
-						gts_eheap_update(openlist);
-					}
-				}
-				else {
-					temppoint->parent = curpoint;
-					curpoint->child = temppoint;
-
-					temppoint->gcost = temp_g_cost;
-					temppoint->gn = temp_gn;
-
-					temppoint->hcost = simple_h_cost(r, temppoint, destv);
-/*          if(cur_layer != dest_layer) temppoint->hcost += r->viacost;*/
-					gts_epcb_heap_insert(openlist, temppoint);
-				}
-
-			}
-			i = i->next;
-		}
-		g_list_free(candidatepoints);
-
-	}
-#ifdef DEBUG_ROUTE
-	printf("ROUTE: could not find path!\n");
-#endif
-
-	data->score = INFINITY;
-	clean_routing_edges(r, data);
-
-	data->path = NULL;
-	/*TOPOROUTER_VERTEX(data->src->point)->parent = NULL;
-	   TOPOROUTER_VERTEX(data->src->point)->child  = NULL; */
-	goto routing_return;
-
-/* 
-  {
-    int i;
-    for(i=0;i<groupcount();i++) {
-      char buffer[256];
-      sprintf(buffer, "route-error-%d-%d.png", r->routecount, i);
-      toporouter_draw_surface(r, r->layers[i].surface, buffer, 1280, 1280, 2, data, i, NULL);
-    }
-    r->routecount++;
-  }
-    exit(0);
-*/
-route_finish:
-/*  printf(" * finished a*\n");*/
-/* 
-  {
-    int i;
-    for(i=0;i<groupcount();i++) {
-      char buffer[256];
-      sprintf(buffer, "route-preclean-%d-%d.png", i, r->routecount);
-      toporouter_draw_surface(r, r->layers[i].surface, buffer, 1024, 1024, 2, data, i, NULL);
-    }
-    r->routecount++;
-  }
-*/
-/*  {
-    i = data->path;
-    while(i) {
-      toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data);
-      
-      if(tv->routingedge) {
-        GList *list = g_list_find(edge_routing(tv->routingedge), tv);
-        toporouter_vertex_t *restartv = NULL, *boxpoint;
-
-        g_assert(list);
-
-        if(!list->next) {
-          if(vertex_bbox(tedge_v2(tv->routingedge))) 
-            boxpoint = TOPOROUTER_VERTEX(vertex_bbox(tedge_v2(tv->routingedge))->point);
-          else
-            boxpoint = NULL;
-
-          if(tedge_v2(tv->routingedge) != srcv && g_list_find(data->srcvertices, tedge_v2(tv->routingedge))) 
-            restartv = tedge_v2(tv->routingedge);
-          else if(boxpoint != srcv && g_list_find(data->srcvertices, boxpoint)) 
-            restartv = boxpoint;
-        }
-        
-        if(!list->prev) {
-          if(vertex_bbox(tedge_v1(tv->routingedge))) 
-            boxpoint = TOPOROUTER_VERTEX(vertex_bbox(tedge_v1(tv->routingedge))->point);
-          else
-            boxpoint = NULL;
-
-          if(tedge_v1(tv->routingedge) != srcv && g_list_find(data->srcvertices, tedge_v1(tv->routingedge))) 
-            restartv = tedge_v1(tv->routingedge);
-          else if(boxpoint != srcv && g_list_find(data->srcvertices, boxpoint)) 
-            restartv = boxpoint;
-          
-        }
-
-        if(restartv) {
-          clean_routing_edges(r, data); 
-          gts_epcb_heap_destroy(openlist);     
-          g_list_free(closelist);
-          openlist = gts_eheap_new(route_heap_cmp, NULL);
-          closelist = NULL;
-          g_list_free(data->path);
-          printf("ROUTING RESTARTING with new src %f,%f,%f\n", vx(restartv), vy(restartv), vz(restartv));
-          curpoint = restartv;
-          goto route_begin;
-        }
-      }
-      
-      i = i->next;
-    }
-  }*/
-
-	{
-		toporouter_vertex_t *pv = NULL;
-		GList *i = data->path;
-		while (i) {
-			toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data);
-
-			if (pv && g_list_find(data->srcvertices, tv)) {
-				GList *temp = g_list_copy(i);
-				g_list_free(data->path);
-				data->path = temp;
-				i = data->path;
-			}
-			pv = tv;
-			i = i->next;
-		}
-	}
-
-	{
-		toporouter_vertex_t *pv = NULL;
-		GList *i = data->path;
-		while (i) {
-			toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data);
-			if (tv->flags & VERTEX_FLAG_TEMP) {
-				tv->flags ^= VERTEX_FLAG_TEMP;
-				tv->flags |= VERTEX_FLAG_ROUTE;
-			}
-			if (pv)
-				pv->child = tv;
-
-			if (tv->routingedge)
-				tv->route = data;
-
-/*      if(tv->routingedge && !TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) space_edge(tv->routingedge, NULL);*/
-
-			pv = tv;
-			i = i->next;
-		}
-	}
-
-	{
-		toporouter_vertex_t *pv = NULL, *v = NULL;
-
-		GList *i = data->path;
-		while (i) {
-			v = TOPOROUTER_VERTEX(i->data);
-
-			if (pv) {
-				v->parent = pv;
-				pv->child = v;
-			}
-			else {
-				v->parent = NULL;
-			}
-
-			pv = v;
-			i = i->next;
-		}
-
-		if (v)
-			v->child = NULL;
-	}
-
-	clean_routing_edges(r, data);
-	{
-		GList *i = data->path;
-		while (i) {
-			toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-
-			if (v->routingedge && !TOPOROUTER_IS_CONSTRAINT(v->routingedge))
-				space_edge(v->routingedge, NULL);
-			i = i->next;
-		}
-	}
-routing_return:
-
-	g_list_free(data->destvertices);
-	g_list_free(data->srcvertices);
-	data->destvertices = NULL;
-	data->srcvertices = NULL;
-	gts_epcb_heap_destroy(openlist);
-	g_list_free(closelist);
-
-	data->alltemppoints = NULL;
-
-	return rval;
-}
-
-/* moves vertex v d units in the direction of vertex p */
-void vertex_move_towards_point(GtsVertex * v, gdouble px, gdouble py, gdouble d)
-{
-	gdouble dx = px - GTS_POINT(v)->x;
-	gdouble dy = py - GTS_POINT(v)->y;
-	gdouble theta = atan(fabs(dy / dx));
-
-	g_assert(finite(theta));
-
-	if (dx >= 0.) {
-
-		if (dy >= 0.) {
-			GTS_POINT(v)->x += d * cos(theta);
-			GTS_POINT(v)->y += d * sin(theta);
-		}
-		else {
-			GTS_POINT(v)->x += d * cos(theta);
-			GTS_POINT(v)->y -= d * sin(theta);
-		}
-
-	}
-	else {
-
-		if (dy >= 0.) {
-			GTS_POINT(v)->x -= d * cos(theta);
-			GTS_POINT(v)->y += d * sin(theta);
-		}
-		else {
-			GTS_POINT(v)->x -= d * cos(theta);
-			GTS_POINT(v)->y -= d * sin(theta);
-		}
-
-	}
-
-}
-
-/* moves vertex v d units in the direction of vertex p */
-void vertex_move_towards_vertex(GtsVertex * v, GtsVertex * p, gdouble d)
-{
-	gdouble dx = GTS_POINT(p)->x - GTS_POINT(v)->x;
-	gdouble dy = GTS_POINT(p)->y - GTS_POINT(v)->y;
-	gdouble theta = atan(fabs(dy / dx));
-
-	g_assert(finite(theta));
-
-	if (dx >= 0.) {
-
-		if (dy >= 0.) {
-			GTS_POINT(v)->x += d * cos(theta);
-			GTS_POINT(v)->y += d * sin(theta);
-		}
-		else {
-			GTS_POINT(v)->x += d * cos(theta);
-			GTS_POINT(v)->y -= d * sin(theta);
-		}
-
-	}
-	else {
-
-		if (dy >= 0.) {
-			GTS_POINT(v)->x -= d * cos(theta);
-			GTS_POINT(v)->y += d * sin(theta);
-		}
-		else {
-			GTS_POINT(v)->x -= d * cos(theta);
-			GTS_POINT(v)->y -= d * sin(theta);
-		}
-
-	}
-
-}
-
-
-gdouble pathvertex_arcing_through_constraint(toporouter_vertex_t * pathv, toporouter_vertex_t * arcv)
-{
-	toporouter_vertex_t *v = pathv->child;
-
-	if (!v || !v->routingedge)
-		return 0.;
-
-	while (v->flags & VERTEX_FLAG_ROUTE && (tedge_v1(v->routingedge) == arcv || tedge_v2(v->routingedge) == arcv)) {
-		if (TOPOROUTER_IS_CONSTRAINT(v->routingedge))
-			return gts_point_distance(GTS_POINT(tedge_v1(v->routingedge)), GTS_POINT(tedge_v2(v->routingedge)));
-		v = v->child;
-	}
-
-	v = pathv->parent;
-	while (v->flags & VERTEX_FLAG_ROUTE && (tedge_v1(v->routingedge) == arcv || tedge_v2(v->routingedge) == arcv)) {
-		if (TOPOROUTER_IS_CONSTRAINT(v->routingedge))
-			return gts_point_distance(GTS_POINT(tedge_v1(v->routingedge)), GTS_POINT(tedge_v2(v->routingedge)));
-		v = v->parent;
-	}
-
-	return 0.;
-}
-
-gint vertices_connected(toporouter_vertex_t * a, toporouter_vertex_t * b)
-{
-	return ((a->route->netlist == b->route->netlist && a->route->src->c == b->route->src->c) ? 1 : 0);
-}
-
-gdouble edge_min_spacing(GList * list, toporouter_edge_t * e, toporouter_vertex_t * v, guint debug)
-{
-	toporouter_vertex_t *origin;
-	GList *i = list;
-	gdouble space = 0.;
-	toporouter_vertex_t *nextv, *prevv;
-	/*toporouter_vertex_t *edgev;
-	   gdouble constraint_spacing; */
-
-	if (!list)
-		return INFINITY;
-
-/*  printf("\t CMS %f,%f - %f,%f\n", vx(tedge_v1(e)), vy(tedge_v1(e)), vx(tedge_v2(e)), vy(tedge_v2(e))); */
-
-	prevv = origin = TOPOROUTER_VERTEX(list->data);
-
-/*  print_edge(e); */
-
-	i = list;
-	if (gts_point_distance2(GTS_POINT(origin), GTS_POINT(edge_v1(e))) < gts_point_distance2(GTS_POINT(v), GTS_POINT(edge_v1(e)))) {
-
-		/* towards v2 */
-		while (i) {
-			nextv = edge_routing_next(e, i);
-			if (nextv->route && vertices_connected(nextv, prevv)) {
-				i = i->next;
-				continue;
-			}
-			if (!(nextv->flags & VERTEX_FLAG_TEMP)) {
-				gdouble ms = min_spacing(prevv, nextv);
-				if (nextv == tedge_v2(e)) {
-					gdouble cms = pathvertex_arcing_through_constraint(TOPOROUTER_VERTEX(i->data), tedge_v2(e));
-/*          printf("\t CMS to %f,%f = %f \t ms = %f\n", vx(tedge_v2(e)), vy(tedge_v2(e)), cms, ms);
-            if(vx(tedge_v2(e)) > -EPSILON && vx(tedge_v2(e)) < EPSILON) {
-              printf("\t\tPROB: ");
-              print_vertex(tedge_v2(e));
-            }*/
-					if (cms > EPSILON)
-						space += MIN(ms, cms / 2.);
-					else
-						space += ms;
-				}
-				else
-					space += ms;
-
-				prevv = nextv;
-			}
-/*      printf("%f ", space);*/
-			i = i->next;
-		}
-	}
-	else {
-
-		/* towards v1 */
-		while (i) {
-			nextv = edge_routing_prev(e, i);
-			if (nextv->route && vertices_connected(nextv, prevv)) {
-				i = i->prev;
-				continue;
-			}
-			if (!(nextv->flags & VERTEX_FLAG_TEMP)) {
-				gdouble ms = min_spacing(prevv, nextv);
-				if (nextv == tedge_v1(e)) {
-					gdouble cms = pathvertex_arcing_through_constraint(TOPOROUTER_VERTEX(i->data), tedge_v1(e));
-/*          printf("\t CMS to %f,%f = %f \t ms = %f\n", vx(tedge_v1(e)), vy(tedge_v1(e)), cms, ms);
-            if(vx(tedge_v1(e)) > -EPSILON && vx(tedge_v1(e)) < EPSILON) {
-              printf("\t\tPROB: ");
-              print_vertex(tedge_v1(e));
-            }*/
-					if (cms > EPSILON)
-						space += MIN(ms, cms / 2.);
-					else
-						space += ms;
-				}
-				else
-					space += ms;
-
-				prevv = nextv;
-			}
-/*      printf("%f ", space);*/
-			i = i->prev;
-		}
-	}
-
-	if (TOPOROUTER_IS_CONSTRAINT(e) && space > gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))) / 2.)
-		space = gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))) / 2.;
-
-/*  if(debug) printf("\tedge_min_spacing: %f\n", space);*/
-	return space;
-}
-
-/* line segment is 1 & 2, point is 3 
-   returns 0 if v3 is outside seg
-*/
-guint
-vertex_line_normal_intersection(gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, gdouble * x,
-																gdouble * y)
-{
-	gdouble m1 = cartesian_gradient(x1, y1, x2, y2);
-	gdouble m2 = perpendicular_gradient(m1);
-	gdouble c2 = (isinf(m2)) ? x3 : y3 - (m2 * x3);
-	gdouble c1 = (isinf(m1)) ? x1 : y1 - (m1 * x1);
-
-	if (isinf(m2))
-		*x = x3;
-	else if (isinf(m1))
-		*x = x1;
-	else
-		*x = (c2 - c1) / (m1 - m2);
-
-	*y = (isinf(m2)) ? y1 : (m2 * (*x)) + c2;
-
-	if (*x >= MIN(x1, x2) - EPSILON && *x <= MAX(x1, x2) + EPSILON && *y >= MIN(y1, y2) - EPSILON && *y <= MAX(y1, y2) + EPSILON)
-		return 1;
-	return 0;
-}
-
-void print_toporouter_arc(toporouter_arc_t * arc)
-{
-/*  GList *i = arc->vs;*/
-
-	printf("ARC CENTRE: %f,%f ", vx(arc->centre), vy(arc->centre));	/* print_vertex(arc->centre); */
-	printf("RADIUS: %f", arc->r);
-
-	if (arc->dir > 0)
-		printf(" COUNTERCLOCKWISE ");
-	else if (arc->dir < 0)
-		printf(" CLOCKWISE ");
-	else
-		printf(" COLINEAR(ERROR) ");
-/*  
-  printf("\n\tVS: ");
-
-  while(i) {
-    toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-    printf("%f,%f ", vx(v), vy(v));
-
-    i = i->next;
-  }
-*/
-}
-
-void toporouter_arc_remove(toporouter_oproute_t * oproute, toporouter_arc_t * arc)
-{
-	oproute->arcs = g_list_remove(oproute->arcs, arc);
-
-	if (arc->v)
-		arc->v->arc = NULL;
-}
-
-toporouter_arc_t *toporouter_arc_new(toporouter_oproute_t * oproute, toporouter_vertex_t * v1, toporouter_vertex_t * v2,
-																		 toporouter_vertex_t * centre, gdouble r, gint dir)
-{
-	toporouter_arc_t *arc = TOPOROUTER_ARC(gts_object_new(GTS_OBJECT_CLASS(toporouter_arc_class())));
-	arc->centre = centre;
-	arc->v = v1;
-	arc->v1 = v1;
-	arc->v2 = v2;
-	arc->r = r;
-	arc->dir = dir;
-
-	if (v1)
-		v1->arc = arc;
-	arc->oproute = oproute;
-
-	arc->clearance = NULL;
-
-	return arc;
-}
-
-void path_set_oproute(GList * path, toporouter_oproute_t * oproute)
-{
-	while (path) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(path->data);
-
-		if (v->flags & VERTEX_FLAG_ROUTE)
-			v->oproute = oproute;
-
-		path = path->next;
-	}
-}
-
-void print_oproute(toporouter_oproute_t * oproute)
-{
-	GList *i = oproute->arcs;
-
-	printf("Optimized Route:\n");
-	printf("\tNetlist:\t\t%s\n\tStyle:\t\t%s\n", oproute->netlist, oproute->style);
-	/* printf("%s\n", oproute->netlist); */
-/*
-  i = oproute->term1->zlink;
-  while(i) {
-    toporouter_vertex_t *thisv = TOPOROUTER_VERTEX(i->data);
-    printf("\tNetlist:\t\t%s\n\tStyle:\t\t%s\n", vertex_bbox(thisv)->netlist, vertex_bbox(thisv)->style);
-    i = i->next;
-  }
-*/
-	printf("\t");
-	print_vertex(oproute->term1);
-	printf("\n");
-	i = oproute->arcs;
-	while (i) {
-		toporouter_arc_t *arc = (toporouter_arc_t *) i->data;
-		printf("\t");
-		print_toporouter_arc(arc);
-		printf("\n");
-		i = i->next;
-	}
-	printf("\t");
-	print_vertex(oproute->term2);
-	printf("\n");
-}
-
-gdouble export_pcb_drawline(guint layer, guint x0, guint y0, guint x1, guint y1, guint thickness, guint clearance)
-{
-	gdouble d = 0.;
-	pcb_line_t *line;
-	line = pcb_line_new_merge(LAYER_PTR(layer), x0, y0, x1, y1,
-																thickness, clearance, pcb_flag_make(PCB_FLAG_AUTO | (PCB_FLAG_TEST(PCB_CLEARNEWFLAG, PCB) ? PCB_FLAG_CLEARLINE : 0)));
-
-	if (line) {
-		pcb_undo_add_obj_to_create(PCB_TYPE_LINE, LAYER_PTR(layer), line, line);
-		d = coord_distance((double) x0, (double) y0, (double) x1, (double) y1) / 100.;
-	}
-	return d;
-}
-
-gdouble arc_angle(toporouter_arc_t * arc)
-{
-	gdouble x0, x1, y0, y1;
-
-	x0 = arc->x0 - vx(arc->centre);
-	x1 = arc->x1 - vx(arc->centre);
-	y0 = arc->y0 - vy(arc->centre);
-	y1 = arc->y1 - vy(arc->centre);
-
-	return fabs(acos(((x0 * x1) + (y0 * y1)) / (sqrt(pow(x0, 2) + pow(y0, 2)) * sqrt(pow(x1, 2) + pow(y1, 2)))));
-}
-
-gdouble export_pcb_drawarc(guint layer, toporouter_arc_t * a, guint thickness, guint clearance)
-{
-	gdouble sa, da, theta;
-	gdouble d = 0.;
-	pcb_arc_t *arc;
-	gint wind;
-
-	wind = coord_wind(a->x0, a->y0, a->x1, a->y1, vx(a->centre), vy(a->centre));
-
-	sa = coord_xangle(a->x0, a->y0, vx(a->centre), vy(a->centre)) * 180. / M_PI;
-
-	theta = arc_angle(a);
-
-	if (!a->dir || !wind)
-		return 0.;
-
-	if (a->dir != wind)
-		theta = 2. * M_PI - theta;
-
-	da = -a->dir * theta * 180. / M_PI;
-
-	if (da < 1. && da > -1.)
-		return 0.;
-	if (da > 359. || da < -359.)
-		return 0.;
-
-	arc = pcb_arc_new(LAYER_PTR(layer), vx(a->centre), vy(a->centre), a->r, a->r,
-														sa, da, thickness, clearance,
-														pcb_flag_make(PCB_FLAG_AUTO | (PCB_FLAG_TEST(PCB_CLEARNEWFLAG, PCB) ? PCB_FLAG_CLEARLINE : 0)));
-
-	if (arc) {
-		pcb_undo_add_obj_to_create(PCB_TYPE_ARC, LAYER_PTR(layer), arc, arc);
-		d = a->r * theta / 100.;
-	}
-
-	return d;
-}
-
-void calculate_term_to_arc(toporouter_vertex_t * v, toporouter_arc_t * arc, guint dir)
-{
-	gdouble theta, a, b, bx, by, a0x, a0y, a1x, a1y;
-	gint winddir;
-
-	theta = acos(arc->r / gts_point_distance(GTS_POINT(v), GTS_POINT(arc->centre)));
-	a = arc->r * sin(theta);
-	b = arc->r * cos(theta);
-#ifdef DEBUG_EXPORT
-	printf("drawing arc with r %f theta %f d %f centre = %f,%f\n", arc->r, theta,
-				 gts_point_distance(GTS_POINT(v), GTS_POINT(arc->centre)), vx(arc->centre), vy(arc->centre));
-#endif
-	point_from_point_to_point(arc->centre, v, b, &bx, &by);
-
-	coords_on_line(bx, by, perpendicular_gradient(point_gradient(GTS_POINT(v), GTS_POINT(arc->centre))), a, &a0x, &a0y, &a1x,
-								 &a1y);
-
-	winddir = coord_wind(vx(v), vy(v), a0x, a0y, vx(arc->centre), vy(arc->centre));
-
-	if (!winddir) {
-		printf("!winddir @ v %f,%f arc->centre %f,%f\n", vx(v), vy(v), vx(arc->centre), vy(arc->centre));
-		/*TODO: fix hack: this shouldn't happen */
-		arc->x0 = vx(v);
-		arc->y0 = vy(v);
-		arc->x1 = vx(v);
-		arc->y1 = vy(v);
-		return;
-	}
-
-	g_assert(winddir);
-
-	if (dir)
-		winddir = -winddir;
-
-	if (winddir == arc->dir) {
-		if (!dir) {
-			arc->x0 = a0x;
-			arc->y0 = a0y;
-		}
-		else {
-			arc->x1 = a0x;
-			arc->y1 = a0y;
-		}
-	}
-	else {
-		if (!dir) {
-			arc->x0 = a1x;
-			arc->y0 = a1y;
-		}
-		else {
-			arc->x1 = a1x;
-			arc->y1 = a1y;
-		}
-	}
-
-}
-
-
-
-/* b1 is the projection in the direction of narc, while b2 is the perpendicular projection*/
-void arc_ortho_projections(toporouter_arc_t * arc, toporouter_arc_t * narc, gdouble * b1, gdouble * b2)
-{
-	gdouble nax, nay, ax, ay, alen2, c;
-	gdouble b1x, b1y, b2x, b2y;
-
-#ifdef DEBUG_EXPORT
-	printf("arc c = %f,%f narc c = %f,%f arc->0 = %f,%f\n",
-				 vx(arc->centre), vy(arc->centre), vx(narc->centre), vy(narc->centre), arc->x0, arc->y0);
-#endif
-
-	nax = vx(narc->centre) - vx(arc->centre);
-	nay = vy(narc->centre) - vy(arc->centre);
-	alen2 = pow(nax, 2) + pow(nay, 2);
-
-
-	ax = arc->x0 - vx(arc->centre);
-	ay = arc->y0 - vy(arc->centre);
-
-#ifdef DEBUG_EXPORT
-	printf("norm narc = %f,%f - %f\tA=%f,%f\n", nax, nay, sqrt(alen2), ax, ay);
-#endif
-
-	c = ((ax * nax) + (ay * nay)) / alen2;
-
-	b1x = c * nax;
-	b1y = c * nay;
-	b2x = ax - b1x;
-	b2y = ay - b1y;
-
-#ifdef DEBUG_EXPORT
-	printf("proj = %f,%f perp proj = %f,%f\n", b1x, b1y, b2x, b2y);
-#endif
-
-	*b1 = sqrt(pow(b1x, 2) + pow(b1y, 2));
-	*b2 = sqrt(pow(b2x, 2) + pow(b2y, 2));
-
-}
-
-guint calculate_arc_to_arc(toporouter_t * ar, toporouter_arc_t * parc, toporouter_arc_t * arc)
-{
-	gdouble theta, a, b, bx, by, a0x, a0y, a1x, a1y, m, preva, prevb;
-	gint winddir;
-	toporouter_arc_t *bigr, *smallr;
-
-	if (parc->r > arc->r) {
-		bigr = parc;
-		smallr = arc;
-	}
-	else {
-		bigr = arc;
-		smallr = parc;
-	}
-#ifdef DEBUG_EXPORT
-	printf("bigr centre = %f,%f smallr centre = %f,%f\n", vx(bigr->centre), vy(bigr->centre),
-				 vx(smallr->centre), vy(smallr->centre));
-#endif
-
-	m = perpendicular_gradient(point_gradient(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)));
-
-	if (bigr->centre == smallr->centre) {
-
-		printf("bigr->centre == smallr->centre @ %f,%f\n", vx(smallr->centre), vy(smallr->centre));
-	}
-
-	g_assert(bigr->centre != smallr->centre);
-
-	if (parc->dir == arc->dir) {
-/*export_arc_straight:*/
-
-		theta = acos((bigr->r - smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)));
-		a = bigr->r * sin(theta);
-		b = bigr->r * cos(theta);
-
-		point_from_point_to_point(bigr->centre, smallr->centre, b, &bx, &by);
-
-		coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y);
-
-		winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre));
-
-		arc_ortho_projections(parc, arc, &prevb, &preva);
-/*#ifdef DEBUG_EXPORT    */
-		if (!winddir) {
-
-			printf("STRAIGHT:\n");
-			printf("bigr centre = %f,%f smallr centre = %f,%f\n", vx(bigr->centre), vy(bigr->centre),
-						 vx(smallr->centre), vy(smallr->centre));
-			printf("theta = %f a = %f b = %f bigrr = %f d = %f po = %f\n", theta, a, b, bigr->r,
-						 gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)),
-						 bigr->r / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)));
-			printf("bigr-r = %f smallr-r = %f ratio = %f\n",
-						 bigr->r, smallr->r, (bigr->r - smallr->r) / gts_point_distance(GTS_POINT(bigr->centre),
-																																						GTS_POINT(smallr->centre)));
-			printf("preva = %f prevb = %f\n\n", preva, prevb);
-
-		}
-/*#endif*/
-		g_assert(winddir);
-
-		if (bigr == parc)
-			winddir = -winddir;
-
-		if (winddir == bigr->dir) {
-			if (bigr == arc) {
-				bigr->x0 = a0x;
-				bigr->y0 = a0y;
-			}
-			else {
-				bigr->x1 = a0x;
-				bigr->y1 = a0y;
-			}
-		}
-		else {
-			if (bigr == arc) {
-				bigr->x0 = a1x;
-				bigr->y0 = a1y;
-			}
-			else {
-				bigr->x1 = a1x;
-				bigr->y1 = a1y;
-			}
-		}
-
-		a = smallr->r * sin(theta);
-		b = smallr->r * cos(theta);
-
-#ifdef DEBUG_EXPORT
-		printf("a = %f b = %f\n", a, b);
-#endif
-		point_from_point_to_point(smallr->centre, bigr->centre, -b, &bx, &by);
-
-		coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y);
-
-		if (winddir == bigr->dir) {
-			if (bigr == arc) {
-				smallr->x1 = a0x;
-				smallr->y1 = a0y;
-			}
-			else {
-				smallr->x0 = a0x;
-				smallr->y0 = a0y;
-			}
-		}
-		else {
-			if (bigr == arc) {
-				smallr->x1 = a1x;
-				smallr->y1 = a1y;
-			}
-			else {
-				smallr->x0 = a1x;
-				smallr->y0 = a1y;
-			}
-		}
-
-	}
-	else {
-
-/*export_arc_twist:    */
-
-		theta = acos((bigr->r + smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)));
-		a = bigr->r * sin(theta);
-		b = bigr->r * cos(theta);
-
-		point_from_point_to_point(bigr->centre, smallr->centre, b, &bx, &by);
-
-		coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y);
-
-		winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre));
-/*#ifdef DEBUG_EXPORT   */
-		if (!winddir) {
-			printf("TWIST:\n");
-			printf("theta = %f a = %f b = %f r = %f d = %f po = %f\n", theta, a, b, bigr->r + smallr->r,
-						 gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)),
-						 (bigr->r + smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)));
-
-			printf("bigr centre = %f,%f smallr centre = %f,%f\n\n", vx(bigr->centre), vy(bigr->centre),
-						 vx(smallr->centre), vy(smallr->centre));
-
-			printf("big wind = %d small wind = %d\n", bigr->dir, smallr->dir);
-			return 1;
-		}
-/*#endif      */
-/*    if(!winddir) {
-      smallr->centre->flags |= VERTEX_FLAG_RED;
-      bigr->centre->flags |= VERTEX_FLAG_GREEN;
-      //bigr->centre->flags |= VERTEX_FLAG_RED;
-      {
-        int i;
-        for(i=0;i<groupcount();i++) {
-          char buffer[256];
-          sprintf(buffer, "wind%d.png", i);
-          toporouter_draw_surface(ar, ar->layers[i].surface, buffer, 2096, 2096, 2, NULL, i, NULL);
-        }
-      }
-      return; 
-    }
-*/
-		g_assert(winddir);
-
-		if (bigr == parc)
-			winddir = -winddir;
-
-		if (winddir == bigr->dir) {
-			if (bigr == arc) {
-				bigr->x0 = a0x;
-				bigr->y0 = a0y;
-			}
-			else {
-				bigr->x1 = a0x;
-				bigr->y1 = a0y;
-			}
-		}
-		else {
-			if (bigr == arc) {
-				bigr->x0 = a1x;
-				bigr->y0 = a1y;
-			}
-			else {
-				bigr->x1 = a1x;
-				bigr->y1 = a1y;
-			}
-		}
-
-		a = smallr->r * sin(theta);
-		b = smallr->r * cos(theta);
-
-		point_from_point_to_point(smallr->centre, bigr->centre, b, &bx, &by);
-
-		coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y);
-
-		winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre));
-
-		g_assert(winddir);
-
-		if (bigr == parc)
-			winddir = -winddir;
-
-		if (winddir == smallr->dir) {
-			if (bigr == arc) {
-				smallr->x1 = a0x;
-				smallr->y1 = a0y;
-			}
-			else {
-				smallr->x0 = a0x;
-				smallr->y0 = a0y;
-			}
-		}
-		else {
-			if (bigr == arc) {
-				smallr->x1 = a1x;
-				smallr->y1 = a1y;
-			}
-			else {
-				smallr->x0 = a1x;
-				smallr->y0 = a1y;
-			}
-		}
-
-	}
-
-	return 0;
-}
-
-void export_oproutes(toporouter_t * ar, toporouter_oproute_t * oproute)
-{
-	guint layer = PCB->LayerGroups.Entries[oproute->layergroup][0];
-	guint thickness = lookup_thickness(oproute->style);
-	guint clearance = lookup_clearance(oproute->style);
-	GList *arcs = oproute->arcs;
-	toporouter_arc_t *arc, *parc = NULL;
-
-	if (!arcs) {
-		ar->wiring_score +=
-			export_pcb_drawline(layer, vx(oproute->term1), vy(oproute->term1), vx(oproute->term2), vy(oproute->term2), thickness,
-													clearance);
-		return;
-	}
-
-
-/*  calculate_term_to_arc(oproute->term1, TOPOROUTER_ARC(arcs->data), 0, layer);*/
-
-	while (arcs) {
-		arc = TOPOROUTER_ARC(arcs->data);
-
-		if (parc && arc) {
-			ar->wiring_score += export_pcb_drawarc(layer, parc, thickness, clearance);
-			ar->wiring_score += export_pcb_drawline(layer, parc->x1, parc->y1, arc->x0, arc->y0, thickness, clearance);
-		}
-		else if (!parc) {
-			ar->wiring_score +=
-				export_pcb_drawline(layer, vx(oproute->term1), vy(oproute->term1), arc->x0, arc->y0, thickness, clearance);
-		}
-
-		parc = arc;
-		arcs = arcs->next;
-	}
-	ar->wiring_score += export_pcb_drawarc(layer, arc, thickness, clearance);
-	ar->wiring_score += export_pcb_drawline(layer, arc->x1, arc->y1, vx(oproute->term2), vy(oproute->term2), thickness, clearance);
-
-}
-
-
-
-void oproute_free(toporouter_oproute_t * oproute)
-{
-	GList *i = oproute->arcs;
-	while (i) {
-		toporouter_arc_t *arc = (toporouter_arc_t *) i->data;
-		if (arc->centre->flags & VERTEX_FLAG_TEMP)
-			gts_object_destroy(GTS_OBJECT(arc->centre));
-
-		i = i->next;
-	}
-
-	g_list_free(oproute->arcs);
-	free(oproute);
-}
-
-void oproute_calculate_tof(toporouter_oproute_t * oproute)
-{
-	GList *arcs = oproute->arcs;
-	toporouter_arc_t *parc = NULL, *arc;
-
-	oproute->tof = 0.;
-
-	if (!arcs) {
-		oproute->tof = gts_point_distance(GTS_POINT(oproute->term1), GTS_POINT(oproute->term2));
-		return;
-	}
-
-	while (arcs) {
-		arc = TOPOROUTER_ARC(arcs->data);
-
-		if (parc && arc) {
-			oproute->tof += arc_angle(parc) * parc->r;
-			oproute->tof += sqrt(pow(parc->x1 - arc->x0, 2) + pow(parc->y1 - arc->y0, 2));
-		}
-		else if (!parc) {
-			oproute->tof += sqrt(pow(arc->x0 - vx(oproute->term1), 2) + pow(arc->y0 - vy(oproute->term1), 2));
-		}
-
-		parc = arc;
-		arcs = arcs->next;
-	}
-
-	oproute->tof += arc_angle(parc) * parc->r;
-	oproute->tof += sqrt(pow(arc->x1 - vx(oproute->term2), 2) + pow(arc->y1 - vy(oproute->term2), 2));
-
-}
-
-gdouble
-line_line_distance_at_normal(gdouble line1_x1, gdouble line1_y1,
-														 gdouble line1_x2, gdouble line1_y2,
-														 gdouble line2_x1, gdouble line2_y1, gdouble line2_x2, gdouble line2_y2, gdouble x, gdouble y)
-{
-	gdouble m1 = perpendicular_gradient(cartesian_gradient(line1_x1, line1_y1, line1_x2, line1_y2));
-	gdouble m2 = cartesian_gradient(line2_x1, line2_y1, line2_x2, line2_y2);
-	gdouble c1 = (isinf(m1)) ? x : y - (m1 * x);
-	gdouble c2 = (isinf(m2)) ? line2_x1 : line2_y1 - (m2 * line2_x1);
-
-	gdouble intx, inty;
-
-	if (isinf(m2))
-		intx = line2_x1;
-	else if (isinf(m1))
-		intx = x;
-	else
-		intx = (c2 - c1) / (m1 - m2);
-
-	inty = (isinf(m2)) ? (m1 * intx) + c1 : (m2 * intx) + c2;
-
-	return sqrt(pow(x - intx, 2) + pow(y - inty, 2));
-}
-
-void calculate_serpintine(gdouble delta, gdouble r, gdouble initiala, gdouble * a, guint * nhalfcycles)
-{
-	gdouble lhalfcycle = 2. * (initiala - r) + (M_PI * r);
-	guint n;
-
-	printf("lhalfcycle = %f r = %f\n", lhalfcycle, r);
-
-	n = (delta - M_PI * r) / (lhalfcycle - 2. * r) + 1;
-	*a = (delta + 4. * n * r - n * M_PI * r + 4. * r - M_PI * r) / (2. * n);
-	*nhalfcycles = n;
-}
-
-gdouble oproute_min_spacing(toporouter_oproute_t * a, toporouter_oproute_t * b)
-{
-	return lookup_thickness(a->style) / 2. + lookup_thickness(b->style) / 2. + MAX(lookup_clearance(a->style),
-																																								 lookup_clearance(b->style));
-}
-
-gdouble vector_angle(gdouble ox, gdouble oy, gdouble ax, gdouble ay, gdouble bx, gdouble by)
-{
-	gdouble alen = sqrt(pow(ax - ox, 2) + pow(ay - oy, 2));
-	gdouble blen = sqrt(pow(bx - ox, 2) + pow(by - oy, 2));
-	return acos(((ax - ox) * (bx - ox) + (ay - oy) * (by - oy)) / (alen * blen));
-}
-
-toporouter_serpintine_t *toporouter_serpintine_new(gdouble x, gdouble y, gdouble x0, gdouble y0, gdouble x1, gdouble y1,
-																									 gpointer start, gdouble halfa, gdouble radius, guint nhalfcycles)
-{
-	toporouter_serpintine_t *serp = (toporouter_serpintine_t *) malloc(sizeof(toporouter_serpintine_t));
-	serp->x = x;
-	serp->y = y;
-	serp->x0 = x0;
-	serp->y0 = y0;
-	serp->x1 = x1;
-	serp->y1 = y1;
-	serp->start = start;
-	serp->halfa = halfa;
-	serp->radius = radius;
-	serp->nhalfcycles = nhalfcycles;
-	serp->arcs = NULL;
-	return serp;
-}
-
-/*#define DEBUG_RUBBERBAND 1*/
-
-gdouble
-check_non_intersect_vertex(gdouble x0, gdouble y0, gdouble x1, gdouble y1, toporouter_vertex_t * pathv,
-													 toporouter_vertex_t * arcv, toporouter_vertex_t * opv, gint wind, gint * arcwind, gdouble * arcr,
-													 guint debug)
-{
-	gdouble ms, line_int_x, line_int_y, x, y, d = 0., m;
-	gdouble tx0, ty0, tx1, ty1;
-	gint wind1, wind2;
-
-	g_assert(pathv->routingedge);
-
-	if (TOPOROUTER_IS_CONSTRAINT(pathv->routingedge)) {
-		gdouble d = tvdistance(tedge_v1(pathv->routingedge), tedge_v2(pathv->routingedge)) / 2.;
-		ms = min_spacing(pathv, arcv);
-		if (ms > d)
-			ms = d;
-	}
-	else {
-		ms = edge_min_spacing(g_list_find(edge_routing(pathv->routingedge), pathv), pathv->routingedge, arcv, debug);
-	}
-
-
-	if (!vertex_line_normal_intersection(x0, y0, x1, y1, vx(arcv), vy(arcv), &line_int_x, &line_int_y)) {
-
-		if (coord_distance2(x0, y0, line_int_x, line_int_y) < coord_distance2(x1, y1, line_int_x, line_int_y)) {
-			line_int_x = x0;
-			line_int_y = y0;
-		}
-		else {
-			line_int_x = x1;
-			line_int_y = y1;
-		}
-
-		m = perpendicular_gradient(cartesian_gradient(vx(arcv), vy(arcv), line_int_x, line_int_y));
-	}
-	else {
-		m = cartesian_gradient(x0, y0, x1, y1);
-	}
-
-	coords_on_line(vx(arcv), vy(arcv), m, 100., &tx0, &ty0, &tx1, &ty1);
-
-	wind1 = coord_wind(tx0, ty0, tx1, ty1, line_int_x, line_int_y);
-	wind2 = coord_wind(tx0, ty0, tx1, ty1, vx(opv), vy(opv));
-
-	if (!wind2 || wind1 == wind2)
-		return -1.;
-
-	if (!wind) {
-		coords_on_line(line_int_x, line_int_y, perpendicular_gradient(m), ms, &tx0, &ty0, &tx1, &ty1);
-		if (coord_distance2(tx0, ty0, vx(opv), vy(opv)) < coord_distance2(tx1, ty1, vx(opv), vy(opv))) {
-			x = tx0;
-			y = ty0;
-		}
-		else {
-			x = tx1;
-			y = ty1;
-		}
-	}
-	else {
-		toporouter_vertex_t *parent = pathv->parent, *child = pathv->child;
-		guint windtests = 0;
-
-		d = coord_distance(vx(arcv), vy(arcv), line_int_x, line_int_y);
-		coord_move_towards_coord_values(line_int_x, line_int_y, vx(arcv), vy(arcv), ms + d, &x, &y);
-	rewind_test:
-		wind1 = coord_wind(line_int_x, line_int_y, x, y, vx(parent), vy(parent));
-		wind2 = coord_wind(line_int_x, line_int_y, x, y, vx(child), vy(child));
-		if (wind1 && wind2 && wind1 == wind2) {
-/*      return -1.;*/
-			if (windtests++ == 2)
-				return -1.;
-
-			if (parent->flags & VERTEX_FLAG_ROUTE)
-				parent = parent->parent;
-			if (child->flags & VERTEX_FLAG_ROUTE)
-				child = child->child;
-			goto rewind_test;
-		}
-	}
-
-
-	*arcr = ms;
-	*arcwind = tvertex_wind(pathv->parent, pathv, arcv);
-
-#ifdef DEBUG_RUBBERBAND
-/*if(debug) 
-    printf("non-int check %f,%f ms %f d %f arcv %f,%f opv %f,%f\n", vx(arcv), vy(arcv), ms, d + ms,
-      vx(arcv), vy(arcv), vx(opv), vy(opv));*/
-#endif
-
-	return d + ms;
-}
-
-gdouble
-check_intersect_vertex(gdouble x0, gdouble y0, gdouble x1, gdouble y1, toporouter_vertex_t * pathv, toporouter_vertex_t * arcv,
-											 toporouter_vertex_t * opv, gint wind, gint * arcwind, gdouble * arcr, guint debug)
-{
-	gdouble ms, line_int_x, line_int_y, x, y, d = 0.;
-
-	if (TOPOROUTER_IS_CONSTRAINT(pathv->routingedge)) {
-		gdouble d = tvdistance(tedge_v1(pathv->routingedge), tedge_v2(pathv->routingedge)) / 2.;
-		ms = min_spacing(pathv, arcv);
-		if (ms > d)
-			ms = d;
-	}
-	else {
-		ms = edge_min_spacing(g_list_find(edge_routing(pathv->routingedge), pathv), pathv->routingedge, arcv, debug);
-	}
-
-	if (!vertex_line_normal_intersection(x0, y0, x1, y1, vx(arcv), vy(arcv), &line_int_x, &line_int_y))
-		return -1.;
-
-	d = coord_distance(line_int_x, line_int_y, vx(arcv), vy(arcv));
-
-
-	if (d > ms - EPSILON)
-		return -1.;
-
-	coord_move_towards_coord_values(vx(arcv), vy(arcv), line_int_x, line_int_y, ms, &x, &y);
-
-	*arcr = ms;
-	*arcwind = tvertex_wind(pathv->parent, pathv, arcv);
-/*  *arcwind = coord_wind(x0, y0, x, y, x1, y1);*/
-#ifdef DEBUG_RUBBERBAND
-/*if(debug) 
-    printf("int check %f,%f ms %f d %f arcv %f,%f opv %f,%f\n", vx(arcv), vy(arcv), ms, ms - d,
-      vx(arcv), vy(arcv), vx(opv), vy(opv));*/
-#endif
-
-	return ms - d;
-}
-
-/* returns non-zero if arc has loops */
-guint check_arc_for_loops(gpointer t1, toporouter_arc_t * arc, gpointer t2)
-{
-	gdouble x0, y0, x1, y1;
-
-	if (TOPOROUTER_IS_VERTEX(t1)) {
-		x0 = vx(TOPOROUTER_VERTEX(t1));
-		y0 = vy(TOPOROUTER_VERTEX(t1));
-	}
-	else {
-		x0 = TOPOROUTER_ARC(t1)->x1;
-		y0 = TOPOROUTER_ARC(t1)->y1;
-	}
-
-	if (TOPOROUTER_IS_VERTEX(t2)) {
-		x1 = vx(TOPOROUTER_VERTEX(t2));
-		y1 = vy(TOPOROUTER_VERTEX(t2));
-	}
-	else {
-		x1 = TOPOROUTER_ARC(t2)->x0;
-		y1 = TOPOROUTER_ARC(t2)->y0;
-	}
-
-	if (coord_intersect_prop(x0, y0, arc->x0, arc->y0, arc->x1, arc->y1, x1, y1)) {
-/*  || 
-     (arc->x0 > arc->x1 - EPSILON && arc->x0 < arc->x1 + EPSILON &&
-       arc->y0 > arc->y1 - EPSILON && arc->y0 < arc->y1 + EPSILON)
-      ) {*/
-#ifdef DEBUG_RUBBERBAND
-		printf("LOOPS %f %f -> %f %f & %f %f -> %f %f\n", x0, y0, arc->x0, arc->y0, arc->x1, arc->y1, x1, y1);
-#endif
-		return 1;
-	}
-	return 0;
-}
-
-toporouter_rubberband_arc_t *new_rubberband_arc(toporouter_vertex_t * pathv, toporouter_vertex_t * arcv, gdouble r, gdouble d,
-																								gint wind, GList * list)
-{
-	toporouter_rubberband_arc_t *rba = (toporouter_rubberband_arc_t *) malloc(sizeof(toporouter_rubberband_arc_t));
-	rba->pathv = pathv;
-	rba->arcv = arcv;
-	rba->r = r;
-	rba->d = d;
-	rba->wind = wind;
-	rba->list = list;
-	return rba;
-}
-
-gint compare_rubberband_arcs(toporouter_rubberband_arc_t * a, toporouter_rubberband_arc_t * b)
-{
-	return b->d - a->d;
-}
-
-void free_list_elements(gpointer data, gpointer user_data)
-{
-	free(data);
-}
-
-
-/* returns the edge opposite v from the triangle facing (x,y), or NULL if v is colinear with an edge between v and a neighbor */
-/*
-GtsEdge *
-vertex_edge_facing_vertex(GtsVertex *v, gdouble x, gdouble y)
-{
-  GSList *ts = gts_vertex_triangles(GTS_VERTEX(n), NULL);
-  GSList *i = ts;
-
-  while(i) {
-    GtsTriangle *t = GTS_TRIANGLE(i->data);
-    GtsEdge *e = gts_triangle_edge_opposite(t, v);
-
-    if(coord_wind(vx(edge_v1(e)), vy(edge_v1(e)), vx(v), vy(v), x, y) == vertex_wind(edge_v1(e), v, edge_v2(e)) && 
-       coord_wind(vx(edge_v2(e)), vy(edge_v2(e)), vx(v), vy(v), x, y) == vertex_wind(edge_v2(e), v, edge_v1(e))
-       ) {
-     g_slist_free(ts);
-     return e;
-    }
-
-    i = i->next;
-  }
-
-  g_slist_free(ts);
-  return NULL;
-}
-*/
-
-gdouble
-check_adj_pushing_vertex(toporouter_oproute_t * oproute, gdouble x0, gdouble y0, gdouble x1, gdouble y1,
-												 toporouter_vertex_t * v, gdouble * arcr, gint * arcwind, toporouter_vertex_t ** arc)
-{
-	GSList *ns = gts_vertex_neighbors(GTS_VERTEX(v), NULL, NULL);
-	GSList *i = ns;
-	gdouble maxd = 0.;
-
-	while (i) {
-		toporouter_vertex_t *n = TOPOROUTER_VERTEX(i->data);
-		gdouble segintx, seginty;
-		if (vertex_line_normal_intersection(x0, y0, x1, y1, vx(n), vy(n), &segintx, &seginty)) {
-			toporouter_edge_t *e = tedge(n, v);
-			gdouble ms = 0., d = coord_distance(segintx, seginty, vx(n), vy(n));
-			/*toporouter_vertex_t *a; */
-			toporouter_vertex_t *b;
-			GList *closestnet = NULL;
-
-			g_assert(e);
-
-			if (v == tedge_v1(e)) {
-				/*a = tedge_v1(e); */
-				b = tedge_v2(e);
-				closestnet = edge_routing(e);
-			}
-			else {
-				/*a = tedge_v2(e); */
-				b = tedge_v1(e);
-				closestnet = g_list_last(edge_routing(e));
-			}
-
-			if (closestnet) {
-				ms = edge_min_spacing(closestnet, e, b, 0);
-				ms += min_oproute_net_spacing(oproute, TOPOROUTER_VERTEX(closestnet->data));
-			}
-			else {
-				ms = min_oproute_vertex_spacing(oproute, b);
-			}
-
-			if (ms - d > maxd) {
-				*arcr = ms;
-				*arc = n;
-				maxd = ms - d;
-				if (vx(v) == x0 && vy(v) == y0) {
-					*arcwind = coord_wind(x0, y0, vx(n), vy(n), x1, y1);
-				}
-				else if (vx(v) == x1 && vy(v) == y1) {
-					*arcwind = coord_wind(x1, y1, vx(n), vy(n), x0, y0);
-				}
-				else {
-					fprintf(stderr, "ERROR: check_adj_pushing_vertex encountered bad vertex v (coordinates don't match)\n");
-				}
-			}
-		}
-
-		i = i->next;
-	}
-
-	g_slist_free(ns);
-	return maxd;
-}
-
-
-/* path is t1 path*/
-GList *oproute_rubberband_segment(toporouter_t * r, toporouter_oproute_t * oproute, GList * path, gpointer t1, gpointer t2,
-																	guint debug)
-{
-	gdouble x0, y0, x1, y1;
-	toporouter_vertex_t *v1, *v2, *av1, *av2;	/* v{1,2} are the vertex terminals of the segment, or arc terminal centres */
-	toporouter_arc_t *arc1 = NULL, *arc2 = NULL, *newarc = NULL;	/* arc{1,2} are the arc terminals of the segment, if they exist */
-	GList *i = path;
-	GList *list1, *list2;
-
-	GList *arcs = NULL;
-	toporouter_rubberband_arc_t *max = NULL;
-
-	gdouble d, arcr;
-	gint v1wind, v2wind, arcwind;
-
-	if (TOPOROUTER_IS_VERTEX(t1)) {
-		v1 = TOPOROUTER_VERTEX(t1);
-		x0 = vx(v1);
-		y0 = vy(v1);
-	}
-	else {
-		g_assert(TOPOROUTER_IS_ARC(t1));
-		arc1 = TOPOROUTER_ARC(t1);
-		v1 = TOPOROUTER_VERTEX(arc1->v1);
-		x0 = arc1->x1;
-		y0 = arc1->y1;
-	}
-
-	if (TOPOROUTER_IS_VERTEX(t2)) {
-		v2 = TOPOROUTER_VERTEX(t2);
-		x1 = vx(v2);
-		y1 = vy(v2);
-	}
-	else {
-		g_assert(TOPOROUTER_IS_ARC(t2));
-		arc2 = TOPOROUTER_ARC(t2);
-		v2 = TOPOROUTER_VERTEX(arc2->v2);
-		x1 = arc2->x0;
-		y1 = arc2->y0;
-	}
-
-#define TEST_AND_INSERT(z) if(d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v, z, arcr, d, arcwind, i));
-#define ARC_CHECKS(z) (!(arc1 && arc1->centre == z) && !(arc2 && arc2->centre == z) && \
-  !(TOPOROUTER_IS_VERTEX(t1) && z == v1) && !(TOPOROUTER_IS_VERTEX(t2) && z == v2))
-
-	if (v1 == v2 || !i->next || TOPOROUTER_VERTEX(i->data) == v2)
-		return NULL;
-
-/*#ifdef DEBUG_RUBBERBAND*/
-	if (debug) {
-		printf("\nRB: line %f,%f %f,%f v1 = %f,%f v2 = %f,%f \n ", x0, y0, x1, y1, vx(v1), vy(v1), vx(v2), vy(v2));
-/*    if(v1->routingedge) print_edge(v1->routingedge);
-      if(v2->routingedge) print_edge(v2->routingedge);*/
-
-	}
-/*#endif*/
-
-	/* check the vectices adjacent to the terminal vectices for push against the segment */
-/*if(TOPOROUTER_IS_VERTEX(t1)) {
-    toporouter_vertex_t *arcc = NULL;
-    d = check_adj_pushing_vertex(oproute, x0, y0, x1, y1, v1, &arcr, &arcwind, &arcc); 
-    g_assert(arcc != v1);
-    if(ARC_CHECKS(arcc) && d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v1, arcc, arcr, d, arcwind, path->next));
-  }
-
-  if(TOPOROUTER_IS_VERTEX(t2)) {
-    toporouter_vertex_t *arcc = NULL;
-    d = check_adj_pushing_vertex(oproute, x0, y0, x1, y1, v2, &arcr, &arcwind, &arcc);
-    g_assert(arcc != v2);
-    if(ARC_CHECKS(arcc) && d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v2, arcc, arcr, d, arcwind, g_list_last(path)->prev));
-  }*/
-
-	i = i->next;
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-
-		if (v == v2 || v == v1 || !v->routingedge)
-			break;
-
-#ifdef DEBUG_RUBBERBAND
-/*  if(debug) 
-    printf("current v %f,%f - edge %f,%f %f,%f\n", vx(v), vy(v),
-      vx(tedge_v1(v->routingedge)), vy(tedge_v1(v->routingedge)),
-      vx(tedge_v2(v->routingedge)), vy(tedge_v2(v->routingedge))
-      );*/
-#endif
-		g_assert(v->routingedge);
-
-		v1wind = coord_wind(x0, y0, x1, y1, vx(tedge_v1(v->routingedge)), vy(tedge_v1(v->routingedge)));
-		v2wind = coord_wind(x0, y0, x1, y1, vx(tedge_v2(v->routingedge)), vy(tedge_v2(v->routingedge)));
-/*    if(debug) printf("\twinds: %d %d\n", v1wind, v2wind);*/
-		if (!v1wind && !v2wind) {
-			i = i->next;
-			continue;
-		}
-
-
-		if (v1wind && v2wind && v1wind != v2wind) {	/* edge is cutting through the current segment */
-
-			if (ARC_CHECKS(tedge_v1(v->routingedge))) {	/* edge v1 is not the centre of an arc terminal */
-				d =
-					check_intersect_vertex(x0, y0, x1, y1, v, tedge_v1(v->routingedge), tedge_v2(v->routingedge), v1wind, &arcwind, &arcr,
-																 debug);
-				TEST_AND_INSERT(tedge_v1(v->routingedge));
-			}
-
-			if (ARC_CHECKS(tedge_v2(v->routingedge))) {	/* edge v2 is not the centre of an arc terminal */
-				d =
-					check_intersect_vertex(x0, y0, x1, y1, v, tedge_v2(v->routingedge), tedge_v1(v->routingedge), v2wind, &arcwind, &arcr,
-																 debug);
-				TEST_AND_INSERT(tedge_v2(v->routingedge));
-			}
-		}
-		else {											/* edge is on one side of the segment */
-
-			if (ARC_CHECKS(tedge_v1(v->routingedge))) {	/* edge v1 is not the centre of an arc terminal */
-				d =
-					check_non_intersect_vertex(x0, y0, x1, y1, v, tedge_v1(v->routingedge), tedge_v2(v->routingedge), v1wind, &arcwind,
-																		 &arcr, debug);
-				TEST_AND_INSERT(tedge_v1(v->routingedge));
-			}
-
-			if (ARC_CHECKS(tedge_v2(v->routingedge))) {	/* edge v2 is not the centre of an arc terminal */
-				d =
-					check_non_intersect_vertex(x0, y0, x1, y1, v, tedge_v2(v->routingedge), tedge_v1(v->routingedge), v2wind, &arcwind,
-																		 &arcr, debug);
-				TEST_AND_INSERT(tedge_v2(v->routingedge));
-			}
-		}
-
-		i = i->next;
-	}
-
-	arcs = g_list_sort(arcs, (GCompareFunc) compare_rubberband_arcs);
-/*rubberband_insert_maxarc:*/
-	if (!arcs)
-		return NULL;
-	max = TOPOROUTER_RUBBERBAND_ARC(arcs->data);
-
-	av2 = max->pathv;
-	i = max->list->next;
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-		if (v->routingedge && (tedge_v1(v->routingedge) == max->arcv || tedge_v2(v->routingedge) == max->arcv)) {
-			av2 = v;
-			i = i->next;
-			continue;
-		}
-		break;
-	}
-
-	av1 = max->pathv;
-	i = max->list->prev;
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-		if (v->routingedge && (tedge_v1(v->routingedge) == max->arcv || tedge_v2(v->routingedge) == max->arcv)) {
-			av1 = v;
-			i = i->prev;
-			continue;
-		}
-		break;
-	}
-/*#ifdef DEBUG_RUBBERBAND*/
-	if (debug)
-		printf("newarc @ %f,%f \t v1 = %f,%f v2 = %f,%f r = %f\n", vx(max->arcv), vy(max->arcv), vx(av1), vy(av1), vx(av2), vy(av2),
-					 max->r);
-/*#endif*/
-	newarc = toporouter_arc_new(oproute, av1, av2, max->arcv, max->r, max->wind);
-
-	if (TOPOROUTER_IS_VERTEX(t1))
-		calculate_term_to_arc(TOPOROUTER_VERTEX(t1), newarc, 0);
-	else if (calculate_arc_to_arc(r, TOPOROUTER_ARC(t1), newarc)) {
-		printf("\tERROR: best:  r = %f d = %f\n", max->r, max->d);
-		printf("\tOPROUTE: %s\n", oproute->netlist);
-		print_vertex(oproute->term1);
-		print_vertex(oproute->term2);
-		return NULL;
-	}
-
-	if (TOPOROUTER_IS_VERTEX(t2))
-		calculate_term_to_arc(TOPOROUTER_VERTEX(t2), newarc, 1);
-	else if (calculate_arc_to_arc(r, newarc, TOPOROUTER_ARC(t2))) {
-		printf("\tERROR: best: r = %f d = %f\n", max->r, max->d);
-		printf("\tOPROUTE: %s\n", oproute->netlist);
-		print_vertex(oproute->term1);
-		print_vertex(oproute->term2);
-		return NULL;
-	}
-
-/*if(check_arc_for_loops(t1, newarc, t2)) {
-    if(arc1 && arc2) calculate_arc_to_arc(r, arc1, arc2);
-    else if(arc1) calculate_term_to_arc(TOPOROUTER_VERTEX(t2), arc1, 1);
-    else if(arc2) calculate_term_to_arc(TOPOROUTER_VERTEX(t1), arc2, 0);*/
-
-/*#ifdef DEBUG_RUBBERBAND
-    printf("REMOVING NEW ARC @ %f,%f\n", vx(newarc->centre), vy(newarc->centre));
-      TODO: properly remove newarc
-  #endif*/
-
-/*  arcs = g_list_remove(arcs, max);
-    free(max);
-    goto rubberband_insert_maxarc;
-  }*/
-
-
-	list1 = oproute_rubberband_segment(r, oproute, path, t1, newarc, debug);
-	list2 = oproute_rubberband_segment(r, oproute, i->next, newarc, t2, debug);
-
-	if (list1) {
-		GList *list = g_list_last(list1);
-		toporouter_arc_t *testarc = TOPOROUTER_ARC(list->data);
-		toporouter_arc_t *parc = list->prev ? TOPOROUTER_ARC(list->prev->data) : arc1;
-		gdouble px = parc ? parc->x1 : vx(TOPOROUTER_VERTEX(t1)), py = parc ? parc->y1 : vy(TOPOROUTER_VERTEX(t1));
-
-		if (coord_intersect_prop(px, py, testarc->x0, testarc->y0, testarc->x1, testarc->y1, newarc->x0, newarc->y0)) {
-			list1 = g_list_remove(list1, testarc);
-			if (parc)
-				calculate_arc_to_arc(r, parc, newarc);
-			else
-				calculate_term_to_arc(TOPOROUTER_VERTEX(t1), newarc, 0);
-/*#ifdef DEBUG_RUBBERBAND*/
-			if (debug)
-				printf("REMOVING ARC @ %f,%f\n", vx(testarc->centre), vy(testarc->centre));
-/*#endif*/
-		}
-	}
-	if (list2) {
-		toporouter_arc_t *testarc = TOPOROUTER_ARC(list2->data);
-		toporouter_arc_t *narc = list2->next ? TOPOROUTER_ARC(list2->next->data) : arc2;
-		gdouble nx = narc ? narc->x0 : vx(TOPOROUTER_VERTEX(t2)), ny = narc ? narc->y0 : vy(TOPOROUTER_VERTEX(t2));
-
-		if (coord_intersect_prop(newarc->x1, newarc->y1, testarc->x0, testarc->y0, testarc->x1, testarc->y1, nx, ny)) {
-			list2 = g_list_remove(list2, testarc);
-			if (narc)
-				calculate_arc_to_arc(r, newarc, narc);
-			else
-				calculate_term_to_arc(TOPOROUTER_VERTEX(t2), newarc, 1);
-
-/*#ifdef DEBUG_RUBBERBAND*/
-			if (debug)
-				printf("REMOVING ARC @ %f,%f\n", vx(testarc->centre), vy(testarc->centre));
-/*#endif*/
-		}
-	}
-
-	g_list_foreach(arcs, free_list_elements, NULL);
-	g_list_free(arcs);
-
-	return g_list_concat(list1, g_list_prepend(list2, newarc));
-}
-
-void oproute_check_all_loops(toporouter_t * r, toporouter_oproute_t * oproute)
-{
-	GList *i;
-	gpointer t1;
-
-loopcheck_restart:
-	t1 = oproute->term1;
-	i = oproute->arcs;
-	while (i) {
-		toporouter_arc_t *arc = TOPOROUTER_ARC(i->data);
-		gpointer t2 = i->next ? i->next->data : oproute->term2;
-
-		if (check_arc_for_loops(t1, arc, t2)) {
-
-			if (TOPOROUTER_IS_ARC(t1) && TOPOROUTER_IS_ARC(t2))
-				calculate_arc_to_arc(r, TOPOROUTER_ARC(t1), TOPOROUTER_ARC(t2));
-			else if (TOPOROUTER_IS_ARC(t1))
-				calculate_term_to_arc(TOPOROUTER_VERTEX(t2), TOPOROUTER_ARC(t1), 1);
-			else if (TOPOROUTER_IS_ARC(t2))
-				calculate_term_to_arc(TOPOROUTER_VERTEX(t1), TOPOROUTER_ARC(t2), 0);
-
-			oproute->arcs = g_list_remove(oproute->arcs, arc);
-			goto loopcheck_restart;
-		}
-
-		t1 = arc;
-
-		i = i->next;
-	}
-
-}
-
-GtsTriangle *opposite_triangle(GtsTriangle * t, toporouter_edge_t * e)
-{
-	GSList *i = GTS_EDGE(e)->triangles;
-
-	g_assert(e && t);
-
-	while (i) {
-		if (GTS_TRIANGLE(i->data) != t)
-			return GTS_TRIANGLE(i->data);
-		i = i->next;
-	}
-
-	return NULL;
-}
-
-
-void speccut_edge_routing_from_edge(GList * i, toporouter_edge_t * e)
-{
-	g_assert(TOPOROUTER_IS_EDGE(e));
-	while (i) {
-		toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data);
-
-		if (!(curv->flags & VERTEX_FLAG_TEMP)) {
-			toporouter_vertex_t *newv = tvertex_intersect(curv, curv->parent, tedge_v1(e), tedge_v2(e));
-
-/*      printf("\nCURV:\n");
-        print_vertex(curv);
-
-        printf("CURV child:\n");
-        if(curv->child) 
-          print_vertex(curv->child);
-        else 
-          printf("NULL\n");
-
-        printf("CURV parent:\n");
-        if(curv->parent)
-          print_vertex(curv->parent);
-        else 
-          printf("NULL\n");*/
-
-			if (newv) {
-				gint index;
-				newv->flags |= VERTEX_FLAG_ROUTE;
-				newv->flags |= VERTEX_FLAG_SPECCUT;
-				e->routing = g_list_insert_sorted_with_data(e->routing, newv, routing_edge_insert, e);
-				newv->route = curv->route;
-				newv->oproute = curv->oproute;
-				newv->routingedge = e;
-				GTS_POINT(newv)->z = vz(curv);
-
-				newv->parent = curv->parent;
-				newv->child = curv;
-
-/*        curv->parent = newv;*/
-
-				index = g_list_index(newv->route->path, curv);
-
-				newv->route->path = g_list_insert(newv->route->path, newv, index);
-
-
-				if (newv->oproute)
-					newv->oproute->path = newv->route->path;
-			}
-
-			if (!(curv->child->routingedge)) {
-				newv = tvertex_intersect(curv, curv->child, tedge_v1(e), tedge_v2(e));
-
-				if (newv) {
-					gint index;
-					newv->flags |= VERTEX_FLAG_ROUTE;
-					newv->flags |= VERTEX_FLAG_SPECCUT;
-					e->routing = g_list_insert_sorted_with_data(e->routing, newv, routing_edge_insert, e);
-					newv->route = curv->route;
-					newv->oproute = curv->oproute;
-					newv->routingedge = e;
-					GTS_POINT(newv)->z = vz(curv);
-
-					newv->parent = curv;
-					newv->child = curv->child;
-
-/*          curv->child = newv;*/
-
-					index = g_list_index(newv->route->path, curv);
-
-					newv->route->path = g_list_insert(newv->route->path, newv, index + 1);
-
-
-					if (newv->oproute)
-						newv->oproute->path = newv->route->path;
-				}
-
-			}
-
-		}
-		i = i->next;
-	}
-
-}
-
-void speccut_edge_patch_links(toporouter_edge_t * e)
-{
-	GList *i = e->routing;
-	g_assert(TOPOROUTER_IS_EDGE(e));
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-		v->parent->child = v;
-		v->child->parent = v;
-		i = i->next;
-	}
-}
-
-gint
-check_speccut(toporouter_oproute_t * oproute, toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_edge_t * e,
-							toporouter_edge_t * e1, toporouter_edge_t * e2)
-{
-	GtsTriangle *t, *opt;
-	toporouter_vertex_t *opv, *opv2;
-	toporouter_edge_t *ope1, *ope2;
-	gdouble cap, flow, line_int_x, line_int_y;
-
-	if (TOPOROUTER_IS_CONSTRAINT(e))
-		return 0;
-
-	if (!(t = gts_triangle_use_edges(GTS_EDGE(e), GTS_EDGE(e1), GTS_EDGE(e2)))) {
-		printf("check_speccut: NULL t\n");
-		return 0;
-	}
-
-	if (!(opt = opposite_triangle(t, e))) {
-/*    printf("check_speccut: NULL opt\n");*/
-		return 0;
-	}
-
-	if (!(opv = segment_common_vertex(GTS_SEGMENT(e1), GTS_SEGMENT(e2)))) {
-		printf("check_speccut: NULL opv\n");
-		return 0;
-	}
-
-	if (!(opv2 = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(opt, GTS_EDGE(e))))) {
-		printf("check_speccut: NULL opv2\n");
-		return 0;
-	}
-
-	/*TODO: shifting it out of the way would be better */
-	if (e->routing) {
-		GList *i = e->routing;
-		while (i) {
-			toporouter_vertex_t *ev = TOPOROUTER_VERTEX(i->data);
-			if (!tvertex_wind(opv, ev, opv2))
-				return 0;
-			i = i->next;
-		}
-
-	}
-
-	ope1 = tedge(opv2, tedge_v1(e));
-	ope2 = tedge(opv2, tedge_v2(e));
-
-	/*this fixes the weird pad exits in r8c board
-	   if(TOPOROUTER_IS_CONSTRAINT(ope1)) return 0; */
-	if (TOPOROUTER_IS_CONSTRAINT(ope2))
-		return 0;
-
-	if (!tvertex_wind(opv2, tedge_v1(e), opv))
-		return 0;
-	if (!tvertex_wind(opv2, tedge_v2(e), opv))
-		return 0;
-
-	if (!vertex_line_normal_intersection(vx(tedge_v1(e)), vy(tedge_v1(e)),
-																			 vx(tedge_v2(e)), vy(tedge_v2(e)), vx(opv2), vy(opv2), &line_int_x, &line_int_y))
-		return 0;
-
-
-/*  return 0;
-  if(vertex_line_normal_intersection(tev1x(e), tev1y(e), tev2x(e), tev2y(e), vx(opv), vy(opv), &line_int_x, &line_int_y))
-    return 0;*/
-
-	g_assert(opt && opv2);
-
-	/* this is just temp, for the purposes of determining flow */
-	if (tedge_v1(ope1) == opv2) {
-		if (TOPOROUTER_IS_CONSTRAINT(ope1))
-			TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_append(TOPOROUTER_CONSTRAINT(ope1)->routing, v1);
-		else
-			ope1->routing = g_list_append(ope1->routing, v1);
-	}
-	else {
-		if (TOPOROUTER_IS_CONSTRAINT(ope1))
-			TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_prepend(TOPOROUTER_CONSTRAINT(ope1)->routing, v1);
-		else
-			ope1->routing = g_list_prepend(ope1->routing, v1);
-	}
-
-	cap = triangle_interior_capacity(opt, opv2);
-	flow = flow_from_edge_to_edge(opt, tedge(opv2, tedge_v1(e)), tedge(opv2, tedge_v2(e)), opv2, v1);
-
-	/* temp v1 removed */
-	if (TOPOROUTER_IS_CONSTRAINT(ope1))
-		TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(ope1)->routing, v1);
-	else
-		ope1->routing = g_list_remove(ope1->routing, v1);
-
-	if (flow >= cap) {
-		toporouter_edge_t *newe =
-			TOPOROUTER_EDGE(gts_edge_new(GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX(opv), GTS_VERTEX(opv2)));
-
-		speccut_edge_routing_from_edge(edge_routing(e1), newe);
-		speccut_edge_routing_from_edge(edge_routing(e2), newe);
-		speccut_edge_routing_from_edge(edge_routing(ope1), newe);
-		speccut_edge_routing_from_edge(edge_routing(ope2), newe);
-
-		speccut_edge_patch_links(newe);
-/*
-    printf("SPECCUT WITH v %f,%f for seg %f,%f %f,%f detected\n", vx(opv2), vy(opv2),
-        vx(v1), vy(v1), 
-        vx(v2), vy(v2));
-    printf("\tflow %f cap %f\n", flow, cap);
-    print_edge(newe);
-  */
-		if (newe->routing)
-			return 1;
-	}
-
-
-	return 0;
-}
-
-
-gint oproute_path_speccut(toporouter_oproute_t * oproute)
-{
-	GList *i;
-	toporouter_vertex_t *pv;
-path_speccut_restart:
-	i = oproute->path;
-	pv = NULL;
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-
-
-		if (pv && (v->routingedge || pv->routingedge) && !(pv->flags & VERTEX_FLAG_SPECCUT) && !(v->flags & VERTEX_FLAG_SPECCUT)) {
-
-			if (!v->routingedge) {
-				if (check_speccut
-						(oproute, pv, v, tedge(tedge_v1(pv->routingedge), v), pv->routingedge, tedge(tedge_v2(pv->routingedge), v)))
-					goto path_speccut_restart;
-				if (check_speccut
-						(oproute, pv, v, tedge(tedge_v2(pv->routingedge), v), pv->routingedge, tedge(tedge_v1(pv->routingedge), v)))
-					goto path_speccut_restart;
-			}
-			else if (!pv->routingedge) {
-				if (check_speccut
-						(oproute, v, pv, tedge(tedge_v1(v->routingedge), pv), v->routingedge, tedge(tedge_v2(v->routingedge), pv)))
-					goto path_speccut_restart;
-				if (check_speccut
-						(oproute, v, pv, tedge(tedge_v2(v->routingedge), pv), v->routingedge, tedge(tedge_v1(v->routingedge), pv)))
-					goto path_speccut_restart;
-			}
-			else {
-				toporouter_vertex_t *v1 = NULL, *v2 = NULL;
-				edges_third_edge(GTS_SEGMENT(v->routingedge), GTS_SEGMENT(pv->routingedge), &v1, &v2);
-				if (check_speccut(oproute, v, pv, tedge(v1, v2), v->routingedge, pv->routingedge))
-					goto path_speccut_restart;
-			}
-		}
-
-
-		pv = v;
-		i = i->next;
-	}
-
-	return 0;
-}
-
-toporouter_oproute_t *oproute_rubberband(toporouter_t * r, GList * path)
-{
-	toporouter_oproute_t *oproute = (toporouter_oproute_t *) malloc(sizeof(toporouter_oproute_t));
-
-	g_assert(path);
-
-	oproute->term1 = TOPOROUTER_VERTEX(path->data);
-	oproute->term2 = TOPOROUTER_VERTEX(g_list_last(path)->data);
-	oproute->arcs = NULL;
-	oproute->style = vertex_bbox(oproute->term1)->cluster->netlist->style;
-	oproute->netlist = vertex_bbox(oproute->term1)->cluster->netlist->netlist;
-	oproute->layergroup = vz(oproute->term1);
-	oproute->path = path;
-	oproute->serp = NULL;
-
-	oproute->term1->parent = NULL;
-	oproute->term2->child = NULL;
-
-	path_set_oproute(path, oproute);
-
-/*  if(!strcmp(oproute->netlist, "  unnamed_net1")) */
-	oproute_path_speccut(oproute);
-
-#ifdef DEBUG_RUBBERBAND
-	if (!strcmp(oproute->netlist, "  VCC3V3") && vx(oproute->term1) == 95700. && vy(oproute->term1) == 70800. &&
-			vx(oproute->term2) == 196700. && vy(oproute->term2) == 67300.) {
-/*    printf("OPROUTE %s - %f,%f %f,%f\n", oproute->netlist, vx(oproute->term1), vy(oproute->term1), vx(oproute->term2), vy(oproute->term2));
-      print_path(path);*/
-		oproute->arcs = oproute_rubberband_segment(r, oproute, path, oproute->term1, oproute->term2, 1);
-	}
-	else
-#endif
-		oproute->arcs = oproute_rubberband_segment(r, oproute, path, oproute->term1, oproute->term2, 0);
-
-	oproute_check_all_loops(r, oproute);
-	return oproute;
-
-}
-
-void toporouter_export(toporouter_t * r)
-{
-	GList *i = r->routednets;
-	GList *oproutes = NULL;
-
-	while (i) {
-		toporouter_route_t *routedata = TOPOROUTER_ROUTE(i->data);
-		toporouter_oproute_t *oproute = oproute_rubberband(r, routedata->path);
-		oproutes = g_list_prepend(oproutes, oproute);
-		i = i->next;
-	}
-
-	i = oproutes;
-	while (i) {
-		toporouter_oproute_t *oproute = (toporouter_oproute_t *) i->data;
-		export_oproutes(r, oproute);
-		oproute_free(oproute);
-		i = i->next;
-	}
-
-	pcb_message(PCB_MSG_INFO, _("Reticulating splines... successful\n\n"));
-	pcb_message(PCB_MSG_INFO, _("Wiring cost: %f inches\n"), r->wiring_score / 1000.);
-	printf("Wiring cost: %f inches\n", r->wiring_score / 1000.);
-
-	g_list_free(oproutes);
-
-}
-
-toporouter_route_t *routedata_create(void)
-{
-	toporouter_route_t *routedata = (toporouter_route_t *) malloc(sizeof(toporouter_route_t));
-	routedata->netlist = NULL;
-	routedata->alltemppoints = NULL;
-	routedata->path = NULL;
-	routedata->curpoint = NULL;
-	routedata->pscore = routedata->score = 0.;
-	routedata->flags = 0;
-	routedata->src = routedata->dest = NULL;
-	routedata->psrc = routedata->pdest = NULL;
-	routedata->ppath = routedata->topopath = NULL;
-
-	routedata->ppathindices = NULL;
-
-	routedata->destvertices = routedata->srcvertices = NULL;
-	return routedata;
-}
-
-/*
-void
-print_routedata(toporouter_route_t *routedata)
-{
-  GList *srcvertices = cluster_vertices(routedata->src);
-  GList *destvertices = cluster_vertices(routedata->dest);
-
-  printf("ROUTEDATA:\n");
-  printf("SRCVERTICES:\n");
-  print_vertices(srcvertices);
-  printf("DESTVERTICES:\n");
-  print_vertices(destvertices);
-
-  g_list_free(srcvertices);
-  g_list_free(destvertices);
-}*/
-
-toporouter_route_t *import_route(toporouter_t * r, pcb_rat_t * line)
-{
-	toporouter_route_t *routedata = routedata_create();
-
-	routedata->src = cluster_find(r, line->Point1.X, line->Point1.Y, line->group1);
-	routedata->dest = cluster_find(r, line->Point2.X, line->Point2.Y, line->group2);
-
-	if (!routedata->src)
-		printf("couldn't locate src\n");
-	if (!routedata->dest)
-		printf("couldn't locate dest\n");
-
-	if (!routedata->src || !routedata->dest) {
-		pcb_printf("PROBLEM: couldn't locate rat src or dest for rat %#mD, %d -> %#mD, %d\n",
-							 line->Point1.X, line->Point1.Y, line->group1, line->Point2.X, line->Point2.Y, line->group2);
-		free(routedata);
-		return NULL;
-	}
-
-	routedata->netlist = routedata->src->netlist;
-
-	g_assert(routedata->src->netlist == routedata->dest->netlist);
-
-	g_ptr_array_add(r->routes, routedata);
-	g_ptr_array_add(routedata->netlist->routes, routedata);
-
-	r->failednets = g_list_prepend(r->failednets, routedata);
-
-	return routedata;
-}
-
-void delete_route(toporouter_route_t * routedata, guint destroy)
-{
-	GList *i = routedata->path;
-	toporouter_vertex_t *pv = NULL;
-
-	while (i) {
-		toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data);
-
-		g_assert(tv);
-
-		if (tv && pv && !(tv->flags & VERTEX_FLAG_ROUTE) && !(pv->flags & VERTEX_FLAG_ROUTE)) {
-			toporouter_edge_t *e = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(tv), GTS_VERTEX(pv)));
-
-			if (e && (e->flags & EDGE_FLAG_DIRECTCONNECTION)) {
-				e->flags ^= EDGE_FLAG_DIRECTCONNECTION;
-			}
-		}
-		pv = tv;
-		i = i->next;
-	}
-
-	i = routedata->path;
-	while (i) {
-		toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data);
-
-		tv->parent = NULL;
-		tv->child = NULL;
-
-		if (tv->routingedge) {
-			if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge))
-				TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv);
-			else
-				tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv);
-			if (destroy)
-				gts_object_destroy(GTS_OBJECT(tv));
-		}
-
-		i = i->next;
-	}
-
-	if (routedata->path)
-		g_list_free(routedata->path);
-	routedata->path = NULL;
-	routedata->curpoint = NULL;
-	routedata->score = INFINITY;
-	routedata->alltemppoints = NULL;
-}
-
-/* remove route can be later reapplied */
-void remove_route(GList * path)
-{
-	GList *i = path;
-
-	while (i) {
-		toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data);
-
-		tv->parent = NULL;
-		tv->child = NULL;
-
-/*    if(tv->flags & VERTEX_FLAG_ROUTE) g_assert(tv->route == routedata);*/
-
-		if (tv->routingedge) {
-
-			if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge))
-				TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv);
-			else
-				tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv);
-		}
-		i = i->next;
-	}
-
-}
-
-gint apply_route(GList * path, toporouter_route_t * routedata)
-{
-	GList *i = path;
-	toporouter_vertex_t *pv = NULL;
-	gint count = 0;
-
-	if (!path)
-		return 0;
-/*  g_assert(path);*/
-
-	while (i) {
-		toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data);
-
-		if (tv->routingedge) {
-			if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge))
-				TOPOROUTER_CONSTRAINT(tv->routingedge)->routing =
-					g_list_insert_sorted_with_data(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv, routing_edge_insert,
-																				 tv->routingedge);
-			else
-				tv->routingedge->routing = g_list_insert_sorted_with_data(tv->routingedge->routing,
-																																	tv, routing_edge_insert, tv->routingedge);
-
-			count++;
-		}
-
-		if (pv) {
-			pv->child = tv;
-			tv->parent = pv;
-		}
-
-		if (tv->flags & VERTEX_FLAG_ROUTE)
-			g_assert(tv->route == routedata);
-
-		pv = tv;
-		i = i->next;
-	}
-
-	TOPOROUTER_VERTEX(path->data)->parent = NULL;
-	pv->child = NULL;
-
-	return count;
-}
-
-
-gint compare_routedata_ascending(gconstpointer a, gconstpointer b)
-{
-	toporouter_route_t *ra = (toporouter_route_t *) a;
-	toporouter_route_t *rb = (toporouter_route_t *) b;
-	return ra->score - rb->score;
-}
-
-void print_costmatrix(gdouble * m, guint n)
-{
-	guint i;
-	printf("COST MATRIX:\n");
-	for (i = 0; i < n; i++) {
-		guint j;
-		for (j = 0; j < n; j++) {
-			printf("%f ", m[(i * n) + j]);
-		}
-		printf("\n");
-	}
-}
-
-
-static inline void init_cost_matrix(gdouble * m, guint n)
-{
-	guint i;
-	for (i = 0; i < n; i++) {
-		guint j;
-		for (j = 0; j < n; j++) {
-			m[(i * n) + j] = INFINITY;
-		}
-	}
-}
-
-
-toporouter_netscore_t *netscore_create(toporouter_t * r, toporouter_route_t * routedata, guint n, guint id)
-{
-	toporouter_netscore_t *netscore = (toporouter_netscore_t *) malloc(sizeof(toporouter_netscore_t));
-	GList *path = route(r, routedata, 0);
-	guint i;
-
-	netscore->id = id;
-
-	netscore->routedata = routedata;
-	routedata->detourscore = netscore->score = routedata->score;
-
-	if (!finite(routedata->detourscore)) {
-		printf("WARNING: !finite(detourscore)\n");
-		print_cluster(routedata->src);
-		print_cluster(routedata->dest);
-		return NULL;
-	}
-
-	netscore->pairwise_nodetour = (guint *) malloc(n * sizeof(guint));
-
-	for (i = 0; i < n; i++) {
-		netscore->pairwise_nodetour[i] = 0;
-	}
-
-	netscore->pairwise_detour_sum = 0.;
-	netscore->pairwise_fails = 0;
-
-	netscore->r = r;
-
-	if (path) {
-		routedata->topopath = g_list_copy(routedata->path);
-		delete_route(routedata, 0);
-	}
-
-	return netscore;
-}
-
-static inline void netscore_destroy(toporouter_netscore_t * netscore)
-{
-	free(netscore->pairwise_nodetour);
-	free(netscore);
-}
-
-void print_netscores(GPtrArray * netscores)
-{
-	toporouter_netscore_t **i;
-	printf("NETSCORES: \n\n");
-	printf("     %15s %15s %15s\n----------------------------------------------------\n", "Score", "Detour Sum",
-				 "Pairwise Fails");
-
-	for (i = (toporouter_netscore_t **) netscores->pdata; i < (toporouter_netscore_t **) netscores->pdata + netscores->len; i++) {
-#ifdef DEBUG_NETSCORES
-		printf("%4d %15f %15f %15d %15x\n", (*i)->id, (*i)->score, (*i)->pairwise_detour_sum, (*i)->pairwise_fails, (guint) * i);
-#endif
-	}
-
-	printf("\n");
-}
-
-void netscore_pairwise_calculation(toporouter_netscore_t * netscore, GPtrArray * netscores)
-{
-	toporouter_netscore_t **i;
-	toporouter_netscore_t **netscores_base = (toporouter_netscore_t **) (netscores->pdata);
-	toporouter_route_t *temproutedata = routedata_create();
-
-	/*route(netscore->r, netscore->routedata, 0); */
-	apply_route(netscore->routedata->topopath, netscore->routedata);
-
-	for (i = netscores_base; i < netscores_base + netscores->len; i++) {
-
-		if (!netscore->pairwise_nodetour[i - netscores_base] && *i != netscore
-				&& (*i)->routedata->netlist != netscore->routedata->netlist) {
-
-			temproutedata->src = (*i)->routedata->src;
-			temproutedata->dest = (*i)->routedata->dest;
-
-			route(netscore->r, temproutedata, 0);
-
-			if (temproutedata->score == (*i)->score) {
-				netscore->pairwise_nodetour[i - netscores_base] = 1;
-				(*i)->pairwise_nodetour[netscore->id] = 1;
-			}
-			else if (!finite(temproutedata->score)) {
-				netscore->pairwise_fails += 1;
-			}
-			else {
-				netscore->pairwise_detour_sum += temproutedata->score - (*i)->score;
-			}
-
-			delete_route(temproutedata, 1);
-		}
-
-	}
-
-/*  delete_route(netscore->routedata, 1);*/
-	remove_route(netscore->routedata->topopath);
-
-	free(temproutedata);
-}
-
-gint netscore_pairwise_size_compare(toporouter_netscore_t ** a, toporouter_netscore_t ** b)
-{
-	/* infinite scores are last */
-	if (!finite((*a)->score) && !finite((*b)->score))
-		return 0;
-	if (finite((*a)->score) && !finite((*b)->score))
-		return -1;
-	if (finite((*b)->score) && !finite((*a)->score))
-		return 1;
-
-	/* order by pairwise fails */
-	if ((*a)->pairwise_fails < (*b)->pairwise_fails)
-		return -1;
-	if ((*b)->pairwise_fails < (*a)->pairwise_fails)
-		return 1;
-
-	/* order by pairwise detour */
-	if ((*a)->pairwise_detour_sum < (*b)->pairwise_detour_sum)
-		return -1;
-	if ((*b)->pairwise_detour_sum < (*a)->pairwise_detour_sum)
-		return 1;
-
-	/* order by score */
-	if ((*a)->score < (*b)->score)
-		return -1;
-	if ((*b)->score < (*a)->score)
-		return 1;
-
-	return 0;
-}
-
-gint netscore_pairwise_compare(toporouter_netscore_t ** a, toporouter_netscore_t ** b)
-{
-	/* infinite scores are last */
-	if (!finite((*a)->score) && !finite((*b)->score))
-		return 0;
-	if (finite((*a)->score) && !finite((*b)->score))
-		return -1;
-	if (finite((*b)->score) && !finite((*a)->score))
-		return 1;
-
-	/* order by pairwise fails */
-	if ((*a)->pairwise_fails < (*b)->pairwise_fails)
-		return -1;
-	if ((*b)->pairwise_fails < (*a)->pairwise_fails)
-		return 1;
-
-	/* order by pairwise detour */
-	if ((*a)->pairwise_detour_sum < (*b)->pairwise_detour_sum)
-		return -1;
-	if ((*b)->pairwise_detour_sum < (*a)->pairwise_detour_sum)
-		return 1;
-
-	return 0;
-}
-
-guint order_nets_preroute_greedy(toporouter_t * r, GList * nets, GList ** rnets)
-{
-	gint len = g_list_length(nets);
-	GPtrArray *netscores = g_ptr_array_sized_new(len);
-	guint failcount = 0;
-
-	while (nets) {
-		toporouter_netscore_t *ns = netscore_create(r, TOPOROUTER_ROUTE(nets->data), len, failcount++);
-		if (ns)
-			g_ptr_array_add(netscores, ns);
-		nets = nets->next;
-	}
-
-	failcount = 0;
-
-	g_ptr_array_foreach(netscores, (GFunc) netscore_pairwise_calculation, netscores);
-
-	g_ptr_array_sort(netscores, (GCompareFunc) r->netsort);
-
-#ifdef DEBUG_ORDERING
-	print_netscores(netscores);
-#endif
-
-	*rnets = NULL;
-	FOREACH_NETSCORE(netscores) {
-		*rnets = g_list_prepend(*rnets, netscore->routedata);
-		if (!finite(netscore->score))
-			failcount++;
-		netscore_destroy(netscore);
-	}
-	FOREACH_END;
-
-	g_ptr_array_free(netscores, TRUE);
-
-	return failcount;
-}
-
-toporouter_vertex_t *edge_closest_vertex(toporouter_edge_t * e, toporouter_vertex_t * v)
-{
-	GList *i = v->routingedge ? edge_routing(v->routingedge) : NULL;
-	gdouble closestd = 0.;
-	toporouter_vertex_t *closestv = NULL;
-
-	while (i) {
-		toporouter_vertex_t *ev = TOPOROUTER_VERTEX(i->data);
-		gdouble tempd = gts_point_distance2(GTS_POINT(ev), GTS_POINT(v));
-
-		if (!closestv || (tempd < closestd)) {
-			closestd = tempd;
-			closestv = ev;
-		}
-
-		i = i->next;
-	}
-
-	return closestv;
-}
-
-void snapshot(toporouter_t * r, char *name, GList * datas)
-{
-	{
-		int i;
-		for (i = 0; i < groupcount(); i++) {
-			char buffer[256];
-			sprintf(buffer, "route-%s-%d.png", name, i);
-			toporouter_draw_surface(r, r->layers[i].surface, buffer, 2048, 2048, 2, datas, i, NULL);
-		}
-	}
-}
-
-/*
-gdouble
-route_conflict(toporouter_t *r, toporouter_route_t *route, guint *n)
-{
-  GList *i = route->path;
-  toporouter_vertex_t *pv = NULL;
-  gdouble cost = 0.;
-
-  while(i) {
-    toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-    if(pv && vz(v) == vz(pv))
-      cost += vertices_routing_conflict_cost(r, v, pv, n);
-    pv = v;
-    i = i->next;
-  }
-
-  return cost;
-}
-*/
-GList *route_conflicts(toporouter_route_t * route)
-{
-	GList *conflicts = NULL, *i = route->path;
-	toporouter_vertex_t *pv = NULL;
-
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-
-		if (pv && vz(pv) == vz(v)) {
-			GList *temp = vertices_routing_conflicts(pv, v), *j;
-
-			j = temp;
-			while (j) {
-				toporouter_route_t *conroute = TOPOROUTER_ROUTE(j->data);
-				if (!g_list_find(conflicts, conroute))
-					conflicts = g_list_prepend(conflicts, conroute);
-				j = j->next;
-			}
-
-			if (temp)
-				g_list_free(temp);
-		}
-
-		pv = v;
-		i = i->next;
-	}
-	return conflicts;
-}
-
-gint spread_edge(gpointer item, gpointer data)
-{
-	toporouter_edge_t *e = TOPOROUTER_EDGE(item);
-	toporouter_vertex_t *v;
-	gdouble spacing, s;
-	GList *i;
-
-	if (TOPOROUTER_IS_CONSTRAINT(e))
-		return 0;
-
-	i = edge_routing(e);
-
-	if (!g_list_length(i))
-		return 0;
-
-	if (g_list_length(i) == 1) {
-		v = TOPOROUTER_VERTEX(i->data);
-		GTS_POINT(v)->x = (vx(edge_v1(e)) + vx(edge_v2(e))) / 2.;
-		GTS_POINT(v)->y = (vy(edge_v1(e)) + vy(edge_v2(e))) / 2.;
-		return 0;
-	}
-
-	s = spacing = (gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e)))) / (g_list_length(i) + 1);
-
-	while (i) {
-		v = TOPOROUTER_VERTEX(i->data);
-		vertex_move_towards_vertex_values(edge_v1(e), edge_v2(e), s, &(GTS_POINT(v)->x), &(GTS_POINT(v)->y));
-
-		s += spacing;
-		i = i->next;
-	}
-
-	return 0;
-}
-
-void route_checkpoint(toporouter_route_t * route, toporouter_route_t * temproute)
-{
-	GList *i = g_list_last(route->path);
-	gint n = g_list_length(route->path);
-
-	if (route->ppathindices)
-		free(route->ppathindices);
-	route->ppathindices = (gint *) malloc(sizeof(gint) * n);
-
-/*  n = 0;*/
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-		n--;
-
-		if (v->routingedge) {
-			GList *j = g_list_find(edge_routing(v->routingedge), v)->prev;
-			gint tempindex = g_list_index(edge_routing(v->routingedge), v);
-
-			while (j) {
-				if (TOPOROUTER_VERTEX(j->data)->route == temproute)
-					tempindex--;
-				j = j->prev;
-			}
-
-			route->ppathindices[n] = tempindex;
-
-			if (TOPOROUTER_IS_CONSTRAINT(v->routingedge))
-				TOPOROUTER_CONSTRAINT(v->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v);
-			else
-				v->routingedge->routing = g_list_remove(v->routingedge->routing, v);
-		}
-
-		i = i->prev;
-	}
-
-	route->pscore = route->score;
-	route->ppath = route->path;
-	remove_route(route->path);
-	route->path = NULL;
-	route->psrc = route->src;
-	route->pdest = route->dest;
-/*route->src->pc = route->src->c;
-  route->dest->pc = route->dest->c;*/
-}
-
-void route_restore(toporouter_route_t * route)
-{
-	GList *i;
-	toporouter_vertex_t *pv = NULL;
-	gint n = 0;
-
-	g_assert(route->ppath);
-	g_assert(route->ppathindices);
-
-	route->path = route->ppath;
-	i = route->ppath;
-	while (i) {
-		toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data);
-
-		if (v->routingedge) {
-			if (TOPOROUTER_IS_CONSTRAINT(v->routingedge))
-				TOPOROUTER_CONSTRAINT(v->routingedge)->routing =
-					g_list_insert(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v, route->ppathindices[n]);
-			else
-				v->routingedge->routing = g_list_insert(v->routingedge->routing, v, route->ppathindices[n]);
-
-			/*      space_edge(v->routingedge, NULL); */
-		}
-
-		if (pv) {
-			pv->child = v;
-			v->parent = pv;
-		}
-
-		n++;
-		pv = v;
-		i = i->next;
-	}
-
-	route->score = route->pscore;
-	route->src = route->psrc;
-	route->dest = route->pdest;
-/*route->src->c = route->src->pc;
-  route->dest->c = route->dest->pc;*/
-
-}
-
-void cluster_merge(toporouter_route_t * routedata)
-{
-	gint oldc = routedata->dest->c, newc = routedata->src->c;
-
-	FOREACH_CLUSTER(routedata->netlist->clusters) {
-		if (cluster->c == oldc)
-			cluster->c = newc;
-	}
-	FOREACH_END;
-
-}
-
-void netlist_recalculate(toporouter_netlist_t * netlist, GList * ignore)
-{
-	GList *i = g_list_last(netlist->routed);
-	gint n = netlist->clusters->len - 1;
-
-	FOREACH_CLUSTER(netlist->clusters) {
-		cluster->c = n--;
-	} FOREACH_END;
-
-	while (i) {
-		if (!ignore || !g_list_find(ignore, i->data))
-			cluster_merge(TOPOROUTER_ROUTE(i->data));
-		i = i->prev;
-	}
-
-}
-
-void netlists_recalculate(GList * netlists, GList * ignore)
-{
-	GList *i = netlists;
-	while (i) {
-		netlist_recalculate(TOPOROUTER_NETLIST(i->data), ignore);
-		i = i->next;
-	}
-}
-
-void netlists_rollback(GList * netlists)
-{
-/*  netlists_recalculate(netlists, NULL);*/
-	while (netlists) {
-		toporouter_netlist_t *netlist = TOPOROUTER_NETLIST(netlists->data);
-
-		FOREACH_CLUSTER(netlist->clusters) {
-			cluster->c = cluster->pc;
-		}
-		FOREACH_END;
-
-		netlists = netlists->next;
-	}
-}
-
-void print_netlist(toporouter_netlist_t * netlist)
-{
-
-	printf("NETLIST %s: ", netlist->netlist);
-
-	FOREACH_CLUSTER(netlist->clusters) {
-		printf("%d ", cluster->c);
-
-	} FOREACH_END;
-	printf("\n");
-}
-
-#define REMOVE_ROUTING(x) x->netlist->routed = g_list_remove(x->netlist->routed, x); \
-  r->routednets = g_list_remove(r->routednets, x); \
-  r->failednets = g_list_prepend(r->failednets, x)
-
-#define INSERT_ROUTING(x) x->netlist->routed = g_list_prepend(x->netlist->routed, x); \
-  r->routednets = g_list_prepend(r->routednets, x); \
-  r->failednets = g_list_remove(r->failednets, x)
-
-gint roar_route(toporouter_t * r, toporouter_route_t * routedata, gint threshold)
-{
-	gint intfails = 0;
-	GList *netlists = NULL, *routed = NULL;
-
-	g_assert(!routedata->path);
-
-	if (routedata->src->c == routedata->dest->c) {
-		printf("ERROR: attempt to route already complete route\n");
-		g_assert(routedata->src->c != routedata->dest->c);
-	}
-
-	routedata->src->pc = routedata->src->c;
-	routedata->dest->pc = routedata->dest->c;
-	routedata->psrc = routedata->src;
-	routedata->pdest = routedata->dest;
-
-	r->flags |= TOPOROUTER_FLAG_LEASTINVALID;
-	if (route(r, routedata, 0)) {
-		GList *conflicts, *j;
-
-		INSERT_ROUTING(routedata);
-
-		conflicts = route_conflicts(routedata);
-		cluster_merge(routedata);
-
-		r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID;
-
-		j = conflicts;
-		while (j) {
-			toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data);
-			if (!g_list_find(netlists, conflict->netlist))
-				netlists = g_list_prepend(netlists, conflict->netlist);
-
-			route_checkpoint(conflict, routedata);
-
-			REMOVE_ROUTING(conflict);
-			j = j->next;
-		}
-
-		netlists = g_list_prepend(netlists, routedata->netlist);
-		netlists_recalculate(netlists, NULL);
-
-		j = conflicts;
-		while (j) {
-			toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data);
-			g_assert(conflict->src->c != conflict->dest->c);
-			if (route(r, conflict, 0)) {
-				cluster_merge(conflict);
-
-				routed = g_list_prepend(routed, conflict);
-
-				INSERT_ROUTING(conflict);
-
-				netlist_recalculate(conflict->netlist, NULL);
-
-			}
-			else {
-				if (++intfails >= threshold) {
-					GList *i = routed;
-					while (i) {
-						toporouter_route_t *intconflict = TOPOROUTER_ROUTE(i->data);
-						REMOVE_ROUTING(intconflict);
-						delete_route(intconflict, 1);
-						i = i->next;
-					}
-					delete_route(routedata, 1);
-					i = g_list_last(conflicts);
-					while (i) {
-						toporouter_route_t *intconflict = TOPOROUTER_ROUTE(i->data);
-
-						route_restore(intconflict);
-						INSERT_ROUTING(intconflict);
-
-						i = i->prev;
-					}
-					REMOVE_ROUTING(routedata);
-					intfails = 0;
-					netlists_recalculate(netlists, NULL);
-					goto roar_route_end;
-				}
-
-			}
-			j = j->next;
-		}
-
-
-		netlists_recalculate(netlists, NULL);
-
-		intfails--;
-	roar_route_end:
-		g_list_free(conflicts);
-		g_list_free(netlists);
-
-	}
-	else {
-		r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID;
-	}
-
-	g_list_free(routed);
-	return intfails;
-}
-
-gint roar_router(toporouter_t * r, gint failcount, gint threshold)
-{
-	guint j;
-	gint pfailcount = failcount + 1;
-
-	pcb_message(PCB_MSG_INFO, _("ROAR router: "));
-	for (j = 0; j < 6; j++) {
-		GList *failed = g_list_copy(r->failednets), *k = failed;
-
-		k = failed;
-		while (k) {
-			failcount += roar_route(r, TOPOROUTER_ROUTE(k->data), threshold);
-			k = k->next;
-		}
-		g_list_free(failed);
-
-		printf("\tROAR pass %d - %d routed -  %d failed\n", j, g_list_length(r->routednets), g_list_length(r->failednets));
-
-		if (!failcount || failcount >= pfailcount) {
-			pcb_message(PCB_MSG_INFO, _("%d nets remaining\n"), failcount);
-			break;
-		}
-		pcb_message(PCB_MSG_INFO, _("%d -> "), failcount);
-		pfailcount = failcount;
-	}
-
-	return failcount;
-}
-
-gint route_detour_compare(toporouter_route_t ** a, toporouter_route_t ** b)
-{
-	return ((*b)->score - (*b)->detourscore) - ((*a)->score - (*a)->detourscore);
-}
-
-
-
-void roar_detour_route(toporouter_t * r, toporouter_route_t * data)
-{
-	gdouble pscore = data->score, nscore = 0.;
-	GList *netlists = NULL;
-
-	route_checkpoint(data, NULL);
-
-	REMOVE_ROUTING(data);
-
-	netlists = g_list_prepend(NULL, data->netlist);
-	netlists_recalculate(netlists, NULL);
-
-	r->flags |= TOPOROUTER_FLAG_LEASTINVALID;
-	if (route(r, data, 0)) {
-		GList *conflicts, *j;
-
-		nscore = data->score;
-		conflicts = route_conflicts(data);
-
-		INSERT_ROUTING(data);
-
-		r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID;
-
-		j = conflicts;
-		while (j) {
-			toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data);
-
-			if (!g_list_find(netlists, conflict->netlist))
-				netlists = g_list_prepend(netlists, conflict->netlist);
-			pscore += conflict->score;
-
-			route_checkpoint(conflict, NULL);
-			REMOVE_ROUTING(conflict);
-
-			j = j->next;
-		}
-		netlists_recalculate(netlists, NULL);
-
-		j = conflicts;
-		while (j) {
-			toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data);
-
-			if (route(r, conflict, 0)) {
-				cluster_merge(conflict);
-				INSERT_ROUTING(conflict);
-				nscore += conflict->score;
-			}
-			else {
-				j = j->prev;
-				goto roar_detour_route_rollback_int;
-			}
-			j = j->next;
-		}
-
-		if (nscore > pscore) {
-			j = g_list_last(conflicts);
-		roar_detour_route_rollback_int:
-			REMOVE_ROUTING(data);
-
-			while (j) {
-				toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data);
-				REMOVE_ROUTING(conflict);
-				delete_route(conflict, 1);
-				j = j->prev;
-			}
-
-			j = g_list_last(conflicts);
-			while (j) {
-				toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data);
-				route_restore(conflict);
-				INSERT_ROUTING(conflict);
-				j = j->prev;
-			}
-			delete_route(data, 1);
-
-			goto roar_detour_route_rollback_exit;
-
-		}
-
-		g_list_free(conflicts);
-	}
-	else {
-		r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID;
-	roar_detour_route_rollback_exit:
-		route_restore(data);
-		INSERT_ROUTING(data);
-	}
-	netlists_recalculate(netlists, NULL);
-
-	g_list_free(netlists);
-}
-
-void detour_router(toporouter_t * r)
-{
-	GList *i = r->routednets;
-	guint n = g_list_length(r->routednets);
-	GPtrArray *scores = g_ptr_array_sized_new(n);
-
-	while (i) {
-		toporouter_route_t *curroute = TOPOROUTER_ROUTE(i->data);
-		curroute->score = path_score(r, curroute->path);
-		g_ptr_array_add(scores, i->data);
-		i = i->next;
-	}
-
-	g_ptr_array_sort(scores, (GCompareFunc) route_detour_compare);
-
-	r->flags |= TOPOROUTER_FLAG_DETOUR;
-
-	{
-		toporouter_route_t **i;
-		for (i = (toporouter_route_t **) scores->pdata; i < (toporouter_route_t **) scores->pdata + scores->len; i++) {
-			toporouter_route_t *curroute = (*i);
-
-			if (finite(curroute->score) && finite(curroute->detourscore)) {
-/*    printf("%15s %15f \t %8f,%8f - %8f,%8f\n", (*i)->src->netlist + 2, (*i)->score - (*i)->detourscore,
-          vx(curroute->mergebox1->point), vy(curroute->mergebox1->point),
-          vx(curroute->mergebox2->point), vy(curroute->mergebox2->point));*/
-
-				if (curroute->score - curroute->detourscore > 1000.) {
-					roar_detour_route(r, curroute);
-				}
-				else
-					break;
-
-			}
-		}
-	}
-	printf("\n");
-
-	r->flags ^= TOPOROUTER_FLAG_DETOUR;
-
-	g_ptr_array_free(scores, TRUE);
-
-}
-
-gint rubix_router(toporouter_t * r, gint failcount)
-{
-	GList *i, *ordering;
-	order_nets_preroute_greedy(r, r->failednets, &ordering);
-
-	i = ordering;
-	while (i) {
-		toporouter_route_t *data = TOPOROUTER_ROUTE(i->data);
-
-		if (route(r, data, 0)) {
-			INSERT_ROUTING(data);
-			cluster_merge(data);
-			failcount--;
-		}
-
-		i = i->next;
-	}
-
-	g_list_free(ordering);
-
-	return failcount;
-}
-
-guint hybrid_router(toporouter_t * r)
-{
-	guint i;
-	gint failcount = g_list_length(r->failednets);
-	r->flags |= TOPOROUTER_FLAG_AFTERORDER;
-	r->flags |= TOPOROUTER_FLAG_AFTERRUBIX;
-	failcount = rubix_router(r, failcount);
-
-	pcb_message(PCB_MSG_INFO, _("RUBIX router: %d nets remaining\n"), failcount);
-	printf("RUBIX router: %d nets remaining\n", failcount);
-
-	r->flags |= TOPOROUTER_FLAG_GOFAR;
-
-	for (i = 0; i < 6 && failcount; i++) {
-		if (i % 2 == 1) {
-			failcount = roar_router(r, failcount, 5);
-			/*    printf("THRESH 5\n"); */
-		}
-		else {
-			failcount = roar_router(r, failcount, 2);
-			/*    printf("THRESH 2\n"); */
-		}
-
-		detour_router(r);
-	}
-
-	failcount = roar_router(r, failcount, 2);
-	detour_router(r);
-
-	return failcount;
-}
-
-void parse_arguments(toporouter_t * r, int argc, char **argv)
-{
-	int i, tempint;
-	guint group;
-
-	for (i = 0; i < argc; i++) {
-		if (sscanf(argv[i], "viacost=%d", &tempint)) {
-			r->viacost = (double) tempint;
-		}
-		else if (sscanf(argv[i], "l%d", &tempint)) {
-			gdouble *layer = (gdouble *) malloc(sizeof(gdouble));
-			*layer = (double) tempint;
-			r->keepoutlayers = g_list_prepend(r->keepoutlayers, layer);
-		}
-	}
-
-	for (group = 0; group < pcb_max_group; group++)
-		for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
-			if ((PCB->LayerGroups.Entries[group][i] < pcb_max_copper_layer) && !(PCB->Data->Layer[PCB->LayerGroups.Entries[group][i]].On)) {
-				gdouble *layer = (gdouble *) malloc(sizeof(gdouble));
-				*layer = (double) group;
-				r->keepoutlayers = g_list_prepend(r->keepoutlayers, layer);
-			}
-
-}
-
-toporouter_t *toporouter_new(void)
-{
-	toporouter_t *r = (toporouter_t *) calloc(1, sizeof(toporouter_t));
-	time_t ltime;
-
-	gettimeofday(&r->starttime, NULL);
-
-	r->netsort = netscore_pairwise_compare;
-
-	r->destboxes = NULL;
-	r->consumeddestboxes = NULL;
-
-	r->paths = NULL;
-
-	r->layers = NULL;
-	r->flags = 0;
-	r->viamax = 3;
-	r->viacost = 10000.;
-	r->stublength = 300.;
-	r->serpintine_half_amplitude = 1500.;
-
-	r->wiring_score = 0.;
-
-	r->bboxes = NULL;
-	r->bboxtree = NULL;
-
-	r->netlists = g_ptr_array_new();
-	r->routes = g_ptr_array_new();
-
-	r->keepoutlayers = NULL;
-
-	r->routednets = NULL;
-	r->failednets = NULL;
-
-	ltime = time(NULL);
-
-	gts_predicates_init();
-
-	pcb_message(PCB_MSG_INFO, _("Topological Autorouter\n"));
-	pcb_message(PCB_MSG_INFO, _("Started %s"), asctime(localtime(&ltime)));
-	pcb_message(PCB_MSG_INFO, _("-------------------------------------\n"));
-	pcb_message(PCB_MSG_INFO, _("Copyright 2009 Anthony Blake (tonyb33 at gmail.com)\n\n"));
-	return r;
-}
-
-void acquire_twonets(toporouter_t * r)
-{
-	PCB_RAT_LOOP(PCB->Data);
-	if (PCB_FLAG_TEST(PCB_FLAG_SELECTED, line))
-		import_route(r, line);
-	PCB_END_LOOP;
-
-	if (!r->routes->len) {
-		PCB_RAT_LOOP(PCB->Data);
-		import_route(r, line);
-		PCB_END_LOOP;
-	}
-}
-
-toporouter_netlist_t *find_netlist_by_name(toporouter_t * r, char *name)
-{
-	FOREACH_NETLIST(r->netlists) {
-		if (!strcmp(netlist->netlist, name))
-			return netlist;
-	}
-	FOREACH_END;
-	return NULL;
-}
-
-gint toporouter_set_pair(toporouter_t * r, toporouter_netlist_t * n1, toporouter_netlist_t * n2)
-{
-	if (!n1 || !n2)
-		return 0;
-	n1->pair = n2;
-	n2->pair = n1;
-	return 1;
-}
-
-static int toporouter(int argc, char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	toporouter_t *r = toporouter_new();
-	parse_arguments(r, argc, argv);
-	import_geometry(r);
-	acquire_twonets(r);
-
-/*if(!toporouter_set_pair(r, find_netlist_by_name(r, "  DRAM_DQS_N"), find_netlist_by_name(r, "  DRAM_DQS"))) {
-    printf("Couldn't associate pair\n");
-  }*/
-
-	hybrid_router(r);
-/*
-  for(gint i=0;i<groupcount();i++) {
-   gts_surface_foreach_edge(r->layers[i].surface, space_edge, NULL);
-  }
-  {
-    int i;
-    for(i=0;i<groupcount();i++) {
-      char buffer[256];
-      sprintf(buffer, "route%d.png", i);
-      toporouter_draw_surface(r, r->layers[i].surface, buffer, 1024, 1024, 2, NULL, i, NULL);
-    }
-  }
-*/
-	toporouter_export(r);
-	toporouter_free(r);
-
-	pcb_undo_save_serial();
-	pcb_rats_destroy(pcb_false);
-	pcb_undo_restore_serial();
-	pcb_rat_add_all(pcb_false, NULL);
-	pcb_undo_restore_serial();
-	pcb_undo_inc_serial();
-	pcb_redraw();
-
-	return 0;
-}
-
-static int escape(int argc, char **argv, pcb_coord_t x, pcb_coord_t y)
-{
-	guint dir, viax, viay;
-	gdouble pitch, length, dx, dy;
-
-	if (argc != 1)
-		return 0;
-
-	dir = atoi(argv[0]);
-
-
-	PCB_PAD_ALL_LOOP(PCB->Data);
-	{
-		if (PCB_FLAG_TEST(PCB_FLAG_SELECTED, pad)) {
-			pcb_pin_t *via;
-			pcb_line_t *line;
-
-			pcb_pad_t *pad0 = element->Pad->data;
-			pcb_pad_t *pad1 = g_list_next(element->Pad)->data;
-
-			pitch = sqrt(pow(abs(pad0->Point1.X - pad1->Point1.X), 2) + pow(abs(pad0->Point1.Y - pad1->Point1.Y), 2));
-			length = sqrt(pow(pitch, 2) + pow(pitch, 2)) / 2.;
-
-			dx = length * sin(M_PI / 4.);
-			dy = length * cos(M_PI / 4.);
-
-			switch (dir) {
-			case 1:
-				viax = pad->Point1.X - dx;
-				viay = pad->Point1.Y + dy;
-				break;
-			case 3:
-				viax = pad->Point1.X + dx;
-				viay = pad->Point1.Y + dy;
-				break;
-			case 9:
-				viax = pad->Point1.X + dx;
-				viay = pad->Point1.Y - dy;
-				break;
-			case 7:
-				viax = pad->Point1.X - dx;
-				viay = pad->Point1.Y - dy;
-				break;
-			case 2:
-				viax = pad->Point1.X;
-				viay = pad->Point1.Y + (pitch / 2);
-				break;
-			case 8:
-				viax = pad->Point1.X;
-				viay = pad->Point1.Y - (pitch / 2);
-				break;
-			case 4:
-				viax = pad->Point1.X - (pitch / 2);
-				viay = pad->Point1.Y;
-				break;
-			case 6:
-				viax = pad->Point1.X + (pitch / 2);
-				viay = pad->Point1.Y;
-				break;
-			default:
-				printf("ERROR: escape() with bad direction (%d)\n", dir);
-				return 1;
-			}
-
-			if ((via = pcb_via_new(PCB->Data, viax, viay,
-															Settings.ViaThickness, 2 * Settings.Clearance,
-															0, Settings.ViaDrillingHole, NULL, pcb_no_flags())) != NULL) {
-				pcb_undo_add_obj_to_create(PCB_TYPE_VIA, via, via, via);
-/*        if (gui->shift_is_pressed ())
-            pcb_chg_obj_thermal(PCB_TYPE_VIA, via, via, via, PCB->ThermStyle);*/
-				DrawVia(via);
-				if ((line = pcb_line_new_merge(CURRENT, pad->Point1.X + 1., pad->Point1.Y + 1., viax + 1., viay + 1.,
-																					 Settings.LineThickness, 2 * Settings.Clearance, pcb_no_flags()))) {
-
-					pcb_undo_add_obj_to_create(PCB_TYPE_LINE, CURRENT, line, line);
-					DrawLine(CURRENT, line);
-
-				}
-
-			}
-
-		}
-	}
-	PCB_END_LOOP;
-	PCB_END_LOOP;
-
-	pcb_undo_inc_serial();
-	pcb_draw();
-	return 0;
-}
-
-static pcb_hid_action_t toporouter_action_list[] = {
-	{"Escape", "Select a set of pads", escape, "Pad escape", "Escape()"},
-	{"Toporouter", "Select net(s)", toporouter, "Topological autorouter", "Toporouter()"}
-};
-
-PCB_REGISTER_ACTIONS(toporouter_action_list, toporouter_cookie)
-
-static void hid_toporouter_uninit(void)
-{
-	pcb_hid_remove_actions_by_cookie(toporouter_cookie);
-}
-
-pcb_uninit_t hid_toporouter_init()
-{
-	register_toporouter_action_list();
-	return hid_toporouter_uninit;
-}
diff --git a/src_plugins/toporouter/toporouter.h b/src_plugins/toporouter/toporouter.h
deleted file mode 100644
index 4f8cc54..0000000
--- a/src_plugins/toporouter/toporouter.h
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- *                            COPYRIGHT
- *
- *  Topological Autorouter for 
- *  PCB, interactive printed circuit board design
- *  Copyright (C) 2009 Anthony Blake
- *
- *  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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Contact addresses for email:
- *  Anthony Blake, tonyb33 at gmail.com
- *
- */
-
-#ifndef PCB_TOPOROUTER_H
-#define PCB_TOPOROUTER_H
-
-#include <assert.h>
-#include <glib.h>
-#include "data.h"
-#include "macro.h"
-#include "../autoroute/autoroute.h"
-#include "box.h"
-#include "draw.h"
-#include "error.h"
-#include "find.h"
-#include "heap.h"
-#include "rtree.h"
-#include "polygon.h"
-#include "rats.h"
-#include "remove.h"
-#include "obj_pinvia_therm.h"
-#include "undo.h"
-#include "config.h"
-
-#include "gts.h"
-
-#include <stdlib.h>
-#include <getopt.h>
-
-#include <sys/time.h>
-
-#define TOPOROUTER_FLAG_VERBOSE       (1<<0)
-#define TOPOROUTER_FLAG_HARDDEST      (1<<1)
-#define TOPOROUTER_FLAG_HARDSRC       (1<<2)
-#define TOPOROUTER_FLAG_MATCH         (1<<3)
-#define TOPOROUTER_FLAG_LAYERHINT     (1<<4)
-#define TOPOROUTER_FLAG_LEASTINVALID  (1<<5)
-#define TOPOROUTER_FLAG_AFTERORDER    (1<<6)
-#define TOPOROUTER_FLAG_AFTERRUBIX    (1<<7)
-#define TOPOROUTER_FLAG_GOFAR         (1<<8)
-#define TOPOROUTER_FLAG_DETOUR        (1<<9)
-
-/* Define to 1 to enable toporouter graphical output - wait, we don't link cairo?! */
-#define TOPO_OUTPUT_ENABLED 0
-
-
-#if TOPO_OUTPUT_ENABLED
-#include <cairo.h>
-#endif
-
-#define EPSILON 0.0001f
-
-/*#define DEBUG_ROAR 1*/
-
-#define coord_distance(a,b,c,d) sqrt(pow(a-c,2)+pow(b-d,2))
-#define coord_distance2(a,b,c,d) (pow(a-c,2)+pow(b-d,2))
-
-#define tvdistance(a,b) sqrt(pow(vx(a)-vx(b),2)+pow(vy(a)-vy(b),2))
-#define tvdistance2(a,b) (pow(vx(a)-vx(b),2)+pow(vy(a)-vy(b),2))
-
-#define edge_v1(e) (GTS_SEGMENT(e)->v1)
-#define edge_v2(e) (GTS_SEGMENT(e)->v2)
-#define tedge_v1(e) (TOPOROUTER_VERTEX(GTS_SEGMENT(e)->v1))
-#define tedge_v2(e) (TOPOROUTER_VERTEX(GTS_SEGMENT(e)->v2))
-
-#define tedge(v1,v2) TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v1), GTS_VERTEX(v2)))
-
-#define edge_routing(e) (TOPOROUTER_IS_CONSTRAINT(e) ? TOPOROUTER_CONSTRAINT(e)->routing : e->routing)
-#define vrouting(v) (edge_routing(v->routingedge))
-
-#define edge_routing_next(e,list) ((list->next) ? TOPOROUTER_VERTEX(list->next->data) : TOPOROUTER_VERTEX(edge_v2(e)))
-#define edge_routing_prev(e,list) ((list->prev) ? TOPOROUTER_VERTEX(list->prev->data) : TOPOROUTER_VERTEX(edge_v1(e)))
-
-#define vx(v) (GTS_POINT(v)->x)
-#define vy(v) (GTS_POINT(v)->y)
-#define vz(v) (GTS_POINT(v)->z)
-
-#define close_enough_xy(a,b) (vx(a) > vx(b) - EPSILON && vx(a) < vx(b) + EPSILON && vy(a) > vy(b) - EPSILON && vy(a) < vy(b) + EPSILON)
-
-#define tev1x(e) (vx(tedge_v1(e))
-#define tev1y(e) (vy(tedge_v1(e))
-#define tev1z(e) (vz(tedge_v1(e))
-#define tev2x(e) (vx(tedge_v2(e))
-#define tev2y(e) (vy(tedge_v2(e))
-#define tev2z(e) (vz(tedge_v2(e))
-
-#define tvertex_intersect(a,b,c,d) (TOPOROUTER_VERTEX(vertex_intersect(GTS_VERTEX(a),GTS_VERTEX(b),GTS_VERTEX(c),GTS_VERTEX(d))))
-
-#define TOPOROUTER_IS_BBOX(obj)      (gts_object_is_from_class (obj, toporouter_bbox_class ()))
-#define TOPOROUTER_BBOX(obj)          GTS_OBJECT_CAST (obj, toporouter_bbox_t, toporouter_bbox_class ())
-#define TOPOROUTER_BBOX_CLASS(klass)  GTS_OBJECT_CLASS_CAST (klass, toporouter_bbox_class_t, toporouter_bbox_class ())
-
-typedef enum {
-	PAD,
-	PIN,
-	VIA,
-	ARC,
-	VIA_SHADOW,
-	LINE,
-	OTHER,
-	BOARD,
-	EXPANSION_AREA,
-	POLYGON,
-	TEMP
-} toporouter_term_t;
-
-struct _toporouter_bbox_t {
-	GtsBBox b;
-
-	toporouter_term_t type;
-	void *data;
-	int layer;
-
-	GtsSurface *surface;
-	GtsTriangle *enclosing;
-
-	GList *constraints;
-	GtsPoint *point, *realpoint;
-
-/*  char *netlist, *style;*/
-
-	struct _toporouter_cluster_t *cluster;
-
-};
-
-struct _toporouter_bbox_class_t {
-	GtsBBoxClass parent_class;
-};
-
-typedef struct _toporouter_bbox_t toporouter_bbox_t;
-typedef struct _toporouter_bbox_class_t toporouter_bbox_class_t;
-
-#define TOPOROUTER_IS_EDGE(obj)      (gts_object_is_from_class (obj, toporouter_edge_class ()))
-#define TOPOROUTER_EDGE(obj)          GTS_OBJECT_CAST (obj, toporouter_edge_t, toporouter_edge_class ())
-#define TOPOROUTER_EDGE_CLASS(klass)  GTS_OBJECT_CLASS_CAST (klass, toporouter_edge_class_t, toporouter_edge_class ())
-
-#define EDGE_FLAG_DIRECTCONNECTION (1<<0)
-
-struct _toporouter_edge_t {
-	GtsEdge e;
-	/*pcb_netlist_t *netlist; */
-
-	guint flags;
-
-	GList *routing;
-};
-
-struct _toporouter_edge_class_t {
-	GtsEdgeClass parent_class;
-};
-
-typedef struct _toporouter_edge_t toporouter_edge_t;
-typedef struct _toporouter_edge_class_t toporouter_edge_class_t;
-
-#define TOPOROUTER_IS_VERTEX(obj)      (gts_object_is_from_class (obj, toporouter_vertex_class ()))
-#define TOPOROUTER_VERTEX(obj)          GTS_OBJECT_CAST (obj, toporouter_vertex_t, toporouter_vertex_class ())
-#define TOPOROUTER_VERTEX_CLASS(klass)  GTS_OBJECT_CLASS_CAST (klass, toporouter_vertex_class_t, toporouter_vertex_class ())
-
-#define VERTEX_FLAG_VIZ      (1<<1)
-#define VERTEX_FLAG_CCW      (1<<2)
-#define VERTEX_FLAG_CW       (1<<3)
-#define VERTEX_FLAG_RED      (1<<4)
-#define VERTEX_FLAG_GREEN    (1<<5)
-#define VERTEX_FLAG_BLUE     (1<<6)
-#define VERTEX_FLAG_TEMP     (1<<7)
-#define VERTEX_FLAG_ROUTE    (1<<8)
-#define VERTEX_FLAG_FAKE     (1<<10)
-#define VERTEX_FLAG_SPECCUT  (1<<11)
-
-struct _toporouter_vertex_t {
-	GtsVertex v;
-	/*GList *boxes; */
-	struct _toporouter_bbox_t *bbox;
-
-	struct _toporouter_vertex_t *parent;
-	struct _toporouter_vertex_t *child;
-
-	toporouter_edge_t *routingedge;
-
-	guint flags;
-
-	gdouble gcost, hcost;
-	guint gn;
-
-	struct _toporouter_arc_t *arc;
-
-	struct _toporouter_oproute_t *oproute;
-	struct _toporouter_route_t *route;
-
-	gdouble thickness;
-
-};
-
-struct _toporouter_vertex_class_t {
-	GtsVertexClass parent_class;
-};
-
-typedef struct _toporouter_vertex_t toporouter_vertex_t;
-typedef struct _toporouter_vertex_class_t toporouter_vertex_class_t;
-
-#define TOPOROUTER_IS_CONSTRAINT(obj)      (gts_object_is_from_class (obj, toporouter_constraint_class ()))
-#define TOPOROUTER_CONSTRAINT(obj)          GTS_OBJECT_CAST (obj, toporouter_constraint_t, toporouter_constraint_class ())
-#define TOPOROUTER_CONSTRAINT_CLASS(klass)  GTS_OBJECT_CLASS_CAST (klass, toporouter_constraint_class_t, toporouter_constraint_class ())
-
-struct _toporouter_constraint_t {
-	GtsConstraint c;
-	toporouter_bbox_t *box;
-	GList *routing;
-};
-
-struct _toporouter_constraint_class_t {
-	GtsConstraintClass parent_class;
-};
-
-typedef struct {
-	gdouble x, y;
-} toporouter_spoint_t;
-
-typedef struct _toporouter_constraint_t toporouter_constraint_t;
-typedef struct _toporouter_constraint_class_t toporouter_constraint_class_t;
-
-typedef struct {
-	GtsSurface *surface;
-/*  GtsTriangle *t;*/
-/*  GtsVertex *v1, *v2, *v3;*/
-
-	GList *vertices;
-	GList *constraints;
-	GList *edges;
-
-} toporouter_layer_t;
-
-#define TOPOROUTER_VERTEX_REGION(x) ((toporouter_vertex_region_t *)x)
-typedef struct {
-
-	GList *points;
-	toporouter_vertex_t *v1, *v2;
-	toporouter_vertex_t *origin;
-
-} toporouter_vertex_region_t;
-
-struct _toporouter_rubberband_arc_t {
-	toporouter_vertex_t *pathv, *arcv;
-	gdouble r, d;
-	gint wind;
-	GList *list;
-};
-
-typedef struct _toporouter_rubberband_arc_t toporouter_rubberband_arc_t;
-#define TOPOROUTER_RUBBERBAND_ARC(x) ((toporouter_rubberband_arc_t *)x)
-
-struct _toporouter_route_t {
-
-	struct _toporouter_netlist_t *netlist;
-
-	struct _toporouter_cluster_t *src, *dest;
-	struct _toporouter_cluster_t *psrc, *pdest;
-
-	gdouble score, detourscore;
-
-	toporouter_vertex_t *curpoint;
-	GHashTable *alltemppoints;
-
-	GList *path;
-
-	guint flags;
-
-	GList *destvertices, *srcvertices;
-
-	GList *topopath;
-
-	gdouble pscore;
-	GList *ppath;
-
-	gint *ppathindices;
-};
-
-typedef struct _toporouter_route_t toporouter_route_t;
-
-#define TOPOROUTER_ROUTE(x) ((toporouter_route_t *)x)
-
-struct _toporouter_netlist_t {
-	GPtrArray *clusters, *routes;
-	char *netlist, *style;
-	GList *routed;
-
-	struct _toporouter_netlist_t *pair;
-};
-
-typedef struct _toporouter_netlist_t toporouter_netlist_t;
-
-#define TOPOROUTER_NETLIST(x) ((toporouter_netlist_t *)x)
-
-struct _toporouter_cluster_t {
-	gint c, pc;
-	GPtrArray *boxes;
-	toporouter_netlist_t *netlist;
-};
-
-typedef struct _toporouter_cluster_t toporouter_cluster_t;
-
-#define TOPOROUTER_CLUSTER(x) ((toporouter_cluster_t *)x)
-
-#define TOPOROUTER_OPROUTE(x) ((toporouter_oproute_t *)x)
-
-#define oproute_next(a,b) (b->next ? TOPOROUTER_ARC(b->next->data) : a->term2)
-#define oproute_prev(a,b) (b->prev ? TOPOROUTER_ARC(b->prev->data) : a->term1)
-
-#define TOPOROUTER_SERPINTINE(x) ((toporouter_serpintine_t *)x)
-
-struct _toporouter_serpintine_t {
-	GList *arcs;
-	gdouble x, y;
-	gdouble x0, y0, x1, y1;
-
-	gpointer start;
-	gdouble halfa, radius;
-	guint nhalfcycles;
-
-};
-typedef struct _toporouter_serpintine_t toporouter_serpintine_t;
-
-struct _toporouter_oproute_t {
-	GList *arcs;
-	toporouter_vertex_t *term1, *term2;
-	char *style;
-	char *netlist;
-	guint layergroup;
-	gdouble tof;
-	GList *path;
-
-	toporouter_serpintine_t *serp;
-};
-
-typedef struct _toporouter_oproute_t toporouter_oproute_t;
-
-
-#define TOPOROUTER_IS_ARC(obj)           (gts_object_is_from_class (obj, toporouter_arc_class()))
-#define TOPOROUTER_ARC(obj)              GTS_OBJECT_CAST (obj, toporouter_arc_t, toporouter_arc_class())
-#define TOPOROUTER_ARC_CLASS(klass)      GTS_OBJECT_CLASS_CAST (klass, toporouter_arc_class_t, toporouter_arc_class())
-
-struct _toporouter_arc_t {
-	GtsObject object;
-
-	gdouble x0, y0, x1, y1;
-	toporouter_vertex_t *centre, *v;
-	gdouble r;
-	gint dir;
-
-	GList *clearance;
-
-	toporouter_oproute_t *oproute;
-
-	toporouter_vertex_t *v1, *v2;
-};
-
-struct _toporouter_arc_class_t {
-	GtsObjectClass parent_class;
-	gboolean binary;
-};
-
-typedef struct _toporouter_arc_t toporouter_arc_t;
-typedef struct _toporouter_arc_class_t toporouter_arc_class_t;
-
-typedef struct _toporouter_t toporouter_t;
-
-
-
-typedef struct {
-	guint id;
-
-	guint *pairwise_nodetour;
-	gdouble pairwise_detour_sum;
-	gdouble score;
-	guint pairwise_fails;
-
-	toporouter_route_t *routedata;
-
-	toporouter_t *r;
-
-} toporouter_netscore_t;
-
-#define TOPOROUTER_NETSCORE(x) ((toporouter_netscore_t *)x)
-
-struct _toporouter_t {
-	GSList *bboxes;
-	GNode *bboxtree;
-
-	toporouter_layer_t *layers;
-
-	GList *paths;
-
-	GList *keepoutlayers;
-
-	guint flags;
-
-	GList *destboxes, *consumeddestboxes;
-
-	/* settings: */
-	guint viamax;
-	gdouble viacost;
-	gdouble stublength;
-	gdouble serpintine_half_amplitude;
-
-	gdouble wiring_score;
-
-	GPtrArray *routes;
-	GPtrArray *netlists;
-
-	GList *routednets, *failednets;
-
-	  gint(*netsort) (toporouter_netscore_t **, toporouter_netscore_t **);
-
-	struct timeval starttime;
-
-	FILE *debug;
-};
-
-typedef gint(*oproute_adjseg_func)
- 
-	(toporouter_t *,
-	 GList **, GList **, guint *, gdouble, gdouble, gdouble, gdouble, toporouter_oproute_t *, toporouter_oproute_t *);
-
-typedef struct {
-#ifdef CAIRO_H
-	cairo_t *cr;
-	cairo_surface_t *surface;
-#endif
-
-	double s;											/* scale factor */
-
-	int mode;
-	void *data;
-
-	char *filename;
-	double iw, ih;								/* image dimensions */
-} drawing_context_t;
-
-#define FOREACH_CLUSTER(clusters) do { \
-  toporouter_cluster_t **i; \
-  for(i = ((toporouter_cluster_t **)clusters->pdata) + clusters->len - 1; i >= (toporouter_cluster_t **)clusters->pdata && clusters->len > 0; --i) { \
-    toporouter_cluster_t *cluster = *i;
-
-#define FOREACH_BBOX(boxes) do { \
-  toporouter_bbox_t **i; \
-  for(i = ((toporouter_bbox_t **)boxes->pdata) + boxes->len - 1; i >= (toporouter_bbox_t **)boxes->pdata && boxes->len > 0; --i) { \
-    toporouter_bbox_t *box = *i;
-
-#define FOREACH_ROUTE(routes) do { \
-  toporouter_route_t **i; \
-  for(i = ((toporouter_route_t **)routes->pdata) + routes->len - 1; i >= (toporouter_route_t **)routes->pdata && routes->len > 0; --i) { \
-    toporouter_route_t *routedata = *i;
-
-#define FOREACH_NETSCORE(netscores) do { \
-  toporouter_netscore_t **i; \
-  for(i = ((toporouter_netscore_t **)netscores->pdata) + netscores->len - 1; i >= (toporouter_netscore_t **)netscores->pdata && netscores->len > 0; --i) { \
-    toporouter_netscore_t *netscore = *i;
-
-#define FOREACH_NETLIST(netlists) do { \
-  toporouter_netlist_t **i; \
-  for(i = ((toporouter_netlist_t **)netlists->pdata) + netlists->len - 1; i >= (toporouter_netlist_t **)netlists->pdata && netlists->len > 0; --i) { \
-    toporouter_netlist_t *netlist = *i;
-
-#define FOREACH_END }} while(0)
-
-#endif /* PCB_TOPOROUTER_H */
diff --git a/tests/RTT/Export.sh b/tests/RTT/Export.sh
index 779b231..85f80ba 100755
--- a/tests/RTT/Export.sh
+++ b/tests/RTT/Export.sh
@@ -5,6 +5,7 @@ TRUNK=../..
 all=0
 valg=0
 global_args="-c rc/quiet=1"
+test_announce=0
 
 if test -z "$pcb_rnd_bin"
 then
@@ -16,11 +17,24 @@ fmt_args=""
 set_fmt_args()
 {
 	case "$fmt" in
+		bboard) ext=.bbrd.png ;;
+		nelma) ext=.nelma.em ;;
 		bom) ext=.bom ;;
 		dsn) ext=.dsn ;;
 		IPC-D-356) ext=.net;;
-		ps) ext=.ps ;;
+		ps)
+			ext=.ps
+			fmt_args="-c plugins/draw_fab/omit_date=1"
+			;;
+		eps)
+			ext=.eps
+#			fmt_args="-c plugins/draw_fab/omit_date=1"
+			;;
 		XY) ext=.xy ;;
+		openscad)
+			ext=.scad
+			fmt_args="--silk_layers"
+			;;
 		png)
 			fmt_args="--dpi 1200"
 			ext=.png
@@ -51,21 +65,41 @@ move_out()
 				s/^C  File created on .*$/C  File created on <date>/
 				s/^C  IPC-D-356 Netlist generated by.*$/C  IPC-D-356 Netlist generated by <version>/
 			' $raw_out ;;
+		nelma)
+			sed -i 's@/[*] Made with PCB Nelma export HID [*]/.*@/* banner */@g' $raw_out ;;
 		gerber)
 			sed -i '
 				s/^G04 CreationDate:.*$/G04 CreationDate: <date>/
 				s/^G04 Creator:.*$/G04 Creator: <version>/
 			' $raw_out.*.gbr
+# do not save or compare the csect yet
+			rm $raw_out.*csect*.gbr
+			;;
+		ps)
+			sed -i '
+				s@%%CreationDate:.*@%%CreationDate: date@
+				s@%%Creator:.*@%%Creator: pcb-rnd@
+				s@%%Version:.*@%%Version: ver@
+				s@^[(]Created on.*@(Created on date@
+			' $raw_out
 			;;
 	esac
 
 # move the output file(s) to their final subdir (for multifile formats) and/or
 # compress them (for large text files)
 	case "$fmt" in
+		bboard)
+			mv ${raw_out%%.bbrd.png}.png $final_out
+			;;
 		gerber)
 			mkdir -p $final_out.gbr
 			mv $raw_out.*.gbr $final_out.gbr
 			;;
+		nelma)
+			mv $raw_out $final_out
+			# do not test the pngs for now
+			rm -f ${raw_out%%nelma.em}.*.png
+			;;
 		remote|ps)
 			gzip $raw_out
 			mv $raw_out.gz $final_out.gz
@@ -82,10 +116,20 @@ move_out()
 
 cmp_fmt()
 {
-	local ref="$1" out="$2" n bn
+	local ref="$1" out="$2" n bn otmp
 	case "$fmt" in
 		png)
-			echo "$ref" "$out"
+			bn=`basename $out`
+			res=`compare "$ref" "$out"  -metric AE  diff/$bn 2>&1`
+			case "$res" in
+				*widths*)
+					otmp=$out.599.png
+					convert -crop 599x599+0x0 $out  $otmp
+					res=`compare "$ref" "$otmp" -metric AE  diff/$bn 2>&1`
+					;;
+			esac
+			test "$res" -lt 8 && rm diff/$bn
+			test "$res" -lt 8
 			;;
 		gerber)
 			for n in $ref.gbr/*.gbr
@@ -94,6 +138,11 @@ cmp_fmt()
 				diff -u "$n" "$out.gbr/$bn"
 			done
 			;;
+		ps)
+			zcat "$ref.gz" > "$ref"
+			zcat "$out.gz" > "$out"
+			diff -u "$ref" "$out" && rm "$ref" "$out"
+			;;
 		*)
 			# simple text files: byte-to-byte match required
 			diff -u "$ref" "$out"
@@ -125,6 +174,7 @@ while test $# -gt 0
 do
 	case "$1"
 	in
+		-t) test_announce=1;;
 		-f|-x) fmt=$2; shift 1;;
 		-b) pcb_rnd_bin=$2; shift 1;;
 		-a) all=1;;
@@ -149,12 +199,28 @@ fi
 
 set_fmt_args
 
+if test "$test_announce" -gt 0
+then
+	echo -n "$fmt: ... "
+fi
+
+bad=0
 if test "$all" -gt 0
 then
-	for n in `ls *.lht *.pcb`
+	for n in `ls *.lht *.pcb 2>/dev/null`
 	do
-		run_test "$n"
+		run_test "$n" || bad=1
 	done
 else
-	run_test "$fn"
+	run_test "$fn" || bad=1
 fi
+
+if test $bad -gt 0
+then
+	echo "$fmt: ... BROKEN"
+else
+	echo "ok"
+fi
+
+exit $bad
+
diff --git a/tests/RTT/Makefile b/tests/RTT/Makefile
new file mode 100644
index 0000000..9bb9071
--- /dev/null
+++ b/tests/RTT/Makefile
@@ -0,0 +1,20 @@
+E = ./Export.sh -t -a
+
+all:
+
+test:
+	@make test_export && echo "*** export: QC PASS ***"
+
+test_export:
+	@$E -f bboard ; \
+	$E -f nelma ; \
+	$E -f bom ; \
+	$E -f dsn 2>/dev/null; \
+	$E -f IPC-D-356 ; \
+	$E -f eps ; \
+	$E -f ps ; \
+	$E -f XY ; \
+	$E -f openscad ; \
+	$E -f png ; \
+	$E -f gerber ; \
+	$E -f svg
diff --git a/tests/RTT/Proto.pcb.text b/tests/RTT/Proto.pcb.text
new file mode 100644
index 0000000..43496a8
--- /dev/null
+++ b/tests/RTT/Proto.pcb.text
@@ -0,0 +1,5 @@
+6731
+
+500 x 500 mils outline
+inside the outline 490 x 490 mils
+no other content
diff --git a/tests/RTT/Vailidation.txt b/tests/RTT/Vailidation.txt
index 9f2bdba..89760ae 100644
--- a/tests/RTT/Vailidation.txt
+++ b/tests/RTT/Vailidation.txt
@@ -1,4 +1,4 @@
-# Validation state of references
+ Validation state of references
 #
 # Each line is a file from ref/, in the following format:
 #  The first word is the file name, relative to ref/
@@ -26,8 +26,46 @@ elem_pads_ds.bom good r5652
 elem_pins.bom good r5652
 elem_sides_smd.bom good r5652
 elem_sides_trh.bom good r5652
-arc_f_clear.bom good r5652
-arc_normal.bom good r5652
-arc_offpage.bom good r5652
-arc_sizes.bom good r5652
-arc_angles.bom good r5452
+arc_f_clear.bom good r6630
+arc_normal.bom good r6630
+arc_offpage.bom good r6630
+arc_sizes.bom good r6630
+arc_angles.bom good r6630
+arc_sizes.svg broken r6023 ellipticals not handled
+arc_angles.png good r6630
+arc_f_clear.png bad r6630
+arc_normal.png good r6630
+arc_offpage.png good r6630
+arc_sizes.png good r6630
+coord_rounding.png good r6630
+clearance.png bad r6630 missing pcb & text file?!
+elem_pads_ds.png good r6630
+elem_pads.png good r6630
+elem_pins.png good r6630
+elem_sides_smd.png good r6630
+elem_sides_trh.png good r6630
+layer_copper.png good r6630
+layer_outline.png good r6630
+layer_spc.png good r6630
+line_f_clear.png good r6630
+line_normal.png good r6630
+line_offpage.png good r6630
+line_overlap1.png good r6630
+line_overlap2.png good r6630
+line_overlap3.png good r6630
+line_overlap4.png good r6630
+line_zerolen.png good r6630
+netlist.png good r6630
+netlist_ba.png good r6630
+poly_hole.png good r6630
+poly_rect.png good r6630
+poly_triangle.png good r6630
+Proto.png good r6731
+rat.png good r6731
+text_rot.png good r6731
+text_scale.png good r6731
+text_sides.png good r6731
+thermal_last.png good r6731
+thermal_layer.png good r6731
+
+
diff --git a/tests/RTT/arc_angles.pcb.text b/tests/RTT/arc_angles.pcb.text
new file mode 100644
index 0000000..052a776
--- /dev/null
+++ b/tests/RTT/arc_angles.pcb.text
@@ -0,0 +1,19 @@
+
+right circle
+110mils h
+110mils v
+~10mils thick
+
+left circle
+110 mils h
+110 mils v (measurement problem)
+~10mils thick
+
+central dot
+~10mils
+
+air gap between right circle and central dot
+90mils
+
+air gap between left circle and central dot
+90mils
diff --git a/tests/RTT/arc_f_clear.pcb.text b/tests/RTT/arc_f_clear.pcb.text
new file mode 100644
index 0000000..d34da35
--- /dev/null
+++ b/tests/RTT/arc_f_clear.pcb.text
@@ -0,0 +1,22 @@
+polygone
+width 450mils
+height 325mils
+
+small near circle completely in polygon
+line width 10mils
+width 60mils
+clearance on the left ~20mils
+clearance on the right ~20.05mils
+clearance on the top ~20.05mils
+clearance on the bottom 20.05mils
+
+longer arc completely in polygon
+line width ~135mils
+width 135mils
+height 
+clearance on the bottom right end ~20.2mils
+clearance on the top right end 
+clearance on the end right end 
+clearance on the right top end ~20.05mils
+clearance on the left top end 20mils
+
diff --git a/tests/RTT/arc_normal.pcb.text b/tests/RTT/arc_normal.pcb.text
new file mode 100644
index 0000000..aa57e31
--- /dev/null
+++ b/tests/RTT/arc_normal.pcb.text
@@ -0,0 +1,25 @@
+outline 500 x 500 mils
+
+upper left arc
+102.60 mils tall
+118.50 mils wide
+20 mil thickness
+
+upper right arc
+190.20 mils wide
+112.20 mils tall
+30mils thick
+
+lower left arc
+135 mils tall
+135 mils wide
+10mils thick
+
+lower right arc (near circle)
+10mils thick
+about 60mils tall
+about 60mils wide (duh)
+
+
+
+
diff --git a/tests/RTT/arc_offpage.pcb.text b/tests/RTT/arc_offpage.pcb.text
new file mode 100644
index 0000000..3b832d6
--- /dev/null
+++ b/tests/RTT/arc_offpage.pcb.text
@@ -0,0 +1,5 @@
+arc
+10mil line width
+155mil tall
+155mil pixels wide
+
diff --git a/tests/RTT/arc_sizes.pcb.text b/tests/RTT/arc_sizes.pcb.text
new file mode 100644
index 0000000..7b960f6
--- /dev/null
+++ b/tests/RTT/arc_sizes.pcb.text
@@ -0,0 +1,17 @@
+
+weird dot thing in the far right
+10mil across
+10mil tall
+
+weird dot to line (horizontal) 108 pixels
+
+horizontal line
+60mil long
+10mil wide
+
+vertical line
+10mil long
+60mil wide
+
+
+
diff --git a/tests/RTT/coord_rounding.pcb.text b/tests/RTT/coord_rounding.pcb.text
new file mode 100644
index 0000000..b1117d7
--- /dev/null
+++ b/tests/RTT/coord_rounding.pcb.text
@@ -0,0 +1,6 @@
+
+weird dot thing
+39.8 mil tall
+43.75 mil wide
+
+
diff --git a/tests/RTT/elem_pads.pcb.text b/tests/RTT/elem_pads.pcb.text
new file mode 100644
index 0000000..494ed6b
--- /dev/null
+++ b/tests/RTT/elem_pads.pcb.text
@@ -0,0 +1,9 @@
+R1 pads
+51.20 x 74.80 mils (approximately)
+
+U1 pads
+15 x 35 mils
+pad 5 upper to nearest silk screen corner 1.5 x 1.5 mils
+pad 5 distance to pad 4 is 11 mils
+
+
diff --git a/tests/RTT/elem_pads_ds.pcb b/tests/RTT/elem_pads_ds.pcb
index 0166de8..74a2975 100644
--- a/tests/RTT/elem_pads_ds.pcb
+++ b/tests/RTT/elem_pads_ds.pcb
@@ -1,27 +1,339 @@
-# release: pcb-rnd 1.1.1
+# release: pcb-rnd 1.1.3
 
 # To read pcb files, the pcb version (or the git source date) must be >= the file version
 FileVersion[20070407]
 
-PCB["element with pads on both sides" 12700000nm 12700000nm]
+PCB["element with pads on both sides" 50000 50000]
 
-Grid[635000nm 0 0 1]
-Cursor[0 0 0.000000]
+Grid[2500 0 0 1]
+Cursor[0 10000 0.000000]
 PolyArea[3100.006200]
 Thermal[0.500000]
-DRC[304800nm 228600nm 254000nm 177800nm 381000nm 254000nm]
+DRC[1200 900 1000 700 1500 1000]
 Flags("nameonpcb,clearnew,snappin")
 Groups("1,3,c:2,4,s:5:6:7")
-Styles["style1,254000nm,1999995nm,800100nm,508000nm:style2,508000nm,2199894nm,999997nm,508000nm:style3,2032000nm,3500119nm,1199895nm,635000nm:style4,2540000nm,1625600nm,800100nm,2540000nm"]
+Styles["style1,1000,7874,3150,2000:style2,2000,8661,3937,2000:style3,8000,13780,4724,2500:style4,10000,6400,3150,10000"]
 
+Symbol[' ' 1800]
+(
+)
+Symbol['1' 1200]
+(
+	SymbolLine[0 800 800 0 800]
+	SymbolLine[800 0 800 4000 800]
+	SymbolLine[0 4000 1500 4000 800]
+)
+Symbol['2' 1200]
+(
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 2000 0 800]
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[2500 500 2500 1500 800]
+	SymbolLine[0 4000 2500 1500 800]
+	SymbolLine[0 4000 2500 4000 800]
+)
+Symbol['3' 1200]
+(
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[500 1800 1500 1800 800]
+	SymbolLine[2000 500 2000 1300 800]
+	SymbolLine[2000 2300 2000 3500 800]
+	SymbolLine[2000 2300 1500 1800 800]
+	SymbolLine[2000 1300 1500 1800 800]
+)
+Symbol['4' 1200]
+(
+	SymbolLine[0 2500 2000 0 800]
+	SymbolLine[0 2500 2500 2500 800]
+	SymbolLine[2000 0 2000 4000 800]
+)
+Symbol['5' 1200]
+(
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[0 0 0 2000 800]
+	SymbolLine[0 2000 500 1500 800]
+	SymbolLine[500 1500 1500 1500 800]
+	SymbolLine[1500 1500 2000 2000 800]
+	SymbolLine[2000 2000 2000 3500 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+)
+Symbol['6' 1200]
+(
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[0 500 0 3500 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[1500 1800 2000 2300 800]
+	SymbolLine[0 1800 1500 1800 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[2000 2300 2000 3500 800]
+)
+Symbol['7' 1200]
+(
+	SymbolLine[500 4000 2500 0 800]
+	SymbolLine[0 0 2500 0 800]
+)
+Symbol['8' 1200]
+(
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[0 2700 0 3500 800]
+	SymbolLine[0 2700 700 2000 800]
+	SymbolLine[700 2000 1300 2000 800]
+	SymbolLine[1300 2000 2000 2700 800]
+	SymbolLine[2000 2700 2000 3500 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[0 1300 700 2000 800]
+	SymbolLine[0 500 0 1300 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[2000 500 2000 1300 800]
+	SymbolLine[1300 2000 2000 1300 800]
+)
+Symbol['9' 1200]
+(
+	SymbolLine[500 4000 2000 2000 800]
+	SymbolLine[2000 500 2000 2000 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[0 500 0 1500 800]
+	SymbolLine[0 1500 500 2000 800]
+	SymbolLine[500 2000 2000 2000 800]
+)
+Symbol['A' 1200]
+(
+	SymbolLine[0 1000 0 4000 800]
+	SymbolLine[0 1000 700 0 800]
+	SymbolLine[700 0 1800 0 800]
+	SymbolLine[1800 0 2500 1000 800]
+	SymbolLine[2500 1000 2500 4000 800]
+	SymbolLine[0 2000 2500 2000 800]
+)
+Symbol['B' 1200]
+(
+	SymbolLine[0 4000 2000 4000 800]
+	SymbolLine[2000 4000 2500 3500 800]
+	SymbolLine[2500 2300 2500 3500 800]
+	SymbolLine[2000 1800 2500 2300 800]
+	SymbolLine[500 1800 2000 1800 800]
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[2500 500 2500 1300 800]
+	SymbolLine[2000 1800 2500 1300 800]
+)
+Symbol['C' 1200]
+(
+	SymbolLine[700 4000 2000 4000 800]
+	SymbolLine[0 3300 700 4000 800]
+	SymbolLine[0 700 0 3300 800]
+	SymbolLine[0 700 700 0 800]
+	SymbolLine[700 0 2000 0 800]
+)
+Symbol['D' 1200]
+(
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[1800 0 2500 700 800]
+	SymbolLine[2500 700 2500 3300 800]
+	SymbolLine[1800 4000 2500 3300 800]
+	SymbolLine[0 4000 1800 4000 800]
+	SymbolLine[0 0 1800 0 800]
+)
+Symbol['E' 1200]
+(
+	SymbolLine[0 1800 1500 1800 800]
+	SymbolLine[0 4000 2000 4000 800]
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 0 2000 0 800]
+)
+Symbol['F' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[0 1800 1500 1800 800]
+)
+Symbol['G' 1200]
+(
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[500 0 2000 0 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[0 500 0 3500 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[500 4000 2000 4000 800]
+	SymbolLine[2000 4000 2500 3500 800]
+	SymbolLine[2500 2500 2500 3500 800]
+	SymbolLine[2000 2000 2500 2500 800]
+	SymbolLine[1000 2000 2000 2000 800]
+)
+Symbol['H' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[2500 0 2500 4000 800]
+	SymbolLine[0 2000 2500 2000 800]
+)
+Symbol['I' 1200]
+(
+	SymbolLine[0 0 1000 0 800]
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[0 4000 1000 4000 800]
+)
+Symbol['J' 1200]
+(
+	SymbolLine[700 0 1500 0 800]
+	SymbolLine[1500 0 1500 3500 800]
+	SymbolLine[1000 4000 1500 3500 800]
+	SymbolLine[500 4000 1000 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[0 3500 0 3000 800]
+)
+Symbol['K' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 2000 2000 0 800]
+	SymbolLine[0 2000 2000 4000 800]
+)
+Symbol['L' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 4000 2000 4000 800]
+)
+Symbol['M' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 0 1500 2000 800]
+	SymbolLine[1500 2000 3000 0 800]
+	SymbolLine[3000 0 3000 4000 800]
+)
+Symbol['N' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 0 2500 4000 800]
+	SymbolLine[2500 0 2500 4000 800]
+)
+Symbol['O' 1200]
+(
+	SymbolLine[0 500 0 3500 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[2000 500 2000 3500 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+)
+Symbol['P' 1200]
+(
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[2500 500 2500 1500 800]
+	SymbolLine[2000 2000 2500 1500 800]
+	SymbolLine[500 2000 2000 2000 800]
+)
+Symbol['Q' 1200]
+(
+	SymbolLine[0 500 0 3500 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[2000 500 2000 3000 800]
+	SymbolLine[1000 4000 2000 3000 800]
+	SymbolLine[500 4000 1000 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[1000 2500 2000 4000 800]
+)
+Symbol['R' 1200]
+(
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[2500 500 2500 1500 800]
+	SymbolLine[2000 2000 2500 1500 800]
+	SymbolLine[500 2000 2000 2000 800]
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[1300 2000 2500 4000 800]
+)
+Symbol['S' 1200]
+(
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[500 0 2000 0 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[0 500 0 1500 800]
+	SymbolLine[0 1500 500 2000 800]
+	SymbolLine[500 2000 2000 2000 800]
+	SymbolLine[2000 2000 2500 2500 800]
+	SymbolLine[2500 2500 2500 3500 800]
+	SymbolLine[2000 4000 2500 3500 800]
+	SymbolLine[500 4000 2000 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+)
+Symbol['T' 1200]
+(
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[1000 0 1000 4000 800]
+)
+Symbol['U' 1200]
+(
+	SymbolLine[0 0 0 3500 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[2000 0 2000 3500 800]
+)
+Symbol['V' 1200]
+(
+	SymbolLine[0 0 1000 4000 800]
+	SymbolLine[1000 4000 2000 0 800]
+)
+Symbol['W' 1200]
+(
+	SymbolLine[0 0 0 2000 800]
+	SymbolLine[0 2000 500 4000 800]
+	SymbolLine[500 4000 1500 2000 800]
+	SymbolLine[1500 2000 2500 4000 800]
+	SymbolLine[2500 4000 3000 2000 800]
+	SymbolLine[3000 2000 3000 0 800]
+)
+Symbol['X' 1200]
+(
+	SymbolLine[0 4000 2500 0 800]
+	SymbolLine[0 0 2500 4000 800]
+)
+Symbol['Y' 1200]
+(
+	SymbolLine[0 0 1000 2000 800]
+	SymbolLine[1000 2000 2000 0 800]
+	SymbolLine[1000 2000 1000 4000 800]
+)
+Symbol['Z' 1200]
+(
+	SymbolLine[0 0 2500 0 800]
+	SymbolLine[0 4000 2500 0 800]
+	SymbolLine[0 4000 2500 4000 800]
+)
 Attribute("PCB::grid::unit" "mil")
 Attribute("PCB::conf::editor/draw_grid" "true")
+Attribute("PCB::loader" "geda/pcb - mainline (centimils)")
+Attribute("PCB::conf::editor/show_solder_side" "0")
+Attribute("PCB::conf::editor/buffer_number" "0")
+Attribute("PCB::conf::editor/view/flip_x" "0")
+Attribute("PCB::conf::editor/view/flip_y" "0")
 
-Element["" "" "" "" 4445000nm 3810000nm 0 0 0 100 ""]
+Element["" "" "E1" "" 17500 15000 0 -7500 0 100 ""]
 (
-	Pad[0 0 1905000nm 0 254000nm 1016000nm 1270000nm "" "1" ""]
-	Pad[2540000nm 635000nm 2540000nm 2540000nm 254000nm 1016000nm 1270000nm "" "2" "onsolder,edge2"]
-	ElementLine [0 0 0 2540000nm 254000nm]
+	Pad[0 0 7500 0 1000 4000 5000 "" "1" ""]
+	Pad[10000 2500 10000 10000 1000 4000 5000 "" "2" "onsolder,edge2"]
+	ElementLine [0 0 0 10000 1000]
 
 	)
 Layer(1 "comp1")
diff --git a/tests/RTT/elem_pads_ds.pcb.text b/tests/RTT/elem_pads_ds.pcb.text
new file mode 100644
index 0000000..5f94490
--- /dev/null
+++ b/tests/RTT/elem_pads_ds.pcb.text
@@ -0,0 +1,10 @@
+E1
+2 pads 1 silk line + text (E1)
+
+silk line 110 mils long 10 mils wide
+
+copper pads 85 mils long 10 mils wide
+
+pad 1 shares it's terminus with the silk line
+
+pad 2's highest point is 95 x 15 mils over from the inside corner of pad 1 & the silk line
diff --git a/tests/RTT/elem_pins.pcb.text b/tests/RTT/elem_pins.pcb.text
new file mode 100644
index 0000000..b3cf3b2
--- /dev/null
+++ b/tests/RTT/elem_pins.pcb.text
@@ -0,0 +1,11 @@
+U1
+5 x 5 mils distance from silk inside top corner to pin 1
+pin 1 dimensions 80 x 80 mils
+pin 2 80 mil circle
+pin 1 to pin 2 distance 220 mils
+
+U2
+pin 1 extremes 80 mils tall 120 mils wide
+pin 2 extremes 120 mills tall 160 mils wide
+pin 1 to pin 2 distance 140 mils
+pin 1 to pin 2 vertical offset 0 mils
diff --git a/tests/RTT/elem_sides_smd.pcb.text b/tests/RTT/elem_sides_smd.pcb.text
new file mode 100644
index 0000000..abc3217
--- /dev/null
+++ b/tests/RTT/elem_sides_smd.pcb.text
@@ -0,0 +1,7 @@
+R1
+pad1 51.20 mils x 74.80 mils approximately
+pad2 51.20 mils x 74.80 mils approximately
+
+R2 - on the bottom
+pad1 51.20 mils x 74.80 mils approximately
+pad2 51.20 mils x 74.80 mils approximately
diff --git a/tests/RTT/elem_sides_trh.pcb.text b/tests/RTT/elem_sides_trh.pcb.text
new file mode 100644
index 0000000..5c08b7c
--- /dev/null
+++ b/tests/RTT/elem_sides_trh.pcb.text
@@ -0,0 +1,14 @@
+r6630
+
+U1
+5 x 5 mils distance from silk inside top corner to pin 1
+pin 1 dimensions 80 x 80 mils
+pin 2 80 mil circle
+pin 1 to pin 2 distance 220 mils
+
+U2
+pin 1 is 120 mils down from U1 Pin 1
+pin 1 is 80 x 80 mils
+pin 2 is an 80 mil circle
+pin 1 to pin 2 distance 220 mils
+
diff --git a/tests/RTT/layer_copper.pcb.text b/tests/RTT/layer_copper.pcb.text
new file mode 100644
index 0000000..28080e9
--- /dev/null
+++ b/tests/RTT/layer_copper.pcb.text
@@ -0,0 +1,7 @@
+3 lines each on a different layer
+
+highest point on red to highest point on green
+50 x 75
+
+highest point on red to "nose" (left side) of blue
+20 x 5
diff --git a/tests/RTT/layer_outline.pcb.text b/tests/RTT/layer_outline.pcb.text
new file mode 100644
index 0000000..1802f58
--- /dev/null
+++ b/tests/RTT/layer_outline.pcb.text
@@ -0,0 +1,4 @@
+board outline
+right triangle
+300 mils tall
+300 mils wide
diff --git a/tests/RTT/layer_silk.pcb.text b/tests/RTT/layer_silk.pcb.text
new file mode 100644
index 0000000..9125b95
--- /dev/null
+++ b/tests/RTT/layer_silk.pcb.text
@@ -0,0 +1,5 @@
+
+line
+width 10mils
+length 385 mils
+
diff --git a/tests/RTT/layer_spc.pcb.text b/tests/RTT/layer_spc.pcb.text
new file mode 100644
index 0000000..6bd1dc3
--- /dev/null
+++ b/tests/RTT/layer_spc.pcb.text
@@ -0,0 +1,2 @@
+
+This is blank. It should be 500 mils by 500 mils
diff --git a/tests/RTT/line_f_clear.pcb.text b/tests/RTT/line_f_clear.pcb.text
new file mode 100644
index 0000000..091bb6f
--- /dev/null
+++ b/tests/RTT/line_f_clear.pcb.text
@@ -0,0 +1,20 @@
+rectangle
+width 
+height 
+
+veritcal line
+width 10mils
+length 260mils
+clearance 42/42 mils (left/right)
+
+horizontal line
+width ~15mils
+length 290mils
+clearance 12/12 mils (top/bottom)
+
+left diangonal line
+45 degrees
+
+right diagonal line
+? degrees
+
diff --git a/tests/RTT/line_normal.pcb.text b/tests/RTT/line_normal.pcb.text
new file mode 100644
index 0000000..684c7cc
--- /dev/null
+++ b/tests/RTT/line_normal.pcb.text
@@ -0,0 +1,13 @@
+horizontal line
+290 mils
+15 mil thickness
+
+vertical line
+260 mils 
+10 mil thickness
+
+fine diagonal line
+5 mils
+
+thick diagonal line
+20 mils
diff --git a/tests/RTT/line_offpage.pcb.text b/tests/RTT/line_offpage.pcb.text
new file mode 100644
index 0000000..ae9f861
--- /dev/null
+++ b/tests/RTT/line_offpage.pcb.text
@@ -0,0 +1,3 @@
+10 mil line
+405 mils on the page (more off)
+
diff --git a/tests/RTT/line_overlap1.pcb.text b/tests/RTT/line_overlap1.pcb.text
new file mode 100644
index 0000000..f33f839
--- /dev/null
+++ b/tests/RTT/line_overlap1.pcb.text
@@ -0,0 +1,4 @@
+15 mil width
+115 mil length
+
+(it is actually 2 traces that should export as 1)
diff --git a/tests/RTT/line_overlap2.pcb.text b/tests/RTT/line_overlap2.pcb.text
new file mode 100644
index 0000000..13e4a34
--- /dev/null
+++ b/tests/RTT/line_overlap2.pcb.text
@@ -0,0 +1,4 @@
+15 mil width
+165 mil length
+
+(it is actually 3 traces that should export as 1)
diff --git a/tests/RTT/line_overlap3.pcb.text b/tests/RTT/line_overlap3.pcb.text
new file mode 100644
index 0000000..db55c2b
--- /dev/null
+++ b/tests/RTT/line_overlap3.pcb.text
@@ -0,0 +1,3 @@
+15 mil width
+165 mil length
+
diff --git a/tests/RTT/line_overlap4.pcb.text b/tests/RTT/line_overlap4.pcb.text
new file mode 100644
index 0000000..c0b3297
--- /dev/null
+++ b/tests/RTT/line_overlap4.pcb.text
@@ -0,0 +1,6 @@
+15 mil width
+165 mil length
+15 mil clearance
+
+in a poly
+150 x 175 mils
diff --git a/tests/RTT/line_zerolen.pcb.text b/tests/RTT/line_zerolen.pcb.text
new file mode 100644
index 0000000..366f85b
--- /dev/null
+++ b/tests/RTT/line_zerolen.pcb.text
@@ -0,0 +1 @@
+15 mil diameter point made of a trace with zero length
diff --git a/tests/RTT/netlist.pcb.text b/tests/RTT/netlist.pcb.text
new file mode 100644
index 0000000..105422c
--- /dev/null
+++ b/tests/RTT/netlist.pcb.text
@@ -0,0 +1,8 @@
+U1
+Inside silk screen corner to Pin1 top corner 5 x 5 milsooo
+Pin1 80 x 80 mils
+Pin1 hole 39.40 mils in diameter
+Pin2 to Pin1 distance 20 mils
+Pin2 80 mil circle
+Pin2 to Pin3 distance 220 mils
+Pin2 hole 39.40 mils in diameter
diff --git a/tests/RTT/netlist_ba.pcb.text b/tests/RTT/netlist_ba.pcb.text
new file mode 100644
index 0000000..105422c
--- /dev/null
+++ b/tests/RTT/netlist_ba.pcb.text
@@ -0,0 +1,8 @@
+U1
+Inside silk screen corner to Pin1 top corner 5 x 5 milsooo
+Pin1 80 x 80 mils
+Pin1 hole 39.40 mils in diameter
+Pin2 to Pin1 distance 20 mils
+Pin2 80 mil circle
+Pin2 to Pin3 distance 220 mils
+Pin2 hole 39.40 mils in diameter
diff --git a/tests/RTT/poly_hole.pcb b/tests/RTT/poly_hole.pcb
index 645ae0f..000012e 100644
--- a/tests/RTT/poly_hole.pcb
+++ b/tests/RTT/poly_hole.pcb
@@ -1,53 +1,361 @@
-# release: pcb-rnd 1.1.1
+# release: pcb-rnd 1.2.0
 
 # To read pcb files, the pcb version (or the git source date) must be >= the file version
 FileVersion[20100606]
 
-PCB["Polygons with holes" 12700000nm 12700000nm]
+PCB["Polygons with holes" 50000 50000]
 
-Grid[635000nm 0 0 1]
+Grid[2500 0 0 1]
 Cursor[0 0 0.000000]
 PolyArea[3100.006200]
 Thermal[0.500000]
-DRC[304800nm 228600nm 254000nm 177800nm 381000nm 254000nm]
+DRC[1200 900 1000 700 1500 1000]
 Flags("nameonpcb,alldirection,clearnew,snappin")
 Groups("1,3,c:2,4,s:5:6:7")
-Styles["style1,254000nm,1999994nm,800100nm,508000nm:style2,508000nm,2199894nm,999996nm,508000nm:style3,2032000nm,3500118nm,1199894nm,635000nm:style4,2540000nm,1625600nm,800100nm,2540000nm"]
+Styles["style1,1000,7874,3150,2000:style2,2000,8661,3937,2000:style3,8000,13780,4724,2500:style4,10000,6400,3150,10000"]
 
+Symbol[' ' 1800]
+(
+)
+Symbol['1' 1200]
+(
+	SymbolLine[0 800 800 0 800]
+	SymbolLine[800 0 800 4000 800]
+	SymbolLine[0 4000 1500 4000 800]
+)
+Symbol['2' 1200]
+(
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 2000 0 800]
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[2500 500 2500 1500 800]
+	SymbolLine[0 4000 2500 1500 800]
+	SymbolLine[0 4000 2500 4000 800]
+)
+Symbol['3' 1200]
+(
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[500 1800 1500 1800 800]
+	SymbolLine[2000 500 2000 1300 800]
+	SymbolLine[2000 2300 2000 3500 800]
+	SymbolLine[2000 2300 1500 1800 800]
+	SymbolLine[2000 1300 1500 1800 800]
+)
+Symbol['4' 1200]
+(
+	SymbolLine[0 2500 2000 0 800]
+	SymbolLine[0 2500 2500 2500 800]
+	SymbolLine[2000 0 2000 4000 800]
+)
+Symbol['5' 1200]
+(
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[0 0 0 2000 800]
+	SymbolLine[0 2000 500 1500 800]
+	SymbolLine[500 1500 1500 1500 800]
+	SymbolLine[1500 1500 2000 2000 800]
+	SymbolLine[2000 2000 2000 3500 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+)
+Symbol['6' 1200]
+(
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[0 500 0 3500 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[1500 1800 2000 2300 800]
+	SymbolLine[0 1800 1500 1800 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[2000 2300 2000 3500 800]
+)
+Symbol['7' 1200]
+(
+	SymbolLine[500 4000 2500 0 800]
+	SymbolLine[0 0 2500 0 800]
+)
+Symbol['8' 1200]
+(
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[0 2700 0 3500 800]
+	SymbolLine[0 2700 700 2000 800]
+	SymbolLine[700 2000 1300 2000 800]
+	SymbolLine[1300 2000 2000 2700 800]
+	SymbolLine[2000 2700 2000 3500 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[0 1300 700 2000 800]
+	SymbolLine[0 500 0 1300 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[2000 500 2000 1300 800]
+	SymbolLine[1300 2000 2000 1300 800]
+)
+Symbol['9' 1200]
+(
+	SymbolLine[500 4000 2000 2000 800]
+	SymbolLine[2000 500 2000 2000 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[0 500 0 1500 800]
+	SymbolLine[0 1500 500 2000 800]
+	SymbolLine[500 2000 2000 2000 800]
+)
+Symbol['A' 1200]
+(
+	SymbolLine[0 1000 0 4000 800]
+	SymbolLine[0 1000 700 0 800]
+	SymbolLine[700 0 1800 0 800]
+	SymbolLine[1800 0 2500 1000 800]
+	SymbolLine[2500 1000 2500 4000 800]
+	SymbolLine[0 2000 2500 2000 800]
+)
+Symbol['B' 1200]
+(
+	SymbolLine[0 4000 2000 4000 800]
+	SymbolLine[2000 4000 2500 3500 800]
+	SymbolLine[2500 2300 2500 3500 800]
+	SymbolLine[2000 1800 2500 2300 800]
+	SymbolLine[500 1800 2000 1800 800]
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[2500 500 2500 1300 800]
+	SymbolLine[2000 1800 2500 1300 800]
+)
+Symbol['C' 1200]
+(
+	SymbolLine[700 4000 2000 4000 800]
+	SymbolLine[0 3300 700 4000 800]
+	SymbolLine[0 700 0 3300 800]
+	SymbolLine[0 700 700 0 800]
+	SymbolLine[700 0 2000 0 800]
+)
+Symbol['D' 1200]
+(
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[1800 0 2500 700 800]
+	SymbolLine[2500 700 2500 3300 800]
+	SymbolLine[1800 4000 2500 3300 800]
+	SymbolLine[0 4000 1800 4000 800]
+	SymbolLine[0 0 1800 0 800]
+)
+Symbol['E' 1200]
+(
+	SymbolLine[0 1800 1500 1800 800]
+	SymbolLine[0 4000 2000 4000 800]
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 0 2000 0 800]
+)
+Symbol['F' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[0 1800 1500 1800 800]
+)
+Symbol['G' 1200]
+(
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[500 0 2000 0 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[0 500 0 3500 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[500 4000 2000 4000 800]
+	SymbolLine[2000 4000 2500 3500 800]
+	SymbolLine[2500 2500 2500 3500 800]
+	SymbolLine[2000 2000 2500 2500 800]
+	SymbolLine[1000 2000 2000 2000 800]
+)
+Symbol['H' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[2500 0 2500 4000 800]
+	SymbolLine[0 2000 2500 2000 800]
+)
+Symbol['I' 1200]
+(
+	SymbolLine[0 0 1000 0 800]
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[0 4000 1000 4000 800]
+)
+Symbol['J' 1200]
+(
+	SymbolLine[700 0 1500 0 800]
+	SymbolLine[1500 0 1500 3500 800]
+	SymbolLine[1000 4000 1500 3500 800]
+	SymbolLine[500 4000 1000 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[0 3500 0 3000 800]
+)
+Symbol['K' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 2000 2000 0 800]
+	SymbolLine[0 2000 2000 4000 800]
+)
+Symbol['L' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 4000 2000 4000 800]
+)
+Symbol['M' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 0 1500 2000 800]
+	SymbolLine[1500 2000 3000 0 800]
+	SymbolLine[3000 0 3000 4000 800]
+)
+Symbol['N' 1200]
+(
+	SymbolLine[0 0 0 4000 800]
+	SymbolLine[0 0 2500 4000 800]
+	SymbolLine[2500 0 2500 4000 800]
+)
+Symbol['O' 1200]
+(
+	SymbolLine[0 500 0 3500 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[2000 500 2000 3500 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+)
+Symbol['P' 1200]
+(
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[2500 500 2500 1500 800]
+	SymbolLine[2000 2000 2500 1500 800]
+	SymbolLine[500 2000 2000 2000 800]
+)
+Symbol['Q' 1200]
+(
+	SymbolLine[0 500 0 3500 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[500 0 1500 0 800]
+	SymbolLine[1500 0 2000 500 800]
+	SymbolLine[2000 500 2000 3000 800]
+	SymbolLine[1000 4000 2000 3000 800]
+	SymbolLine[500 4000 1000 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[1000 2500 2000 4000 800]
+)
+Symbol['R' 1200]
+(
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[2500 500 2500 1500 800]
+	SymbolLine[2000 2000 2500 1500 800]
+	SymbolLine[500 2000 2000 2000 800]
+	SymbolLine[500 0 500 4000 800]
+	SymbolLine[1300 2000 2500 4000 800]
+)
+Symbol['S' 1200]
+(
+	SymbolLine[2000 0 2500 500 800]
+	SymbolLine[500 0 2000 0 800]
+	SymbolLine[0 500 500 0 800]
+	SymbolLine[0 500 0 1500 800]
+	SymbolLine[0 1500 500 2000 800]
+	SymbolLine[500 2000 2000 2000 800]
+	SymbolLine[2000 2000 2500 2500 800]
+	SymbolLine[2500 2500 2500 3500 800]
+	SymbolLine[2000 4000 2500 3500 800]
+	SymbolLine[500 4000 2000 4000 800]
+	SymbolLine[0 3500 500 4000 800]
+)
+Symbol['T' 1200]
+(
+	SymbolLine[0 0 2000 0 800]
+	SymbolLine[1000 0 1000 4000 800]
+)
+Symbol['U' 1200]
+(
+	SymbolLine[0 0 0 3500 800]
+	SymbolLine[0 3500 500 4000 800]
+	SymbolLine[500 4000 1500 4000 800]
+	SymbolLine[1500 4000 2000 3500 800]
+	SymbolLine[2000 0 2000 3500 800]
+)
+Symbol['V' 1200]
+(
+	SymbolLine[0 0 1000 4000 800]
+	SymbolLine[1000 4000 2000 0 800]
+)
+Symbol['W' 1200]
+(
+	SymbolLine[0 0 0 2000 800]
+	SymbolLine[0 2000 500 4000 800]
+	SymbolLine[500 4000 1500 2000 800]
+	SymbolLine[1500 2000 2500 4000 800]
+	SymbolLine[2500 4000 3000 2000 800]
+	SymbolLine[3000 2000 3000 0 800]
+)
+Symbol['X' 1200]
+(
+	SymbolLine[0 4000 2500 0 800]
+	SymbolLine[0 0 2500 4000 800]
+)
+Symbol['Y' 1200]
+(
+	SymbolLine[0 0 1000 2000 800]
+	SymbolLine[1000 2000 2000 0 800]
+	SymbolLine[1000 2000 1000 4000 800]
+)
+Symbol['Z' 1200]
+(
+	SymbolLine[0 0 2500 0 800]
+	SymbolLine[0 4000 2500 0 800]
+	SymbolLine[0 4000 2500 4000 800]
+)
 Attribute("PCB::grid::unit" "mil")
 Attribute("PCB::conf::editor/draw_grid" "true")
+Attribute("PCB::loader" "geda/pcb - mainline (centimils)")
 Layer(1 "comp1")
 (
 	Polygon("clearpoly")
 	(
-		[635000nm 635000nm] [3175000nm 635000nm] [635000nm 3175000nm] 
+		[2500 2500] [12500 2500] [2500 12500] 
 		Hole (
-			[1270000nm 1270000nm] [1270000nm 1905000nm] [1905000nm 1270000nm] 
+			[5000 5000] [5000 7500] [7500 5000] 
 		)
 	)
 	Polygon("clearpoly")
 	(
-		[635000nm 3810000nm] [3810000nm 635000nm] [3810000nm 3810000nm] 
+		[2500 15000] [15000 2500] [15000 15000] 
 		Hole (
-			[1905000nm 3175000nm] [3175000nm 3175000nm] [3175000nm 2540000nm] [2540000nm 2540000nm] 
+			[7500 12500] [12500 12500] [12500 10000] [10000 10000] 
 		)
 	)
 	Polygon("clearpoly")
 	(
-		[4445000nm 3810000nm] [7620000nm 635000nm] [10795000nm 3810000nm] 
+		[17500 15000] [30000 2500] [42500 15000] 
 		Hole (
-			[6985000nm 1905000nm] [6985000nm 3175000nm] [8255000nm 3175000nm] [8255000nm 1905000nm] 
+			[27500 7500] [27500 12500] [32500 12500] [32500 7500] 
 		)
 	)
 	Polygon("clearpoly")
 	(
-		[635000nm 4445000nm] [7620000nm 5080000nm] [1270000nm 8890000nm] 
+		[2500 17500] [30000 20000] [5000 35000] 
 		Hole (
-			[3810000nm 5715000nm] [3810000nm 6350000nm] [4445000nm 6350000nm] [4445000nm 5715000nm] 
+			[15000 22500] [15000 25000] [17500 25000] [17500 22500] 
 		)
 		Hole (
-			[1905000nm 5715000nm] [1905000nm 6985000nm] [2540000nm 7620000nm] [3175000nm 6985000nm] [3175000nm 6350000nm] 
-			[2540000nm 5715000nm] 
+			[7500 22500] [7500 27500] [10000 30000] [12500 27500] [12500 25000] 
+			[10000 22500] 
 		)
 	)
 )
diff --git a/tests/RTT/poly_hole.pcb.text b/tests/RTT/poly_hole.pcb.text
new file mode 100644
index 0000000..ef1bf48
--- /dev/null
+++ b/tests/RTT/poly_hole.pcb.text
@@ -0,0 +1,20 @@
+r6630
+
+500 x 500 mil outline
+
+upper left triangle
+Top left corner to top left cutout corner 25 mils down 25 mils over
+cutout 25 mils wide
+cutout 25 mils high
+
+upper right triangle
+bottom right corner to bottom right on cutout 25 x 25 mils
+cutout 50mils wide
+cutout 25 mils high
+
+far right piramid
+cutout 50mils x 50mils
+cutout located 50mils down from the apex
+
+
+
diff --git a/tests/RTT/poly_rect.pcb.text b/tests/RTT/poly_rect.pcb.text
new file mode 100644
index 0000000..65ced7c
--- /dev/null
+++ b/tests/RTT/poly_rect.pcb.text
@@ -0,0 +1,17 @@
+
+outline 500 x 500 mils
+
+vertical polygon
+25 x 425 mils
+
+horizontal polygon
+350 x 25 mils
+
+giant middle polygon
+275 x 375 mils
+
+smallest polygon (bottom right)
+25 x 25 mils
+
+
+
diff --git a/tests/RTT/poly_triangle.pcb.text b/tests/RTT/poly_triangle.pcb.text
new file mode 100644
index 0000000..79c77d8
--- /dev/null
+++ b/tests/RTT/poly_triangle.pcb.text
@@ -0,0 +1,31 @@
+
+upper left triangle
+100 mils wide
+100 mils tall
+
+gap from lower left triangle to upper left triangle
+25 mils horizontally
+25 mils vertically
+
+lower left triangle
+125 mils wide
+125 mils tall
+
+gap from lower left triangle to far right piramid
+25 mils
+
+far right piramid
+125 mils height
+250 mils base
+
+bottom triangle
+275 mils across
+175 mils up
+top edge
+276.13 mils long __ degrees
+side edge
+176.78 mils long __ degrees
+bottom edge
+291.55 mils long __ degrees
+
+
diff --git a/tests/RTT/ref/Proto.bbrd.png b/tests/RTT/ref/Proto.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/Proto.bbrd.png differ
diff --git a/tests/RTT/ref/Proto.dsn b/tests/RTT/ref/Proto.dsn
index 61b3a2f..b43120d 100644
--- a/tests/RTT/ref/Proto.dsn
+++ b/tests/RTT/ref/Proto.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/Proto.eps b/tests/RTT/ref/Proto.eps
new file mode 100644
index 0000000..f1ef8d7
--- /dev/null
+++ b/tests/RTT/ref/Proto.eps
@@ -0,0 +1,31 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: Proto.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/Proto.gbr/Proto.fab.gbr b/tests/RTT/ref/Proto.gbr/Proto.fab.gbr
index b76c56e..ede845d 100644
--- a/tests/RTT/ref/Proto.gbr/Proto.fab.gbr
+++ b/tests/RTT/ref/Proto.gbr/Proto.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group -1 layer_idx -1 *
-G04 Title: (unknown), TODO:group_name *
+G04 start of page 2 for group -1 layer_idx 16777221 *
+G04 Title: (unknown), <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/Proto.nelma.em b/tests/RTT/ref/Proto.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/Proto.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/Proto.png b/tests/RTT/ref/Proto.png
index 852eb60..673e79f 100644
Binary files a/tests/RTT/ref/Proto.png and b/tests/RTT/ref/Proto.png differ
diff --git a/tests/RTT/ref/Proto.png.text b/tests/RTT/ref/Proto.png.text
new file mode 100644
index 0000000..65cfa73
--- /dev/null
+++ b/tests/RTT/ref/Proto.png.text
@@ -0,0 +1,5 @@
+r6731
+
+587 x 589 pix (489.167 x 490.833) inside the outline box
+
+
diff --git a/tests/RTT/ref/Proto.ps.gz b/tests/RTT/ref/Proto.ps.gz
index 5f43e1e..2182c61 100644
Binary files a/tests/RTT/ref/Proto.ps.gz and b/tests/RTT/ref/Proto.ps.gz differ
diff --git a/tests/RTT/ref/Proto.remote.gz b/tests/RTT/ref/Proto.remote.gz
index be5ed50..628de05 100644
Binary files a/tests/RTT/ref/Proto.remote.gz and b/tests/RTT/ref/Proto.remote.gz differ
diff --git a/tests/RTT/ref/Proto.scad b/tests/RTT/ref/Proto.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/Proto.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/Proto.svg b/tests/RTT/ref/Proto.svg
index 6ac2399..a483669 100644
--- a/tests/RTT/ref/Proto.svg
+++ b/tests/RTT/ref/Proto.svg
@@ -1,17 +1,17 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/arc_angles.bbrd.png b/tests/RTT/ref/arc_angles.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/arc_angles.bbrd.png differ
diff --git a/tests/RTT/ref/arc_angles.dsn b/tests/RTT/ref/arc_angles.dsn
index 364a8ec..e5de37f 100644
--- a/tests/RTT/ref/arc_angles.dsn
+++ b/tests/RTT/ref/arc_angles.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/arc_angles.eps b/tests/RTT/ref/arc_angles.eps
new file mode 100644
index 0000000..cbdfd74
--- /dev/null
+++ b/tests/RTT/ref/arc_angles.eps
@@ -0,0 +1,37 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: arc_angles.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0 750 -0.05000 0.05000 0.10000 0.10000 0.2 a
+0 0 -0.05000 0.05000 0.30000 0.10000 0.2 a
+-750 0 -0.05000 0.05000 0.40000 0.10000 0.2 a
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/arc_angles.gbr/arc_angles.fab.gbr b/tests/RTT/ref/arc_angles.gbr/arc_angles.fab.gbr
index d7a7cec..085b490 100644
--- a/tests/RTT/ref/arc_angles.gbr/arc_angles.fab.gbr
+++ b/tests/RTT/ref/arc_angles.gbr/arc_angles.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: arcs with different strange angles, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: arcs with different strange angles, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_angles.gbr/arc_angles.top.gbr b/tests/RTT/ref/arc_angles.gbr/arc_angles.top.gbr
index 4691cde..8a1ed86 100644
--- a/tests/RTT/ref/arc_angles.gbr/arc_angles.top.gbr
+++ b/tests/RTT/ref/arc_angles.gbr/arc_angles.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: arcs with different strange angles, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: arcs with different strange angles, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_angles.nelma.em b/tests/RTT/ref/arc_angles.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/arc_angles.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/arc_angles.png b/tests/RTT/ref/arc_angles.png
index e56f163..c281e52 100644
Binary files a/tests/RTT/ref/arc_angles.png and b/tests/RTT/ref/arc_angles.png differ
diff --git a/tests/RTT/ref/arc_angles.png.text b/tests/RTT/ref/arc_angles.png.text
index 75c7f15..f34b7b2 100644
--- a/tests/RTT/ref/arc_angles.png.text
+++ b/tests/RTT/ref/arc_angles.png.text
@@ -1,22 +1,22 @@
+r6630
 
 right circle
-132 pixels horizontally
-132 pixels vertically
-13 pixels wall thickness
+132 pixels (110 mil) horizontally
+132 pixels (110 mil) vertically
+13 pixels (10.833 mil) wall thickness
 
 left circle
-132 pixels horizontally
-132 pixels vertically
-13 pixels wall thickness
+132 pixels (110 mil) horizontally
+132 pixels (100 mil) vertically
+13 pixels (10.833 mil) wall thickness
 
 central dot
-13 pixel diameter
+13 pixel (10.833 mil) diameter
 
 air gap between right circle and central dot
-107 pixels
+107 pixels (89.166 mil)
 
 air gap between left circle and central dot
-108 pixels
-
+108 pixels (90 mil)
 
 
diff --git a/tests/RTT/ref/arc_angles.ps.gz b/tests/RTT/ref/arc_angles.ps.gz
index 668a985..799b12b 100644
Binary files a/tests/RTT/ref/arc_angles.ps.gz and b/tests/RTT/ref/arc_angles.ps.gz differ
diff --git a/tests/RTT/ref/arc_angles.remote.gz b/tests/RTT/ref/arc_angles.remote.gz
index cb5a8dc..d6f3a03 100644
Binary files a/tests/RTT/ref/arc_angles.remote.gz and b/tests/RTT/ref/arc_angles.remote.gz differ
diff --git a/tests/RTT/ref/arc_angles.scad b/tests/RTT/ref/arc_angles.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/arc_angles.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/arc_angles.svg b/tests/RTT/ref/arc_angles.svg
index f2a32b5..5e5288e 100644
--- a/tests/RTT/ref/arc_angles.svg
+++ b/tests/RTT/ref/arc_angles.svg
@@ -1,21 +1,23 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
- <path d="M 1.2700 2.5400 A 1.2700 1.2700 0 0 0 1.2700 2.5400" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 6.3500 2.5400 A 1.2700 1.2700 0 0 0 6.3500 2.5400" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 8.8900 2.5400 A 1.2700 1.2700 0 0 0 8.8900 2.5400" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 3.81000000 2.54000000 A 1.2700 1.2700 0 0 1 1.2700 2.5400" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 1.27000000 2.53999900 A 1.2700 1.2700 0 0 1 3.8100 2.5400" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 6.35000100 2.53997800 A 1.2700 1.2700 0 0 0 6.3500 2.5400" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 11.43000000 2.54000000 A 1.2700 1.2700 0 0 1 8.8900 2.5400" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 8.89000000 2.53999900 A 1.2700 1.2700 0 0 1 11.4300 2.5400" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/arc_f_clear.bbrd.png b/tests/RTT/ref/arc_f_clear.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/arc_f_clear.bbrd.png differ
diff --git a/tests/RTT/ref/arc_f_clear.dsn b/tests/RTT/ref/arc_f_clear.dsn
index 39f7356..6dc05b9 100644
--- a/tests/RTT/ref/arc_f_clear.dsn
+++ b/tests/RTT/ref/arc_f_clear.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/arc_f_clear.eps b/tests/RTT/ref/arc_f_clear.eps
new file mode 100644
index 0000000..86eebaa
--- /dev/null
+++ b/tests/RTT/ref/arc_f_clear.eps
@@ -0,0 +1,216 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: arc_f_clear.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.30002 0.15000 moveto
+0.47500 0.15000 lineto
+0.47500 0.47500 lineto
+0.30002 0.47500 lineto
+0.30002 0.32505 lineto
+0.30436 0.32486 lineto
+0.30869 0.32429 lineto
+0.31295 0.32334 lineto
+0.31712 0.32203 lineto
+0.32115 0.32036 lineto
+0.32502 0.31834 lineto
+0.32871 0.31600 lineto
+0.33217 0.31334 lineto
+0.33539 0.31039 lineto
+0.33834 0.30717 lineto
+0.34100 0.30371 lineto
+0.34334 0.30002 lineto
+0.34389 0.29891 lineto
+0.34536 0.29615 lineto
+0.34703 0.29212 lineto
+0.34834 0.28795 lineto
+0.34929 0.28369 lineto
+0.34986 0.27936 lineto
+0.35005 0.27500 lineto
+0.34986 0.27064 lineto
+0.34929 0.26631 lineto
+0.34834 0.26205 lineto
+0.34703 0.25788 lineto
+0.34536 0.25385 lineto
+0.34334 0.24998 lineto
+0.34100 0.24629 lineto
+0.33834 0.24283 lineto
+0.33539 0.23961 lineto
+0.33217 0.23666 lineto
+0.32871 0.23400 lineto
+0.32502 0.23166 lineto
+0.32115 0.22964 lineto
+0.31712 0.22797 lineto
+0.31295 0.22666 lineto
+0.30869 0.22571 lineto
+0.30436 0.22514 lineto
+0.30002 0.22495 lineto
+fill
+0.13759 0.15000 moveto
+0.30002 0.15000 lineto
+0.30002 0.22495 lineto
+0.30000 0.22495 lineto
+0.29564 0.22514 lineto
+0.29131 0.22571 lineto
+0.28705 0.22666 lineto
+0.28288 0.22797 lineto
+0.27885 0.22964 lineto
+0.27498 0.23166 lineto
+0.27172 0.23386 lineto
+0.26886 0.23657 lineto
+0.26647 0.23969 lineto
+0.26459 0.24315 lineto
+0.26328 0.24686 lineto
+0.26256 0.25073 lineto
+0.26249 0.25334 lineto
+0.26026 0.25471 lineto
+0.25727 0.25727 lineto
+0.25471 0.26026 lineto
+0.25266 0.26362 lineto
+0.25115 0.26725 lineto
+0.25023 0.27108 lineto
+0.25000 0.27500 lineto
+0.25014 0.27936 lineto
+0.25071 0.28369 lineto
+0.25166 0.28795 lineto
+0.25297 0.29212 lineto
+0.25464 0.29615 lineto
+0.25666 0.30002 lineto
+0.25900 0.30371 lineto
+0.26166 0.30717 lineto
+0.26461 0.31039 lineto
+0.26783 0.31334 lineto
+0.27129 0.31600 lineto
+0.27498 0.31834 lineto
+0.27885 0.32036 lineto
+0.28288 0.32203 lineto
+0.28705 0.32334 lineto
+0.29131 0.32429 lineto
+0.29564 0.32486 lineto
+0.30000 0.32505 lineto
+0.30002 0.32505 lineto
+0.30002 0.47500 lineto
+0.13759 0.47500 lineto
+0.13759 0.36151 lineto
+0.14865 0.36609 lineto
+0.16114 0.37003 lineto
+0.17393 0.37286 lineto
+0.18691 0.37457 lineto
+0.20000 0.37514 lineto
+0.20394 0.37486 lineto
+0.20778 0.37394 lineto
+0.21143 0.37243 lineto
+0.21480 0.37037 lineto
+0.21780 0.36780 lineto
+0.22037 0.36480 lineto
+0.22243 0.36143 lineto
+0.22394 0.35778 lineto
+0.22486 0.35394 lineto
+0.22517 0.35000 lineto
+0.22486 0.34606 lineto
+0.22394 0.34222 lineto
+0.22243 0.33857 lineto
+0.22037 0.33520 lineto
+0.21780 0.33220 lineto
+0.21480 0.32963 lineto
+0.21143 0.32757 lineto
+0.20778 0.32606 lineto
+0.20394 0.32514 lineto
+0.20000 0.32490 lineto
+0.19128 0.32462 lineto
+0.18264 0.32348 lineto
+0.17412 0.32159 lineto
+0.16580 0.31897 lineto
+0.15774 0.31563 lineto
+0.15000 0.31160 lineto
+0.14264 0.30692 lineto
+0.13759 0.30304 lineto
+fill
+0.02500 0.15000 moveto
+0.13759 0.15000 lineto
+0.13759 0.30304 lineto
+0.13572 0.30160 lineto
+0.12929 0.29571 lineto
+0.12340 0.28928 lineto
+0.11808 0.28236 lineto
+0.11340 0.27500 lineto
+0.10937 0.26726 lineto
+0.10603 0.25920 lineto
+0.10341 0.25088 lineto
+0.10152 0.24236 lineto
+0.10038 0.23372 lineto
+0.10000 0.22500 lineto
+0.09977 0.22108 lineto
+0.09885 0.21725 lineto
+0.09734 0.21362 lineto
+0.09529 0.21026 lineto
+0.09273 0.20727 lineto
+0.08974 0.20471 lineto
+0.08638 0.20266 lineto
+0.08275 0.20115 lineto
+0.07892 0.20023 lineto
+0.07500 0.19992 lineto
+0.07108 0.20023 lineto
+0.06725 0.20115 lineto
+0.06362 0.20266 lineto
+0.06026 0.20471 lineto
+0.05727 0.20727 lineto
+0.05471 0.21026 lineto
+0.05266 0.21362 lineto
+0.05115 0.21725 lineto
+0.05023 0.22108 lineto
+0.05000 0.22500 lineto
+0.05043 0.23809 lineto
+0.05214 0.25107 lineto
+0.05497 0.26386 lineto
+0.05891 0.27635 lineto
+0.06392 0.28845 lineto
+0.06997 0.30007 lineto
+0.07701 0.31112 lineto
+0.08498 0.32151 lineto
+0.09383 0.33117 lineto
+0.10349 0.34002 lineto
+0.11388 0.34799 lineto
+0.12493 0.35503 lineto
+0.13655 0.36108 lineto
+0.13759 0.36151 lineto
+0.13759 0.47500 lineto
+0.02500 0.47500 lineto
+fill
+0.01000 setlinewidth
+0 90 -0.12500 0.12500 0.20000 0.22500 0.08 a
+0.02000 setlinewidth
+-90 -10 -0.10000 0.10000 0.17500 0.22500 0.2 a
+0.01000 setlinewidth
+0 300 -0.02500 0.02500 0.30000 0.27500 0.4 a
+0.03000 setlinewidth
+-160 -70 -0.12500 0.12500 0.25000 0.22500 0.24 a
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.fab.gbr b/tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.fab.gbr
index 8d32444..1f8f495 100644
--- a/tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.fab.gbr
+++ b/tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Arc with clearline flag, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Arc with clearline flag, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.top.gbr b/tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.top.gbr
index adc965e..f8d7edd 100644
--- a/tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.top.gbr
+++ b/tests/RTT/ref/arc_f_clear.gbr/arc_f_clear.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Arc with clearline flag, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Arc with clearline flag, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_f_clear.nelma.em b/tests/RTT/ref/arc_f_clear.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/arc_f_clear.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/arc_f_clear.png b/tests/RTT/ref/arc_f_clear.png
index c9138f9..0904429 100644
Binary files a/tests/RTT/ref/arc_f_clear.png and b/tests/RTT/ref/arc_f_clear.png differ
diff --git a/tests/RTT/ref/arc_f_clear.png.text b/tests/RTT/ref/arc_f_clear.png.text
index 6419c45..b945179 100644
--- a/tests/RTT/ref/arc_f_clear.png.text
+++ b/tests/RTT/ref/arc_f_clear.png.text
@@ -1,24 +1,25 @@
+r6630
 
 polygone
-width 541 pixels
-height 391 pixels
-
+width 541 pixels (450.833 mil)
+height 391 pixels (324.833 mil)
+----
 small near circle completely in polygon
-width 13 pixels
-clearance on the left 22 pixels
-clearance on the right 25 pixels
-clearance on the top 23 pixels
-clearance on the bottom 25 pixels
+width 13 pixels (10.833 mils)
+clearance on the left 23 pixels (19.166 mil)
+clearance on the right 24 pixels (20 mil)
+clearance on the top 24 pixels (20 mil)
+clearance on the bottom 24 pixels (20 mil)
 
 longer arc completely in polygon
-line width 13 pixels
-width 163 pixels
-height 162 pixels
-clearance on the bottom right end 25 pixels
-clearance on the top right end 23 pixels
-clearance on the end right end 25 pixels
-clearance on the right top end 22 pixels
-clearance on the left top end 23 pixels
+line width 13 pixels(10.833 mil)
+width 162 pixels (135 mil)
+height 162 pixels (135 mil)
+clearance on the bottom right end 24 pixels (20 mil)
+clearance on the top right end 23 pixels (19.166 mil)
+clearance on the end right end 24 pixels (20 mil)
+clearance on the right top end 23 pixels (19.333 mil)
+clearance on the left top end 23 pixels (19.166 mil)
 
 
 
diff --git a/tests/RTT/ref/arc_f_clear.ps.gz b/tests/RTT/ref/arc_f_clear.ps.gz
index eb5b870..7aa6c6e 100644
Binary files a/tests/RTT/ref/arc_f_clear.ps.gz and b/tests/RTT/ref/arc_f_clear.ps.gz differ
diff --git a/tests/RTT/ref/arc_f_clear.remote.gz b/tests/RTT/ref/arc_f_clear.remote.gz
index 2a648da..8c3c212 100644
Binary files a/tests/RTT/ref/arc_f_clear.remote.gz and b/tests/RTT/ref/arc_f_clear.remote.gz differ
diff --git a/tests/RTT/ref/arc_f_clear.scad b/tests/RTT/ref/arc_f_clear.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/arc_f_clear.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/arc_f_clear.svg b/tests/RTT/ref/arc_f_clear.svg
index b15b3e2..3320742 100644
--- a/tests/RTT/ref/arc_f_clear.svg
+++ b/tests/RTT/ref/arc_f_clear.svg
@@ -1,25 +1,25 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <polygon points="7.6206,3.8100 12.0650,3.8100 12.0650,12.0650 7.6206,12.0650 7.6206,8.2562 7.7308,8.2514 7.8407,8.2369 7.9490,8.2129 8.0548,8.1795 8.1572,8.1371 8.2556,8.0859 8.3491,8.0263 8.4371,7.9588 8.5189,7.8839 8.5938,7.8021 8.6613,7.7141 8.7209,7.6206 8.7347,7.5922 8.7721,7.5222 8.8145,7.4198 8.8479,7.3140 8.8719,7.2057 8.8864,7.0958 8.8912,6.9850 8.8864,6.8742 8.8719,6.7643 8.8479,6.6560 8.8145,6.5502 8.7721,6.4478 8.7209,6.3494 8.6613,6.2559 8.5938,6.1679 8.5189,6.0861 8.4371,6 [...]
  <polygon points="3.4947,3.8100 7.6206,3.8100 7.6206,5.7138 7.6200,5.7138 7.5092,5.7186 7.3993,5.7331 7.2910,5.7571 7.1852,5.7905 7.0828,5.8329 6.9844,5.8841 6.9016,5.9401 6.8291,6.0089 6.7683,6.0882 6.7206,6.1760 6.6872,6.2702 6.6690,6.3685 6.6673,6.4350 6.6106,6.4697 6.5346,6.5346 6.4697,6.6106 6.4175,6.6958 6.3792,6.7882 6.3559,6.8854 6.3500,6.9850 6.3536,7.0958 6.3681,7.2057 6.3921,7.3140 6.4255,7.4198 6.4679,7.5222 6.5191,7.6206 6.5787,7.7141 6.6462,7.8021 6.7211,7.8839 6.8029,7.958 [...]
  <polygon points="0.6350,3.8100 3.4947,3.8100 3.4947,7.6971 3.4473,7.6608 3.2839,7.5111 3.1342,7.3477 2.9994,7.1719 2.8803,6.9850 2.7780,6.7885 2.6932,6.5837 2.6265,6.3724 2.5786,6.1561 2.5497,5.9364 2.5400,5.7150 2.5341,5.6154 2.5108,5.5182 2.4725,5.4258 2.4203,5.3406 2.3554,5.2646 2.2794,5.1997 2.1942,5.1475 2.1018,5.1092 2.0046,5.0859 1.9050,5.0780 1.8054,5.0859 1.7082,5.1092 1.6158,5.1475 1.5306,5.1997 1.4546,5.2646 1.3897,5.3406 1.3375,5.4258 1.2992,5.5182 1.2759,5.6154 1.2700,5.715 [...]
- <path d="M 1.9050 5.7150 A 3.1750 3.1750 0 0 0 5.0800 8.8900" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 4.4450 3.1750 A 2.5400 2.5400 0 0 0 1.9436 5.2739" stroke-width="0.5080" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 6.9850 6.9850 A 0.6350 0.6350 0 0 0 7.3025 6.4351" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 9.3335 4.6291 A 3.1750 3.1750 0 0 0 5.2641 2.7315" stroke-width="0.7620" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 5.08000000 8.89000000 A 3.1750 3.1750 0 0 1 1.9050 5.7150" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 4.44499900 3.17500000 A 2.5400 2.5400 0 0 0 1.9436 5.2739" stroke-width="0.5080" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 7.30249900 6.43507300 A 0.6350 0.6350 0 1 1 6.9850 6.9850" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 9.33352400 4.62908600 A 3.1750 3.1750 0 0 0 5.2641 2.7315" stroke-width="0.7620" stroke="#8b2323" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/arc_normal.bbrd.png b/tests/RTT/ref/arc_normal.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/arc_normal.bbrd.png differ
diff --git a/tests/RTT/ref/arc_normal.dsn b/tests/RTT/ref/arc_normal.dsn
index bf8faf5..85b7bdb 100644
--- a/tests/RTT/ref/arc_normal.dsn
+++ b/tests/RTT/ref/arc_normal.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/arc_normal.eps b/tests/RTT/ref/arc_normal.eps
new file mode 100644
index 0000000..ef113a5
--- /dev/null
+++ b/tests/RTT/ref/arc_normal.eps
@@ -0,0 +1,41 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: arc_normal.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0 90 -0.12500 0.12500 0.20000 0.22500 0.08 a
+0.02000 setlinewidth
+-90 -10 -0.10000 0.10000 0.17500 0.22500 0.2 a
+0.01000 setlinewidth
+0 300 -0.02500 0.02500 0.30000 0.27500 0.4 a
+0.03000 setlinewidth
+-160 -70 -0.12500 0.12500 0.25000 0.22500 0.24 a
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/arc_normal.gbr/arc_normal.fab.gbr b/tests/RTT/ref/arc_normal.gbr/arc_normal.fab.gbr
index 091fb4b..fcf30f3 100644
--- a/tests/RTT/ref/arc_normal.gbr/arc_normal.fab.gbr
+++ b/tests/RTT/ref/arc_normal.gbr/arc_normal.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Arcs with different sizes, normal cases, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Arcs with different sizes, normal cases, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_normal.gbr/arc_normal.top.gbr b/tests/RTT/ref/arc_normal.gbr/arc_normal.top.gbr
index 85703bf..04b6f18 100644
--- a/tests/RTT/ref/arc_normal.gbr/arc_normal.top.gbr
+++ b/tests/RTT/ref/arc_normal.gbr/arc_normal.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Arcs with different sizes, normal cases, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Arcs with different sizes, normal cases, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_normal.nelma.em b/tests/RTT/ref/arc_normal.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/arc_normal.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/arc_normal.png b/tests/RTT/ref/arc_normal.png
index 136f1e2..8d5821f 100644
Binary files a/tests/RTT/ref/arc_normal.png and b/tests/RTT/ref/arc_normal.png differ
diff --git a/tests/RTT/ref/arc_normal.png.text b/tests/RTT/ref/arc_normal.png.text
index 9be4650..4b055ff 100644
--- a/tests/RTT/ref/arc_normal.png.text
+++ b/tests/RTT/ref/arc_normal.png.text
@@ -1,21 +1,22 @@
+r6630
 
 top left arc
-25 pixel line width
-124 pixels tall
-142 pixesl wide
+25 pixel line width (20.833 mil)
+124 pixels tall (103.333 mil)
+142 pixesl wide (118.333 mil)
 
 top right arc
-37 pixel line width
-227 pixels wide
-135 pixels tall
+37 pixel line width (30.833 mil)
+227 pixels wide (189.166 mil)
+135 pixels tall (112.5 mil)
 
 lower left arc
-13 pixel line width
-162 pixels wide
+13 pixel line width (10.833 mil)
+162 pixels wide (135 mil)
 162 pixels tall
 
 lower right arc
-13 pixel line width
-72 pixels diameter
+13 pixel line width (10.833 mil)
+72 pixels diameter (60 mil)
 
 
diff --git a/tests/RTT/ref/arc_normal.ps.gz b/tests/RTT/ref/arc_normal.ps.gz
index b03593b..d1348d3 100644
Binary files a/tests/RTT/ref/arc_normal.ps.gz and b/tests/RTT/ref/arc_normal.ps.gz differ
diff --git a/tests/RTT/ref/arc_normal.remote.gz b/tests/RTT/ref/arc_normal.remote.gz
index 0155ebf..3cd0d68 100644
Binary files a/tests/RTT/ref/arc_normal.remote.gz and b/tests/RTT/ref/arc_normal.remote.gz differ
diff --git a/tests/RTT/ref/arc_normal.scad b/tests/RTT/ref/arc_normal.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/arc_normal.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/arc_normal.svg b/tests/RTT/ref/arc_normal.svg
index 30b4af4..66b7000 100644
--- a/tests/RTT/ref/arc_normal.svg
+++ b/tests/RTT/ref/arc_normal.svg
@@ -1,22 +1,22 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
- <path d="M 1.9050 5.7150 A 3.1750 3.1750 0 0 0 5.0800 8.8900" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 4.4450 3.1750 A 2.5400 2.5400 0 0 0 1.9436 5.2739" stroke-width="0.5080" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 6.9850 6.9850 A 0.6350 0.6350 0 0 0 7.3025 6.4351" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 9.3335 4.6291 A 3.1750 3.1750 0 0 0 5.2641 2.7315" stroke-width="0.7620" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 5.08000000 8.89000000 A 3.1750 3.1750 0 0 1 1.9050 5.7150" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 4.44499900 3.17500000 A 2.5400 2.5400 0 0 0 1.9436 5.2739" stroke-width="0.5080" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 7.30249900 6.43507300 A 0.6350 0.6350 0 1 1 6.9850 6.9850" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 9.33352400 4.62908600 A 3.1750 3.1750 0 0 0 5.2641 2.7315" stroke-width="0.7620" stroke="#8b2323" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/arc_offpage.bbrd.png b/tests/RTT/ref/arc_offpage.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/arc_offpage.bbrd.png differ
diff --git a/tests/RTT/ref/arc_offpage.dsn b/tests/RTT/ref/arc_offpage.dsn
index 343c8fb..3bf6e2b 100644
--- a/tests/RTT/ref/arc_offpage.dsn
+++ b/tests/RTT/ref/arc_offpage.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/arc_offpage.eps b/tests/RTT/ref/arc_offpage.eps
new file mode 100644
index 0000000..ec629b7
--- /dev/null
+++ b/tests/RTT/ref/arc_offpage.eps
@@ -0,0 +1,35 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: arc_offpage.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0 230 -0.10000 0.10000 0.05000 0.05000 0.1 a
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/arc_offpage.gbr/arc_offpage.fab.gbr b/tests/RTT/ref/arc_offpage.gbr/arc_offpage.fab.gbr
index c6cf0d0..518abda 100644
--- a/tests/RTT/ref/arc_offpage.gbr/arc_offpage.fab.gbr
+++ b/tests/RTT/ref/arc_offpage.gbr/arc_offpage.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Arcs with some parts off the page, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Arcs with some parts off the page, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_offpage.gbr/arc_offpage.top.gbr b/tests/RTT/ref/arc_offpage.gbr/arc_offpage.top.gbr
index 954dabe..df90e6e 100644
--- a/tests/RTT/ref/arc_offpage.gbr/arc_offpage.top.gbr
+++ b/tests/RTT/ref/arc_offpage.gbr/arc_offpage.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Arcs with some parts off the page, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Arcs with some parts off the page, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_offpage.nelma.em b/tests/RTT/ref/arc_offpage.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/arc_offpage.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/arc_offpage.png b/tests/RTT/ref/arc_offpage.png
index ec9272a..31e4d2b 100644
Binary files a/tests/RTT/ref/arc_offpage.png and b/tests/RTT/ref/arc_offpage.png differ
diff --git a/tests/RTT/ref/arc_offpage.png.text b/tests/RTT/ref/arc_offpage.png.text
index beda1c2..ea12410 100644
--- a/tests/RTT/ref/arc_offpage.png.text
+++ b/tests/RTT/ref/arc_offpage.png.text
@@ -1,6 +1,10 @@
+r6630
 
 arc
-13 pixel line width
-185 pixels tall
-185 pixels wide
+13 pixel line width (10.833 mil)
+180 pixels wide [measured from inside corner] (15.000 mil)
+186 pixels tall (154.167 mil)
+179 pixels wide [measured from inside corner] (14.917 mil)
+186 pixels wide (154.167 mil)
+
 
diff --git a/tests/RTT/ref/arc_offpage.ps.gz b/tests/RTT/ref/arc_offpage.ps.gz
index ed38e15..fbd696d 100644
Binary files a/tests/RTT/ref/arc_offpage.ps.gz and b/tests/RTT/ref/arc_offpage.ps.gz differ
diff --git a/tests/RTT/ref/arc_offpage.remote.gz b/tests/RTT/ref/arc_offpage.remote.gz
index 7afd43c..d6de520 100644
Binary files a/tests/RTT/ref/arc_offpage.remote.gz and b/tests/RTT/ref/arc_offpage.remote.gz differ
diff --git a/tests/RTT/ref/arc_offpage.scad b/tests/RTT/ref/arc_offpage.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/arc_offpage.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/arc_offpage.svg b/tests/RTT/ref/arc_offpage.svg
index ed87196..e344a18 100644
--- a/tests/RTT/ref/arc_offpage.svg
+++ b/tests/RTT/ref/arc_offpage.svg
@@ -1,19 +1,19 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
- <path d="M -1.2700 1.2700 A 2.5400 2.5400 0 0 0 2.9027 -0.6758" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 2.90268000 -0.67575200 A 2.5400 2.5400 0 1 1 -1.2700 1.2700" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/arc_sizes.bbrd.png b/tests/RTT/ref/arc_sizes.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/arc_sizes.bbrd.png differ
diff --git a/tests/RTT/ref/arc_sizes.dsn b/tests/RTT/ref/arc_sizes.dsn
index 8022e27..e418972 100644
--- a/tests/RTT/ref/arc_sizes.dsn
+++ b/tests/RTT/ref/arc_sizes.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/arc_sizes.eps b/tests/RTT/ref/arc_sizes.eps
new file mode 100644
index 0000000..d6e07c1
--- /dev/null
+++ b/tests/RTT/ref/arc_sizes.eps
@@ -0,0 +1,37 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: arc_sizes.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0 90 0.00000 0.05000 0.10000 0.20000 inf a
+0 90 -0.05000 0.00000 0.20000 0.20000 0.2 a
+0 90 0.00000 0.00000 0.30000 0.20000 inf a
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/arc_sizes.gbr/arc_sizes.fab.gbr b/tests/RTT/ref/arc_sizes.gbr/arc_sizes.fab.gbr
index 98e1d58..99ead0a 100644
--- a/tests/RTT/ref/arc_sizes.gbr/arc_sizes.fab.gbr
+++ b/tests/RTT/ref/arc_sizes.gbr/arc_sizes.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: arcs with different strange sizes, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: arcs with different strange sizes, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_sizes.gbr/arc_sizes.top.gbr b/tests/RTT/ref/arc_sizes.gbr/arc_sizes.top.gbr
index 91d7ecc..1476f70 100644
--- a/tests/RTT/ref/arc_sizes.gbr/arc_sizes.top.gbr
+++ b/tests/RTT/ref/arc_sizes.gbr/arc_sizes.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: arcs with different strange sizes, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: arcs with different strange sizes, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/arc_sizes.nelma.em b/tests/RTT/ref/arc_sizes.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/arc_sizes.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/arc_sizes.png b/tests/RTT/ref/arc_sizes.png
index 91cf8cf..467bd78 100644
Binary files a/tests/RTT/ref/arc_sizes.png and b/tests/RTT/ref/arc_sizes.png differ
diff --git a/tests/RTT/ref/arc_sizes.png.text b/tests/RTT/ref/arc_sizes.png.text
index 9784a77..0a5834b 100644
--- a/tests/RTT/ref/arc_sizes.png.text
+++ b/tests/RTT/ref/arc_sizes.png.text
@@ -1,17 +1,18 @@
+r6630
 
 weird dot thing in the far right
-12 pixels across
-12 pixels tall
+12 pixels across (10)
+12 pixels tall (10)
 
 weird dot to line (horizontal) 108 pixels
 
 horizontal line
-72 pixels long
-12 pixels wide
+72 pixels long (60)
+12 pixels wide (10)
 
 vertical line
-72 pixels long
-12 pixels wide
-
+72 pixels long (60)
+12 pixels wide (12)
 
+(mils)
 
diff --git a/tests/RTT/ref/arc_sizes.ps.gz b/tests/RTT/ref/arc_sizes.ps.gz
index 7a4b4a8..eb91c9e 100644
Binary files a/tests/RTT/ref/arc_sizes.ps.gz and b/tests/RTT/ref/arc_sizes.ps.gz differ
diff --git a/tests/RTT/ref/arc_sizes.remote.gz b/tests/RTT/ref/arc_sizes.remote.gz
index 2a87e4c..3363ace 100644
Binary files a/tests/RTT/ref/arc_sizes.remote.gz and b/tests/RTT/ref/arc_sizes.remote.gz differ
diff --git a/tests/RTT/ref/arc_sizes.scad b/tests/RTT/ref/arc_sizes.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/arc_sizes.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/arc_sizes.svg b/tests/RTT/ref/arc_sizes.svg
index 538fb37..40685d7 100644
--- a/tests/RTT/ref/arc_sizes.svg
+++ b/tests/RTT/ref/arc_sizes.svg
@@ -1,21 +1,21 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
- <path d="M 2.5400 5.0800 A 0.0000 0.0000 0 0 0 2.5400 5.0800" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 3.8100 5.0800 A 1.2700 1.2700 0 0 0 5.0800 6.3500" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
- <path d="M 7.6200 5.0800 A 0.0000 0.0000 0 0 0 7.6200 5.0800" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 2.54000000 5.08000000 A 0.0000 0.0000 0 0 1 2.5400 5.0800" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 5.08000000 6.35000000 A 1.2700 1.2700 0 0 1 3.8100 5.0800" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
+ <path d="M 7.62000000 5.08000000 A 0.0000 0.0000 0 0 1 7.6200 5.0800" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/clearance.bbrd.png b/tests/RTT/ref/clearance.bbrd.png
new file mode 100644
index 0000000..1df8166
Binary files /dev/null and b/tests/RTT/ref/clearance.bbrd.png differ
diff --git a/tests/RTT/ref/clearance.nelma.em b/tests/RTT/ref/clearance.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/clearance.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/clearance.png b/tests/RTT/ref/clearance.png
index 0a01467..426f200 100644
Binary files a/tests/RTT/ref/clearance.png and b/tests/RTT/ref/clearance.png differ
diff --git a/tests/RTT/ref/clearance.png.text b/tests/RTT/ref/clearance.png.text
index 9564e67..4d83690 100644
--- a/tests/RTT/ref/clearance.png.text
+++ b/tests/RTT/ref/clearance.png.text
@@ -1,11 +1,13 @@
+r6630
 
 line
-width 12 pixels
-clearance 23 pixels
-length 343 pixels
+width 12 pixels (10)
+clearance 23/24 pixels left/right (19.167/20)
+length 343 pixels (28.583)
 
 polygon
-width 520 pixels
-height 284 pixels
+width 520 pixels (433.333)
+height 284 pixels (236.667)
 
+(mil)
 
diff --git a/tests/RTT/ref/clearance.ps.gz b/tests/RTT/ref/clearance.ps.gz
index 07339b2..7905277 100644
Binary files a/tests/RTT/ref/clearance.ps.gz and b/tests/RTT/ref/clearance.ps.gz differ
diff --git a/tests/RTT/ref/clearance.remote.gz b/tests/RTT/ref/clearance.remote.gz
index f312172..226dc97 100644
Binary files a/tests/RTT/ref/clearance.remote.gz and b/tests/RTT/ref/clearance.remote.gz differ
diff --git a/tests/RTT/ref/clearance.scad b/tests/RTT/ref/clearance.scad
new file mode 100644
index 0000000..81d8f1b
--- /dev/null
+++ b/tests/RTT/ref/clearance.scad
@@ -0,0 +1,68 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_00_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_00
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/clearance.svg b/tests/RTT/ref/clearance.svg
index 754da76..cf53f58 100644
--- a/tests/RTT/ref/clearance.svg
+++ b/tests/RTT/ref/clearance.svg
@@ -1,20 +1,20 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_4_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_3_group3">
 </g>
-<g id="layer_2_copper">
+<g id="layer_2_group2">
 </g>
-<g id="layer_1_copper">
+<g id="layer_1_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_0_top">
 <!--normal-->
  <polygon points="1.0000,1.0000 12.0000,1.0000 12.0000,7.0000 6.6350,7.0000 6.6350,3.0000 6.6291,2.9004 6.6058,2.8032 6.5675,2.7108 6.5153,2.6256 6.4504,2.5496 6.3744,2.4847 6.2892,2.4325 6.1968,2.3942 6.0996,2.3709 6.0000,2.3630 5.9003,2.3709 5.8032,2.3942 5.7108,2.4325 5.6256,2.4847 5.5496,2.5496 5.4847,2.6256 5.4325,2.7108 5.3942,2.8032 5.3709,2.9004 5.3650,3.0000 5.3650,7.0000 1.0000,7.0000 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <line x1="6.0000" y1="10.0000" x2="6.0000" y2="3.0000" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_0_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/coord_rounding.bbrd.png b/tests/RTT/ref/coord_rounding.bbrd.png
new file mode 100644
index 0000000..aabf465
Binary files /dev/null and b/tests/RTT/ref/coord_rounding.bbrd.png differ
diff --git a/tests/RTT/ref/coord_rounding.dsn b/tests/RTT/ref/coord_rounding.dsn
index 1aaacd8..14ebc7c 100644
--- a/tests/RTT/ref/coord_rounding.dsn
+++ b/tests/RTT/ref/coord_rounding.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/coord_rounding.eps b/tests/RTT/ref/coord_rounding.eps
new file mode 100644
index 0000000..972262e
--- /dev/null
+++ b/tests/RTT/ref/coord_rounding.eps
@@ -0,0 +1,36 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: coord_rounding.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.03937 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.23622 0.24016 0.24055 0.24059 t
+0.24059 0.24059 0.24059 0.24059 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/coord_rounding.gbr/coord_rounding.fab.gbr b/tests/RTT/ref/coord_rounding.gbr/coord_rounding.fab.gbr
index 393f7ca..4cf8c51 100644
--- a/tests/RTT/ref/coord_rounding.gbr/coord_rounding.fab.gbr
+++ b/tests/RTT/ref/coord_rounding.gbr/coord_rounding.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: odd coordinates to check rounding errors, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: odd coordinates to check rounding errors, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/coord_rounding.gbr/coord_rounding.top.gbr b/tests/RTT/ref/coord_rounding.gbr/coord_rounding.top.gbr
index 163e457..1b0bdad 100644
--- a/tests/RTT/ref/coord_rounding.gbr/coord_rounding.top.gbr
+++ b/tests/RTT/ref/coord_rounding.gbr/coord_rounding.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: odd coordinates to check rounding errors, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: odd coordinates to check rounding errors, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/coord_rounding.nelma.em b/tests/RTT/ref/coord_rounding.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/coord_rounding.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/coord_rounding.png b/tests/RTT/ref/coord_rounding.png
index 1d1103b..4b8b599 100644
Binary files a/tests/RTT/ref/coord_rounding.png and b/tests/RTT/ref/coord_rounding.png differ
diff --git a/tests/RTT/ref/coord_rounding.png.text b/tests/RTT/ref/coord_rounding.png.text
index a898d6f..42f5e54 100644
--- a/tests/RTT/ref/coord_rounding.png.text
+++ b/tests/RTT/ref/coord_rounding.png.text
@@ -1,5 +1,6 @@
+r6630
 
 weird dot thing
-47 pixels tall
-52 pixels wide
+48 pixels (40) tall
+53 pixels (44.167) wide
 
diff --git a/tests/RTT/ref/coord_rounding.ps.gz b/tests/RTT/ref/coord_rounding.ps.gz
index 7e5469f..763abdf 100644
Binary files a/tests/RTT/ref/coord_rounding.ps.gz and b/tests/RTT/ref/coord_rounding.ps.gz differ
diff --git a/tests/RTT/ref/coord_rounding.remote.gz b/tests/RTT/ref/coord_rounding.remote.gz
index 1f5118c..31cdb19 100644
Binary files a/tests/RTT/ref/coord_rounding.remote.gz and b/tests/RTT/ref/coord_rounding.remote.gz differ
diff --git a/tests/RTT/ref/coord_rounding.scad b/tests/RTT/ref/coord_rounding.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/coord_rounding.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/coord_rounding.svg b/tests/RTT/ref/coord_rounding.svg
index 0cd0131..fea7973 100644
--- a/tests/RTT/ref/coord_rounding.svg
+++ b/tests/RTT/ref/coord_rounding.svg
@@ -1,20 +1,20 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="6.0000" y1="6.1000" x2="6.1100" y2="6.1110" stroke-width="1.0000" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="6.1111" y1="6.1111" x2="6.1111" y2="6.1110" stroke-width="1.0000" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/elem_pads.bbrd.png b/tests/RTT/ref/elem_pads.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/elem_pads.bbrd.png differ
diff --git a/tests/RTT/ref/elem_pads.dsn b/tests/RTT/ref/elem_pads.dsn
index 67edab4..f61e3d7 100644
--- a/tests/RTT/ref/elem_pads.dsn
+++ b/tests/RTT/ref/elem_pads.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,19 +33,19 @@
     )
   )
   (placement
-    (component 8
+    (component 9
       (place "R1" 6.350000 10.160000 front 0 (PN 0))
     )
-    (component 16
+    (component 17
       (place "U1" 6.339840 4.241800 front 0 (PN 0))
     )
   )
   (library
-    (image 8
+    (image 9
       (pin Smd_rect_1299972x1899920 "1" -1.499870 0.000000)
       (pin Smd_rect_1299972x1899920 "2" 1.499870 0.000000)
     )
-    (image 16
+    (image 17
       (pin Smd_rect_381000x889000 "1" -0.650240 -1.066800)
       (pin Smd_rect_381000x889000 "2" 0.645160 -1.066800)
       (pin Smd_rect_381000x889000 "3" 0.645160 0.711200)
diff --git a/tests/RTT/ref/elem_pads.eps b/tests/RTT/ref/elem_pads.eps
new file mode 100644
index 0000000..f85e49f
--- /dev/null
+++ b/tests/RTT/ref/elem_pads.eps
@@ -0,0 +1,71 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: elem_pads.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01500 setlinewidth
+2 setlinecap
+0.301961 0.301961 0.301961 setrgbcolor
+0.22400 0.36500 0.22400 0.38500 t
+0.27500 0.36500 0.27500 0.38500 t
+0.27500 0.29500 0.27500 0.31500 t
+0.25000 0.29500 0.25000 0.31500 t
+0.22400 0.29500 0.22400 0.31500 t
+0.05118 setlinewidth
+0.19095 0.08819 0.19095 0.11181 t
+0.30905 0.08819 0.30905 0.11181 t
+% Layer topsilk group 1 drill 0 mask 0
+0.00800 setlinewidth
+1 setlinecap
+0 0 0 setrgbcolor
+0.22638 0.06260 0.27362 0.06260 t
+0.22638 0.13740 0.27362 0.13740 t
+0.01000 setlinewidth
+0.21000 0.28100 0.21000 0.40000 t
+0.21000 0.40000 0.29000 0.40000 t
+0.29000 0.40000 0.29000 0.28100 t
+0.29000 0.28100 0.21000 0.28100 t
+0.00700 setlinewidth
+0.21850 0.14350 0.23850 0.14350 t
+0.23850 0.14350 0.24350 0.14850 t
+0.24350 0.14850 0.24350 0.15850 t
+0.23850 0.16350 0.24350 0.15850 t
+0.22350 0.16350 0.23850 0.16350 t
+0.22350 0.14350 0.22350 0.18350 t
+0.23150 0.16350 0.24350 0.18350 t
+0.25550 0.15150 0.26350 0.14350 t
+0.26350 0.14350 0.26350 0.18350 t
+0.25550 0.18350 0.27050 0.18350 t
+0.22500 0.41500 0.22500 0.45000 t
+0.22500 0.45000 0.23000 0.45500 t
+0.23000 0.45500 0.24000 0.45500 t
+0.24000 0.45500 0.24500 0.45000 t
+0.24500 0.41500 0.24500 0.45000 t
+0.25700 0.42300 0.26500 0.41500 t
+0.26500 0.41500 0.26500 0.45500 t
+0.25700 0.45500 0.27200 0.45500 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/elem_pads.gbr/elem_pads.fab.gbr b/tests/RTT/ref/elem_pads.gbr/elem_pads.fab.gbr
index 07a6efb..8132cc0 100644
--- a/tests/RTT/ref/elem_pads.gbr/elem_pads.fab.gbr
+++ b/tests/RTT/ref/elem_pads.gbr/elem_pads.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 6 for group -1 layer_idx -1 *
-G04 Title: pads with different geometry, TODO:group_name *
+G04 start of page 6 for group -1 layer_idx 16777221 *
+G04 Title: pads with different geometry, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads.gbr/elem_pads.top.gbr b/tests/RTT/ref/elem_pads.gbr/elem_pads.top.gbr
index 28a265f..a92f8e8 100644
--- a/tests/RTT/ref/elem_pads.gbr/elem_pads.top.gbr
+++ b/tests/RTT/ref/elem_pads.gbr/elem_pads.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: pads with different geometry, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: pads with different geometry, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads.gbr/elem_pads.topmask.gbr b/tests/RTT/ref/elem_pads.gbr/elem_pads.topmask.gbr
index f4a2af9..8fcd612 100644
--- a/tests/RTT/ref/elem_pads.gbr/elem_pads.topmask.gbr
+++ b/tests/RTT/ref/elem_pads.gbr/elem_pads.topmask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: pads with different geometry, TODO:group_name *
+G04 start of page 3 for group 2 layer_idx 0 *
+G04 Title: pads with different geometry, top mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads.gbr/elem_pads.toppaste.gbr b/tests/RTT/ref/elem_pads.gbr/elem_pads.toppaste.gbr
index 3058898..c24e5fa 100644
--- a/tests/RTT/ref/elem_pads.gbr/elem_pads.toppaste.gbr
+++ b/tests/RTT/ref/elem_pads.gbr/elem_pads.toppaste.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: pads with different geometry, TODO:group_name *
+G04 start of page 5 for group 0 layer_idx 0 *
+G04 Title: pads with different geometry, top paste *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads.gbr/elem_pads.topsilk.gbr b/tests/RTT/ref/elem_pads.gbr/elem_pads.topsilk.gbr
index 90f0bd0..e41ac35 100644
--- a/tests/RTT/ref/elem_pads.gbr/elem_pads.topsilk.gbr
+++ b/tests/RTT/ref/elem_pads.gbr/elem_pads.topsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group 0 layer_idx 8 *
-G04 Title: pads with different geometry, TODO:group_name *
+G04 start of page 4 for group 1 layer_idx 8 *
+G04 Title: pads with different geometry, top silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads.nelma.em b/tests/RTT/ref/elem_pads.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/elem_pads.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/elem_pads.png b/tests/RTT/ref/elem_pads.png
index ca43f43..3cc3316 100644
Binary files a/tests/RTT/ref/elem_pads.png and b/tests/RTT/ref/elem_pads.png differ
diff --git a/tests/RTT/ref/elem_pads.png.text b/tests/RTT/ref/elem_pads.png.text
new file mode 100644
index 0000000..cfd518e
--- /dev/null
+++ b/tests/RTT/ref/elem_pads.png.text
@@ -0,0 +1,13 @@
+r6630
+
+R1 pads
+61 x 89 pixels (50.833 x 74.167)
+distance between pads 81 pixels (67.5)
+
+U1 pads
+18 x 42 pixels (15 x 35)
+pad 5 upper to nearest silk screen corner 2 x 2 pixels (1.667 x 1.667)
+pad 5 distance to pad 4 is 13 pixels (10.833)
+
+(mil)
+
diff --git a/tests/RTT/ref/elem_pads.ps.gz b/tests/RTT/ref/elem_pads.ps.gz
index f3d44f7..c832cca 100644
Binary files a/tests/RTT/ref/elem_pads.ps.gz and b/tests/RTT/ref/elem_pads.ps.gz differ
diff --git a/tests/RTT/ref/elem_pads.remote.gz b/tests/RTT/ref/elem_pads.remote.gz
index ba000de..f0b2ecb 100644
Binary files a/tests/RTT/ref/elem_pads.remote.gz and b/tests/RTT/ref/elem_pads.remote.gz differ
diff --git a/tests/RTT/ref/elem_pads.scad b/tests/RTT/ref/elem_pads.scad
new file mode 100644
index 0000000..3965c67
--- /dev/null
+++ b/tests/RTT/ref/elem_pads.scad
@@ -0,0 +1,107 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(1.199896,0.203200,0.037500,6.350000,-1.590040,180.000000,1,1,1);
+	line_segment_r(1.199896,0.203200,0.037500,6.350000,-3.489960,180.000000,1,1,1);
+	line_segment_r(3.022600,0.254000,0.037500,5.334000,-8.648700,90.000000,1,1,1);
+	line_segment_r(2.032000,0.254000,0.037500,6.350000,-10.160000,180.000000,1,1,1);
+	line_segment_r(3.022600,0.254000,0.037500,7.366000,-8.648700,-90.000000,1,1,1);
+	line_segment_r(2.032000,0.254000,0.037500,6.350000,-7.137400,0.000000,1,1,1);
+	line_segment_r(0.508000,0.177800,0.037500,5.803900,-3.644900,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,6.121400,-3.708400,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,6.184900,-3.898900,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,6.121400,-4.089400,-135.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,5.867400,-4.152900,180.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,5.676900,-4.152900,90.000000,1,1,1);
+	line_segment_r(0.592425,0.177800,0.037500,6.032500,-4.406900,120.963753,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,6.591301,-3.746500,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,6.692901,-4.152900,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,6.680201,-4.660900,180.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,5.715000,-10.985500,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,5.778500,-11.493500,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,5.969000,-11.557000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,6.159500,-11.493500,-135.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,6.223000,-10.985500,90.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,6.629401,-10.642600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,6.731001,-11.049000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,6.718301,-11.557000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/elem_pads.svg b/tests/RTT/ref/elem_pads.svg
index bde4e53..2a06aca 100644
--- a/tests/RTT/ref/elem_pads.svg
+++ b/tests/RTT/ref/elem_pads.svg
@@ -1,16 +1,16 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="5.6896" y1="9.2710" x2="5.6896" y2="9.7790" stroke-width="0.3810" stroke="#4d4d4d" stroke-linecap="square"/>
  <line x1="6.9850" y1="9.2710" x2="6.9850" y2="9.7790" stroke-width="0.3810" stroke="#4d4d4d" stroke-linecap="square"/>
@@ -20,7 +20,7 @@
  <line x1="4.8501" y1="2.2400" x2="4.8501" y2="2.8400" stroke-width="1.3000" stroke="#4d4d4d" stroke-linecap="square"/>
  <line x1="7.8499" y1="2.2400" x2="7.8499" y2="2.8400" stroke-width="1.3000" stroke="#4d4d4d" stroke-linecap="square"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="5.7501" y1="1.5900" x2="6.9499" y2="1.5900" stroke-width="0.2032" stroke="#000000" stroke-linecap="round"/>
  <line x1="5.7501" y1="3.4900" x2="6.9499" y2="3.4900" stroke-width="0.2032" stroke="#000000" stroke-linecap="round"/>
diff --git a/tests/RTT/ref/elem_pads_ds.bbrd.png b/tests/RTT/ref/elem_pads_ds.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/elem_pads_ds.bbrd.png differ
diff --git a/tests/RTT/ref/elem_pads_ds.bom b/tests/RTT/ref/elem_pads_ds.bom
index fc3da8f..84aa2fe 100644
--- a/tests/RTT/ref/elem_pads_ds.bom
+++ b/tests/RTT/ref/elem_pads_ds.bom
@@ -5,4 +5,4 @@
 # Title: element with pads on both sides - PCB BOM
 # Quantity, Description, Value, RefDes
 # --------------------------------------------
-1,"(unknown)","(unknown)",(unknown) 
+1,"(unknown)","(unknown)",E1 
diff --git a/tests/RTT/ref/elem_pads_ds.dsn b/tests/RTT/ref/elem_pads_ds.dsn
index bbe5788..16a78da 100644
--- a/tests/RTT/ref/elem_pads_ds.dsn
+++ b/tests/RTT/ref/elem_pads_ds.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,12 +33,12 @@
     )
   )
   (placement
-    (component 8
-      (place "null" 6.191250 8.096250 front 0 (PN 0))
+    (component 9
+      (place "E1" 6.191250 8.096250 front 0 (PN 0))
     )
   )
   (library
-    (image 8
+    (image 9
       (pin Smd_rect_2159000x254000 "1" -0.793750 0.793750)
       (pin Smd_rect_254000x2159000 "2" 0.793750 -0.793750)
     )
diff --git a/tests/RTT/ref/elem_pads_ds.eps b/tests/RTT/ref/elem_pads_ds.eps
new file mode 100644
index 0000000..6099fa3
--- /dev/null
+++ b/tests/RTT/ref/elem_pads_ds.eps
@@ -0,0 +1,48 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: elem_pads_ds.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0.8 0.8 0.8 setrgbcolor
+0.27500 0.17500 0.27500 0.25000 t
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.17500 0.15000 0.25000 0.15000 t
+% Layer topsilk group 1 drill 0 mask 0
+1 setlinecap
+0 0 0 setrgbcolor
+0.17500 0.15000 0.17500 0.25000 t
+0.00700 setlinewidth
+0.17500 0.09300 0.19000 0.09300 t
+0.17500 0.11500 0.19500 0.11500 t
+0.17500 0.07500 0.17500 0.11500 t
+0.17500 0.07500 0.19500 0.07500 t
+0.20700 0.08300 0.21500 0.07500 t
+0.21500 0.07500 0.21500 0.11500 t
+0.20700 0.11500 0.22200 0.11500 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottom.gbr b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottom.gbr
index dd2ba70..ed091d0 100644
--- a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottom.gbr
+++ b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottom.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group 1 layer_idx 1 *
-G04 Title: element with pads on both sides, TODO:group_name *
+G04 start of page 3 for group 10 layer_idx 1 *
+G04 Title: element with pads on both sides, bottom copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottommask.gbr b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottommask.gbr
index 16f6960..8286228 100644
--- a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottommask.gbr
+++ b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottommask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: element with pads on both sides, TODO:group_name *
+G04 start of page 5 for group 11 layer_idx 0 *
+G04 Title: element with pads on both sides, bottom mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottompaste.gbr b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottompaste.gbr
index 43b4852..8706996 100644
--- a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottompaste.gbr
+++ b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.bottompaste.gbr
@@ -1,5 +1,5 @@
-G04 start of page 8 for group -1 layer_idx -1 *
-G04 Title: element with pads on both sides, TODO:group_name *
+G04 start of page 8 for group 13 layer_idx 0 *
+G04 Title: element with pads on both sides, bottom paste *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,6 +9,6 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNBOTTOMPASTE*%
-%ADD17C,0.0100*%
-G54D17*X27500Y32500D02*Y25000D01*
+%ADD18C,0.0100*%
+G54D18*X27500Y32500D02*Y25000D01*
 M02*
diff --git a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.fab.gbr b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.fab.gbr
index 52994fd..7d5711f 100644
--- a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.fab.gbr
+++ b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 9 for group -1 layer_idx -1 *
-G04 Title: element with pads on both sides, TODO:group_name *
+G04 start of page 9 for group -1 layer_idx 16777221 *
+G04 Title: element with pads on both sides, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,10 +9,10 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNFAB*%
-%ADD20C,0.0100*%
-%ADD19C,0.0001*%
-%ADD18C,0.0060*%
-G54D18*X3000Y125000D02*X3750Y124250D01*
+%ADD21C,0.0100*%
+%ADD20C,0.0001*%
+%ADD19C,0.0060*%
+G54D19*X3000Y125000D02*X3750Y124250D01*
 X750Y125000D02*X3000D01*
 X0Y124250D02*X750Y125000D01*
 X0Y124250D02*Y122750D01*
@@ -23,7 +23,7 @@ Y119750D01*
 X3000Y119000D02*X3750Y119750D01*
 X750Y119000D02*X3000D01*
 X0Y119750D02*X750Y119000D01*
-G54D19*G36*
+G54D20*G36*
 X5550Y125000D02*Y119000D01*
 X10050D01*
 Y125000D01*
@@ -53,14 +53,14 @@ X31650D01*
 Y125000D01*
 X27150D01*
 G37*
-G54D18*X0Y118000D02*X5550D01*
+G54D19*X0Y118000D02*X5550D01*
 X41750Y125000D02*Y119000D01*
 X43700Y125000D02*X44750Y123950D01*
 Y120050D01*
 X43700Y119000D02*X44750Y120050D01*
 X41000Y119000D02*X43700D01*
 X41000Y125000D02*X43700D01*
-G54D19*G36*
+G54D20*G36*
 X46550D02*Y119000D01*
 X51050D01*
 Y125000D01*
@@ -90,10 +90,10 @@ X75350D01*
 Y125000D01*
 X70850D01*
 G37*
-G54D18*X76250D02*X77750D01*
+G54D19*X76250D02*X77750D01*
 X77000D02*Y119000D01*
 X76250D02*X77750D01*
-G54D19*G36*
+G54D20*G36*
 X79550Y125000D02*Y119000D01*
 X84050D01*
 Y125000D01*
@@ -117,13 +117,13 @@ X100250D01*
 Y125000D01*
 X95750D01*
 G37*
-G54D18*X41000Y118000D02*X52550D01*
+G54D19*X41000Y118000D02*X52550D01*
 X96050Y119000D02*X98000D01*
 X95000Y120050D02*X96050Y119000D01*
 X95000Y123950D02*Y120050D01*
 Y123950D02*X96050Y125000D01*
 X98000D01*
-G54D19*G36*
+G54D20*G36*
 X99800D02*Y119000D01*
 X104300D01*
 Y125000D01*
@@ -147,14 +147,14 @@ X120500D01*
 Y125000D01*
 X116000D01*
 G37*
-G54D18*X95000Y118000D02*X99800D01*
+G54D19*X95000Y118000D02*X99800D01*
 X130750Y125000D02*Y119000D01*
 X130000Y125000D02*X133000D01*
 X133750Y124250D01*
 Y122750D01*
 X133000Y122000D02*X133750Y122750D01*
 X130750Y122000D02*X133000D01*
-G54D19*G36*
+G54D20*G36*
 X135550Y125000D02*Y119000D01*
 X140050D01*
 Y125000D01*
@@ -190,10 +190,10 @@ X167050D01*
 Y125000D01*
 X162550D01*
 G37*
-G54D18*X130000Y118000D02*X135550D01*
+G54D19*X130000Y118000D02*X135550D01*
 X0Y140000D02*X3000D01*
 X1500D02*Y134000D01*
-G54D19*G36*
+G54D20*G36*
 X4800Y140000D02*Y134000D01*
 X9300D01*
 Y140000D01*
@@ -523,15 +523,15 @@ X333300D01*
 Y140000D01*
 X328800D01*
 G37*
-G54D20*X0Y50000D02*X50000D01*
+G54D21*X0Y50000D02*X50000D01*
 X0D02*Y0D01*
 X50000Y50000D02*Y0D01*
 X0D02*X50000D01*
-G54D18*X200000Y65000D02*Y59000D01*
+G54D19*X200000Y65000D02*Y59000D01*
 Y65000D02*X202250Y62000D01*
 X204500Y65000D01*
 Y59000D01*
-G54D19*G36*
+G54D20*G36*
 X206300Y65000D02*Y59000D01*
 X210800D01*
 Y65000D01*
@@ -567,13 +567,13 @@ X237800D01*
 Y65000D01*
 X233300D01*
 G37*
-G54D18*X242150D02*Y59000D01*
+G54D19*X242150D02*Y59000D01*
 X244100Y65000D02*X245150Y63950D01*
 Y60050D01*
 X244100Y59000D02*X245150Y60050D01*
 X241400Y59000D02*X244100D01*
 X241400Y65000D02*X244100D01*
-G54D19*G36*
+G54D20*G36*
 X246950D02*Y59000D01*
 X251450D01*
 Y65000D01*
@@ -633,7 +633,7 @@ X300050D01*
 Y65000D01*
 X295550D01*
 G37*
-G54D18*X303650D02*X306650D01*
+G54D19*X303650D02*X306650D01*
 X303650D02*Y62000D01*
 X304400Y62750D01*
 X305900D01*
@@ -642,7 +642,7 @@ Y59750D01*
 X305900Y59000D02*X306650Y59750D01*
 X304400Y59000D02*X305900D01*
 X303650Y59750D02*X304400Y59000D01*
-G54D19*G36*
+G54D20*G36*
 X308450Y65000D02*Y59000D01*
 X312950D01*
 Y65000D01*
@@ -750,7 +750,7 @@ X410150D01*
 Y65000D01*
 X405650D01*
 G37*
-G54D18*X413750D02*X416750D01*
+G54D19*X413750D02*X416750D01*
 X413750D02*Y62000D01*
 X414500Y62750D01*
 X416000D01*
@@ -759,7 +759,7 @@ Y59750D01*
 X416000Y59000D02*X416750Y59750D01*
 X414500Y59000D02*X416000D01*
 X413750Y59750D02*X414500Y59000D01*
-G54D19*G36*
+G54D20*G36*
 X418550Y65000D02*Y59000D01*
 X423050D01*
 Y65000D01*
@@ -861,7 +861,7 @@ X514850D01*
 Y65000D01*
 X510350D01*
 G37*
-G54D18*X0Y-8000D02*X3000D01*
+G54D19*X0Y-8000D02*X3000D01*
 X3750Y-7250D01*
 Y-5450D02*Y-7250D01*
 X3000Y-4700D02*X3750Y-5450D01*
@@ -871,7 +871,7 @@ X0Y-2000D02*X3000D01*
 X3750Y-2750D01*
 Y-3950D01*
 X3000Y-4700D02*X3750Y-3950D01*
-G54D19*G36*
+G54D20*G36*
 X5550Y-2000D02*Y-8000D01*
 X10050D01*
 Y-2000D01*
@@ -1063,7 +1063,7 @@ X193650D01*
 Y-2000D01*
 X189150D01*
 G37*
-G54D18*X197250Y-7250D02*X198000Y-8000D01*
+G54D19*X197250Y-7250D02*X198000Y-8000D01*
 X197250Y-6050D02*Y-7250D01*
 Y-6050D02*X198300Y-5000D01*
 X199200D01*
@@ -1078,7 +1078,7 @@ X199500D01*
 X200250Y-2750D01*
 Y-3950D01*
 X199200Y-5000D02*X200250Y-3950D01*
-G54D19*G36*
+G54D20*G36*
 X202050Y-2000D02*Y-8000D01*
 X206550D01*
 Y-2000D01*
@@ -1228,7 +1228,7 @@ X349650D01*
 Y-2000D01*
 X345150D01*
 G37*
-G54D18*X353250D02*X356250D01*
+G54D19*X353250D02*X356250D01*
 X353250D02*Y-5000D01*
 X354000Y-4250D01*
 X355500D01*
@@ -1237,7 +1237,7 @@ Y-7250D01*
 X355500Y-8000D02*X356250Y-7250D01*
 X354000Y-8000D02*X355500D01*
 X353250Y-7250D02*X354000Y-8000D01*
-G54D19*G36*
+G54D20*G36*
 X358050Y-2000D02*Y-8000D01*
 X362550D01*
 Y-2000D01*
@@ -1297,7 +1297,7 @@ X411150D01*
 Y-2000D01*
 X406650D01*
 G37*
-G54D18*X412050D02*X415050D01*
+G54D19*X412050D02*X415050D01*
 X412050D02*Y-5000D01*
 X412800Y-4250D01*
 X414300D01*
@@ -1306,7 +1306,7 @@ Y-7250D01*
 X414300Y-8000D02*X415050Y-7250D01*
 X412800Y-8000D02*X414300D01*
 X412050Y-7250D02*X412800Y-8000D01*
-G54D19*G36*
+G54D20*G36*
 X416850Y-2000D02*Y-8000D01*
 X421350D01*
 Y-2000D01*
@@ -1384,13 +1384,13 @@ X488850D01*
 Y-2000D01*
 X484350D01*
 G37*
-G54D18*X200750Y80000D02*Y74000D01*
+G54D19*X200750Y80000D02*Y74000D01*
 X202700Y80000D02*X203750Y78950D01*
 Y75050D01*
 X202700Y74000D02*X203750Y75050D01*
 X200000Y74000D02*X202700D01*
 X200000Y80000D02*X202700D01*
-G54D19*G36*
+G54D20*G36*
 X205550D02*Y74000D01*
 X210050D01*
 Y80000D01*
@@ -1450,13 +1450,13 @@ X261350D01*
 Y80000D01*
 X256850D01*
 G37*
-G54D18*X200000Y93500D02*Y89000D01*
+G54D19*X200000Y93500D02*Y89000D01*
 Y93500D02*X201050Y95000D01*
 X202700D01*
 X203750Y93500D01*
 Y89000D01*
 X200000Y92000D02*X203750D01*
-G54D19*G36*
+G54D20*G36*
 X205550Y95000D02*Y89000D01*
 X210050D01*
 Y95000D01*
@@ -1492,9 +1492,9 @@ X237050D01*
 Y95000D01*
 X232550D01*
 G37*
-G54D18*X200000Y110000D02*X203000D01*
+G54D19*X200000Y110000D02*X203000D01*
 X201500D02*Y104000D01*
-G54D19*G36*
+G54D20*G36*
 X204800Y110000D02*Y104000D01*
 X209300D01*
 Y110000D01*
@@ -1686,10 +1686,10 @@ X395600D01*
 Y110000D01*
 X391100D01*
 G37*
-G54D18*X399200D02*Y104000D01*
+G54D19*X399200D02*Y104000D01*
 Y110000D02*X402200D01*
 X399200Y107300D02*X401450D01*
-G54D19*G36*
+G54D20*G36*
 X404000Y110000D02*Y104000D01*
 X408500D01*
 Y110000D01*
@@ -1749,13 +1749,13 @@ X457100D01*
 Y110000D01*
 X452600D01*
 G37*
-G54D18*X461450D02*Y104000D01*
+G54D19*X461450D02*Y104000D01*
 X463400Y110000D02*X464450Y108950D01*
 Y105050D01*
 X463400Y104000D02*X464450Y105050D01*
 X460700Y104000D02*X463400D01*
 X460700Y110000D02*X463400D01*
-G54D19*G36*
+G54D20*G36*
 X466250D02*Y104000D01*
 X470750D01*
 Y110000D01*
diff --git a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.top.gbr b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.top.gbr
index 2a989b2..b76350c 100644
--- a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.top.gbr
+++ b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: element with pads on both sides, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: element with pads on both sides, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.topmask.gbr b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.topmask.gbr
index 36f6877..3285b5c 100644
--- a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.topmask.gbr
+++ b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.topmask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group -1 layer_idx -1 *
-G04 Title: element with pads on both sides, TODO:group_name *
+G04 start of page 4 for group 2 layer_idx 0 *
+G04 Title: element with pads on both sides, top mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.toppaste.gbr b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.toppaste.gbr
index 64eb44c..d9a0301 100644
--- a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.toppaste.gbr
+++ b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.toppaste.gbr
@@ -1,5 +1,5 @@
-G04 start of page 7 for group -1 layer_idx -1 *
-G04 Title: element with pads on both sides, TODO:group_name *
+G04 start of page 7 for group 0 layer_idx 0 *
+G04 Title: element with pads on both sides, top paste *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,6 +9,6 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNTOPPASTE*%
-%ADD16C,0.0100*%
-G54D16*X17500Y35000D02*X25000D01*
+%ADD17C,0.0100*%
+G54D17*X17500Y35000D02*X25000D01*
 M02*
diff --git a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.topsilk.gbr b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.topsilk.gbr
index e2b9245..5cda991 100644
--- a/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.topsilk.gbr
+++ b/tests/RTT/ref/elem_pads_ds.gbr/elem_pads_ds.topsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 6 for group 0 layer_idx 8 *
-G04 Title: element with pads on both sides, TODO:group_name *
+G04 start of page 6 for group 1 layer_idx 8 *
+G04 Title: element with pads on both sides, top silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,6 +9,14 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNTOPSILK*%
+%ADD16C,0.0070*%
 %ADD15C,0.0100*%
 G54D15*X17500Y35000D02*Y25000D01*
+G54D16*Y40700D02*X19000D01*
+X17500Y38500D02*X19500D01*
+X17500Y42500D02*Y38500D01*
+Y42500D02*X19500D01*
+X20700Y41700D02*X21500Y42500D01*
+Y38500D01*
+X20700D02*X22200D01*
 M02*
diff --git a/tests/RTT/ref/elem_pads_ds.nelma.em b/tests/RTT/ref/elem_pads_ds.nelma.em
new file mode 100644
index 0000000..40f7fea
--- /dev/null
+++ b/tests/RTT/ref/elem_pads_ds.nelma.em
@@ -0,0 +1,75 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+layer substrate-11 {
+	height = 20
+	z-order = 11
+	material = "composite"
+}
+layer bottom {
+	height = 1
+	z-order = 12
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top",
+		"substrate-11",
+		"bottom"
+	}
+}
diff --git a/tests/RTT/ref/elem_pads_ds.net b/tests/RTT/ref/elem_pads_ds.net
new file mode 100644
index 0000000..2a9520e
--- /dev/null
+++ b/tests/RTT/ref/elem_pads_ds.net
@@ -0,0 +1,14 @@
+C  IPC-D-356 Netlist generated by <version>
+C  
+C  File created on <date>
+C  
+P  JOB   element with pads on both sides
+P  CODE  00
+P  UNITS CUST 0
+P  DIM   N
+P  VER   IPC-D-356
+P  IMAGE PRIMARY
+C  
+327N/C              E1    -1          A01X+002125Y+003500X0850Y0100R000 S1      
+327N/C              E1    -2          A02X+002750Y+002875X0100Y0850R000 S2      
+999
diff --git a/tests/RTT/ref/elem_pads_ds.png b/tests/RTT/ref/elem_pads_ds.png
index 9d9a036..9a709e3 100644
Binary files a/tests/RTT/ref/elem_pads_ds.png and b/tests/RTT/ref/elem_pads_ds.png differ
diff --git a/tests/RTT/ref/elem_pads_ds.png.text b/tests/RTT/ref/elem_pads_ds.png.text
new file mode 100644
index 0000000..4d53a48
--- /dev/null
+++ b/tests/RTT/ref/elem_pads_ds.png.text
@@ -0,0 +1,14 @@
+r6630
+
+E1
+2 pads 1 silk line + text (E1)
+
+silk line 132 pixels (110) long 12 pixels (10) wide
+
+copper pads 102 pixels (85) long 12 pixels (10) wide
+
+pad 1 shares it's terminus with the silk line
+
+pad 2's highest point is 114 x 18 pixels (95 x 15) over from the inside corner of pad 1 & the silk line
+
+pad 2's lenght 102 pixels (85) width 12 pixels (10) 
diff --git a/tests/RTT/ref/elem_pads_ds.ps.gz b/tests/RTT/ref/elem_pads_ds.ps.gz
index 867a51f..3a4f36a 100644
Binary files a/tests/RTT/ref/elem_pads_ds.ps.gz and b/tests/RTT/ref/elem_pads_ds.ps.gz differ
diff --git a/tests/RTT/ref/elem_pads_ds.remote.gz b/tests/RTT/ref/elem_pads_ds.remote.gz
index df2c3f5..dd09a2b 100644
Binary files a/tests/RTT/ref/elem_pads_ds.remote.gz and b/tests/RTT/ref/elem_pads_ds.remote.gz differ
diff --git a/tests/RTT/ref/elem_pads_ds.scad b/tests/RTT/ref/elem_pads_ds.scad
new file mode 100644
index 0000000..8fc3aa6
--- /dev/null
+++ b/tests/RTT/ref/elem_pads_ds.scad
@@ -0,0 +1,91 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(2.540000,0.254000,0.037500,4.445000,-5.080000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,4.635500,-2.362200,180.000000,1,1,1);
+	line_segment_r(0.508000,0.177800,0.037500,4.699000,-2.921000,180.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,4.445000,-2.413000,90.000000,1,1,1);
+	line_segment_r(0.508000,0.177800,0.037500,4.699000,-1.905000,180.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,5.359401,-2.006600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,5.461001,-2.413000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,5.448301,-2.921000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/elem_pads_ds.svg b/tests/RTT/ref/elem_pads_ds.svg
index 87da67c..5ac05ce 100644
--- a/tests/RTT/ref/elem_pads_ds.svg
+++ b/tests/RTT/ref/elem_pads_ds.svg
@@ -1,23 +1,30 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <line x1="6.9850" y1="4.4450" x2="6.9850" y2="6.3500" stroke-width="0.2540" stroke="#cccccc" stroke-linecap="round"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="4.4450" y1="3.8100" x2="6.3500" y2="3.8100" stroke-width="0.2540" stroke="#4d4d4d" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="4.4450" y1="3.8100" x2="4.4450" y2="6.3500" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
+ <line x1="4.4450" y1="2.3622" x2="4.8260" y2="2.3622" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
+ <line x1="4.4450" y1="2.9210" x2="4.9530" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
+ <line x1="4.4450" y1="1.9050" x2="4.4450" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
+ <line x1="4.4450" y1="1.9050" x2="4.9530" y2="1.9050" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
+ <line x1="5.2578" y1="2.1082" x2="5.4610" y2="1.9050" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
+ <line x1="5.4610" y1="1.9050" x2="5.4610" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
+ <line x1="5.2578" y1="2.9210" x2="5.6388" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
 </g>
 </svg>
diff --git a/tests/RTT/ref/elem_pads_ds.xy b/tests/RTT/ref/elem_pads_ds.xy
index 889e1cb..27b7903 100644
--- a/tests/RTT/ref/elem_pads_ds.xy
+++ b/tests/RTT/ref/elem_pads_ds.xy
@@ -6,4 +6,4 @@
 # RefDes, Description, Value, X, Y, rotation, top/bottom
 # X,Y in mil.  rotation in degrees.
 # --------------------------------------------
-(unknown),"(unknown)","(unknown)",243.75,318.75,0,top
+E1,"(unknown)","(unknown)",243.75,318.75,0,top
diff --git a/tests/RTT/ref/elem_pins.bbrd.png b/tests/RTT/ref/elem_pins.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/elem_pins.bbrd.png differ
diff --git a/tests/RTT/ref/elem_pins.dsn b/tests/RTT/ref/elem_pins.dsn
index 08ca2ab..032b0d7 100644
--- a/tests/RTT/ref/elem_pins.dsn
+++ b/tests/RTT/ref/elem_pins.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,19 +33,19 @@
     )
   )
   (placement
-    (component 8
+    (component 9
       (place "U1" 5.715000 9.525000 front 0 (PN 0))
     )
-    (component 20
+    (component 21
       (place "U2" 5.715000 4.445000 front 0 (PN 0))
     )
   )
   (library
-    (image 8
+    (image 9
       (pin Th_square_2032000 "1" -3.810000 0.000000)
       (pin Th_round_2032000 "2" 3.810000 0.000000)
     )
-    (image 20
+    (image 21
       (pin Th_square_2032000 "1" -3.810000 0.000000)
       (pin Th_square_2032000 "2" 3.810000 0.000000)
     )
diff --git a/tests/RTT/ref/elem_pins.eps b/tests/RTT/ref/elem_pins.eps
new file mode 100644
index 0000000..758ab91
--- /dev/null
+++ b/tests/RTT/ref/elem_pins.eps
@@ -0,0 +1,176 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: elem_pins.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.301961 0.301961 0.301961 setrgbcolor
+0.03500 0.08500 0.11500 0.16500 r
+0.37500 0.12500 0.04000 c
+0.15500 0.30843 moveto
+0.10814 0.28500 lineto
+0.05843 0.28500 lineto
+0.03500 0.30843 lineto
+0.03500 0.34157 lineto
+0.05843 0.36500 lineto
+0.10814 0.36500 lineto
+0.15500 0.34157 lineto
+fill
+0.45500 0.29186 moveto
+0.40814 0.24500 lineto
+0.34186 0.24500 lineto
+0.29500 0.29186 lineto
+0.29500 0.34157 lineto
+0.34186 0.36500 lineto
+0.40814 0.36500 lineto
+0.45500 0.34157 lineto
+fill
+1 1 1 setrgbcolor
+0.07500 0.12500 0.01968 c
+0.37500 0.12500 0.01968 c
+0.07500 0.32500 0.01968 c
+0.37500 0.32500 0.01968 c
+% Layer group5 group 5 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.03500 0.08500 0.11500 0.16500 r
+0.37500 0.12500 0.04000 c
+0.15500 0.30843 moveto
+0.10814 0.28500 lineto
+0.05843 0.28500 lineto
+0.03500 0.30843 lineto
+0.03500 0.34157 lineto
+0.05843 0.36500 lineto
+0.10814 0.36500 lineto
+0.15500 0.34157 lineto
+fill
+0.45500 0.29186 moveto
+0.40814 0.24500 lineto
+0.34186 0.24500 lineto
+0.29500 0.29186 lineto
+0.29500 0.34157 lineto
+0.34186 0.36500 lineto
+0.40814 0.36500 lineto
+0.45500 0.34157 lineto
+fill
+1 1 1 setrgbcolor
+0.07500 0.12500 0.01968 c
+0.37500 0.12500 0.01968 c
+0.07500 0.32500 0.01968 c
+0.37500 0.32500 0.01968 c
+% Layer group7 group 7 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.03500 0.08500 0.11500 0.16500 r
+0.37500 0.12500 0.04000 c
+0.15500 0.30843 moveto
+0.10814 0.28500 lineto
+0.05843 0.28500 lineto
+0.03500 0.30843 lineto
+0.03500 0.34157 lineto
+0.05843 0.36500 lineto
+0.10814 0.36500 lineto
+0.15500 0.34157 lineto
+fill
+0.45500 0.29186 moveto
+0.40814 0.24500 lineto
+0.34186 0.24500 lineto
+0.29500 0.29186 lineto
+0.29500 0.34157 lineto
+0.34186 0.36500 lineto
+0.40814 0.36500 lineto
+0.45500 0.34157 lineto
+fill
+1 1 1 setrgbcolor
+0.07500 0.12500 0.01968 c
+0.37500 0.12500 0.01968 c
+0.07500 0.32500 0.01968 c
+0.37500 0.32500 0.01968 c
+% Layer top group 3 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.03500 0.08500 0.11500 0.16500 r
+0.37500 0.12500 0.04000 c
+0.15500 0.30843 moveto
+0.10814 0.28500 lineto
+0.05843 0.28500 lineto
+0.03500 0.30843 lineto
+0.03500 0.34157 lineto
+0.05843 0.36500 lineto
+0.10814 0.36500 lineto
+0.15500 0.34157 lineto
+fill
+0.45500 0.29186 moveto
+0.40814 0.24500 lineto
+0.34186 0.24500 lineto
+0.29500 0.29186 lineto
+0.29500 0.34157 lineto
+0.34186 0.36500 lineto
+0.40814 0.36500 lineto
+0.45500 0.34157 lineto
+fill
+1 1 1 setrgbcolor
+0.07500 0.12500 0.01968 c
+0.37500 0.12500 0.01968 c
+0.07500 0.32500 0.01968 c
+0.37500 0.32500 0.01968 c
+% Layer plated-drill group -1 drill 1 mask 0
+0.07500 0.12500 0.01968 c
+0.37500 0.12500 0.01968 c
+0.07500 0.32500 0.01968 c
+0.37500 0.32500 0.01968 c
+% Layer topsilk group 1 drill 0 mask 0
+0.01000 setlinewidth
+0 0 0 setrgbcolor
+0.02500 0.07500 0.02500 0.17500 t
+0.42500 0.17500 0.02500 0.17500 t
+0.42500 0.17500 0.42500 0.07500 t
+0.02500 0.07500 0.17500 0.07500 t
+0.27500 0.07500 0.42500 0.07500 t
+0 180 -0.05000 0.05000 0.22500 0.07500 0.2 a
+0.02500 0.27500 0.02500 0.37500 t
+0.42500 0.37500 0.02500 0.37500 t
+0.42500 0.37500 0.42500 0.27500 t
+0.02500 0.27500 0.17500 0.27500 t
+0.27500 0.27500 0.42500 0.27500 t
+0 180 -0.05000 0.05000 0.22500 0.27500 0.2 a
+0.00700 setlinewidth
+0.07500 0.02500 0.07500 0.06000 t
+0.07500 0.06000 0.08000 0.06500 t
+0.08000 0.06500 0.09000 0.06500 t
+0.09000 0.06500 0.09500 0.06000 t
+0.09500 0.02500 0.09500 0.06000 t
+0.10700 0.03300 0.11500 0.02500 t
+0.11500 0.02500 0.11500 0.06500 t
+0.10700 0.06500 0.12200 0.06500 t
+0.07500 0.22500 0.07500 0.26000 t
+0.07500 0.26000 0.08000 0.26500 t
+0.08000 0.26500 0.09000 0.26500 t
+0.09000 0.26500 0.09500 0.26000 t
+0.09500 0.22500 0.09500 0.26000 t
+0.10700 0.23000 0.11200 0.22500 t
+0.11200 0.22500 0.12700 0.22500 t
+0.12700 0.22500 0.13200 0.23000 t
+0.13200 0.23000 0.13200 0.24000 t
+0.10700 0.26500 0.13200 0.24000 t
+0.10700 0.26500 0.13200 0.26500 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/elem_pins.gbr/elem_pins.bottommask.gbr b/tests/RTT/ref/elem_pins.gbr/elem_pins.bottommask.gbr
index f1ff4d5..20ca26c 100644
--- a/tests/RTT/ref/elem_pins.gbr/elem_pins.bottommask.gbr
+++ b/tests/RTT/ref/elem_pins.gbr/elem_pins.bottommask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group -1 layer_idx -1 *
-G04 Title: pins with different shapes, TODO:group_name *
+G04 start of page 4 for group 11 layer_idx 0 *
+G04 Title: pins with different shapes, bottom mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pins.gbr/elem_pins.fab.gbr b/tests/RTT/ref/elem_pins.gbr/elem_pins.fab.gbr
index f304524..5d20339 100644
--- a/tests/RTT/ref/elem_pins.gbr/elem_pins.fab.gbr
+++ b/tests/RTT/ref/elem_pins.gbr/elem_pins.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: pins with different shapes, TODO:group_name *
+G04 start of page 6 for group -1 layer_idx 16777221 *
+G04 Title: pins with different shapes, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,11 +9,11 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNFAB*%
-%ADD19C,0.0100*%
-%ADD18C,0.0001*%
-%ADD17C,0.0060*%
-%ADD16C,0.0080*%
-G54D16*X7500Y37500D02*Y35900D01*
+%ADD21C,0.0100*%
+%ADD20C,0.0001*%
+%ADD19C,0.0060*%
+%ADD18C,0.0080*%
+G54D18*X7500Y37500D02*Y35900D01*
 Y37500D02*X8887Y38300D01*
 X7500Y37500D02*X6113Y38300D01*
 X37500Y37500D02*Y35900D01*
@@ -28,7 +28,7 @@ X37500Y17500D02*X36113Y18300D01*
 X15000Y106250D02*Y104650D01*
 Y106250D02*X16387Y107050D01*
 X15000Y106250D02*X13613Y107050D01*
-G54D17*X135000Y110000D02*X136500Y107000D01*
+G54D19*X135000Y110000D02*X136500Y107000D01*
 X138000Y110000D01*
 X136500Y107000D02*Y104000D01*
 X139800Y107300D02*X142050D01*
@@ -49,7 +49,7 @@ X144600Y104750D02*X145350Y104000D01*
 X98000Y106250D02*X101000Y110000D01*
 X98000Y106250D02*X101750D01*
 X101000Y110000D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X45000Y110000D02*Y104000D01*
 X49500D01*
 Y110000D01*
@@ -67,16 +67,16 @@ X60300D01*
 Y110000D01*
 X55800D01*
 G37*
-G54D17*X61200Y106250D02*X64200Y110000D01*
+G54D19*X61200Y106250D02*X64200Y110000D01*
 X61200Y106250D02*X64950D01*
 X64200Y110000D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X66750Y110000D02*Y104000D01*
 X71250D01*
 Y110000D01*
 X66750D01*
 G37*
-G54D17*X3000Y125000D02*X3750Y124250D01*
+G54D19*X3000Y125000D02*X3750Y124250D01*
 X750Y125000D02*X3000D01*
 X0Y124250D02*X750Y125000D01*
 X0Y124250D02*Y122750D01*
@@ -87,7 +87,7 @@ Y119750D01*
 X3000Y119000D02*X3750Y119750D01*
 X750Y119000D02*X3000D01*
 X0Y119750D02*X750Y119000D01*
-G54D18*G36*
+G54D20*G36*
 X5550Y125000D02*Y119000D01*
 X10050D01*
 Y125000D01*
@@ -117,14 +117,14 @@ X31650D01*
 Y125000D01*
 X27150D01*
 G37*
-G54D17*X0Y118000D02*X5550D01*
+G54D19*X0Y118000D02*X5550D01*
 X41750Y125000D02*Y119000D01*
 X43700Y125000D02*X44750Y123950D01*
 Y120050D01*
 X43700Y119000D02*X44750Y120050D01*
 X41000Y119000D02*X43700D01*
 X41000Y125000D02*X43700D01*
-G54D18*G36*
+G54D20*G36*
 X46550D02*Y119000D01*
 X51050D01*
 Y125000D01*
@@ -154,10 +154,10 @@ X75350D01*
 Y125000D01*
 X70850D01*
 G37*
-G54D17*X76250D02*X77750D01*
+G54D19*X76250D02*X77750D01*
 X77000D02*Y119000D01*
 X76250D02*X77750D01*
-G54D18*G36*
+G54D20*G36*
 X79550Y125000D02*Y119000D01*
 X84050D01*
 Y125000D01*
@@ -181,13 +181,13 @@ X100250D01*
 Y125000D01*
 X95750D01*
 G37*
-G54D17*X41000Y118000D02*X52550D01*
+G54D19*X41000Y118000D02*X52550D01*
 X96050Y119000D02*X98000D01*
 X95000Y120050D02*X96050Y119000D01*
 X95000Y123950D02*Y120050D01*
 Y123950D02*X96050Y125000D01*
 X98000D01*
-G54D18*G36*
+G54D20*G36*
 X99800D02*Y119000D01*
 X104300D01*
 Y125000D01*
@@ -211,14 +211,14 @@ X120500D01*
 Y125000D01*
 X116000D01*
 G37*
-G54D17*X95000Y118000D02*X99800D01*
+G54D19*X95000Y118000D02*X99800D01*
 X130750Y125000D02*Y119000D01*
 X130000Y125000D02*X133000D01*
 X133750Y124250D01*
 Y122750D01*
 X133000Y122000D02*X133750Y122750D01*
 X130750Y122000D02*X133000D01*
-G54D18*G36*
+G54D20*G36*
 X135550Y125000D02*Y119000D01*
 X140050D01*
 Y125000D01*
@@ -254,10 +254,10 @@ X167050D01*
 Y125000D01*
 X162550D01*
 G37*
-G54D17*X130000Y118000D02*X135550D01*
+G54D19*X130000Y118000D02*X135550D01*
 X0Y140000D02*X3000D01*
 X1500D02*Y134000D01*
-G54D18*G36*
+G54D20*G36*
 X4800Y140000D02*Y134000D01*
 X9300D01*
 Y140000D01*
@@ -299,10 +299,10 @@ X44400D01*
 Y140000D01*
 X39900D01*
 G37*
-G54D17*X48000Y138800D02*X49200Y140000D01*
+G54D19*X48000Y138800D02*X49200Y140000D01*
 Y134000D01*
 X48000D02*X50250D01*
-G54D18*G36*
+G54D20*G36*
 X54750Y140000D02*Y134000D01*
 X59250D01*
 Y140000D01*
@@ -518,10 +518,10 @@ X264450D01*
 Y140000D01*
 X259950D01*
 G37*
-G54D17*X268050Y136250D02*X271050Y140000D01*
+G54D19*X268050Y136250D02*X271050Y140000D01*
 X268050Y136250D02*X271800D01*
 X271050Y140000D02*Y134000D01*
-G54D18*G36*
+G54D20*G36*
 X276300Y140000D02*Y134000D01*
 X280800D01*
 Y140000D01*
@@ -581,15 +581,15 @@ X332100D01*
 Y140000D01*
 X327600D01*
 G37*
-G54D19*X0Y50000D02*X50000D01*
+G54D21*X0Y50000D02*X50000D01*
 X0D02*Y0D01*
 X50000Y50000D02*Y0D01*
 X0D02*X50000D01*
-G54D17*X200000Y65000D02*Y59000D01*
+G54D19*X200000Y65000D02*Y59000D01*
 Y65000D02*X202250Y62000D01*
 X204500Y65000D01*
 Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X206300Y65000D02*Y59000D01*
 X210800D01*
 Y65000D01*
@@ -625,13 +625,13 @@ X237800D01*
 Y65000D01*
 X233300D01*
 G37*
-G54D17*X242150D02*Y59000D01*
+G54D19*X242150D02*Y59000D01*
 X244100Y65000D02*X245150Y63950D01*
 Y60050D01*
 X244100Y59000D02*X245150Y60050D01*
 X241400Y59000D02*X244100D01*
 X241400Y65000D02*X244100D01*
-G54D18*G36*
+G54D20*G36*
 X246950D02*Y59000D01*
 X251450D01*
 Y65000D01*
@@ -691,7 +691,7 @@ X300050D01*
 Y65000D01*
 X295550D01*
 G37*
-G54D17*X303650D02*X306650D01*
+G54D19*X303650D02*X306650D01*
 X303650D02*Y62000D01*
 X304400Y62750D01*
 X305900D01*
@@ -700,7 +700,7 @@ Y59750D01*
 X305900Y59000D02*X306650Y59750D01*
 X304400Y59000D02*X305900D01*
 X303650Y59750D02*X304400Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X308450Y65000D02*Y59000D01*
 X312950D01*
 Y65000D01*
@@ -808,7 +808,7 @@ X410150D01*
 Y65000D01*
 X405650D01*
 G37*
-G54D17*X413750D02*X416750D01*
+G54D19*X413750D02*X416750D01*
 X413750D02*Y62000D01*
 X414500Y62750D01*
 X416000D01*
@@ -817,7 +817,7 @@ Y59750D01*
 X416000Y59000D02*X416750Y59750D01*
 X414500Y59000D02*X416000D01*
 X413750Y59750D02*X414500Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X418550Y65000D02*Y59000D01*
 X423050D01*
 Y65000D01*
@@ -919,7 +919,7 @@ X514850D01*
 Y65000D01*
 X510350D01*
 G37*
-G54D17*X0Y-8000D02*X3000D01*
+G54D19*X0Y-8000D02*X3000D01*
 X3750Y-7250D01*
 Y-5450D02*Y-7250D01*
 X3000Y-4700D02*X3750Y-5450D01*
@@ -929,7 +929,7 @@ X0Y-2000D02*X3000D01*
 X3750Y-2750D01*
 Y-3950D01*
 X3000Y-4700D02*X3750Y-3950D01*
-G54D18*G36*
+G54D20*G36*
 X5550Y-2000D02*Y-8000D01*
 X10050D01*
 Y-2000D01*
@@ -1121,7 +1121,7 @@ X193650D01*
 Y-2000D01*
 X189150D01*
 G37*
-G54D17*X197250Y-7250D02*X198000Y-8000D01*
+G54D19*X197250Y-7250D02*X198000Y-8000D01*
 X197250Y-6050D02*Y-7250D01*
 Y-6050D02*X198300Y-5000D01*
 X199200D01*
@@ -1136,7 +1136,7 @@ X199500D01*
 X200250Y-2750D01*
 Y-3950D01*
 X199200Y-5000D02*X200250Y-3950D01*
-G54D18*G36*
+G54D20*G36*
 X202050Y-2000D02*Y-8000D01*
 X206550D01*
 Y-2000D01*
@@ -1286,7 +1286,7 @@ X349650D01*
 Y-2000D01*
 X345150D01*
 G37*
-G54D17*X353250D02*X356250D01*
+G54D19*X353250D02*X356250D01*
 X353250D02*Y-5000D01*
 X354000Y-4250D01*
 X355500D01*
@@ -1295,7 +1295,7 @@ Y-7250D01*
 X355500Y-8000D02*X356250Y-7250D01*
 X354000Y-8000D02*X355500D01*
 X353250Y-7250D02*X354000Y-8000D01*
-G54D18*G36*
+G54D20*G36*
 X358050Y-2000D02*Y-8000D01*
 X362550D01*
 Y-2000D01*
@@ -1355,7 +1355,7 @@ X411150D01*
 Y-2000D01*
 X406650D01*
 G37*
-G54D17*X412050D02*X415050D01*
+G54D19*X412050D02*X415050D01*
 X412050D02*Y-5000D01*
 X412800Y-4250D01*
 X414300D01*
@@ -1364,7 +1364,7 @@ Y-7250D01*
 X414300Y-8000D02*X415050Y-7250D01*
 X412800Y-8000D02*X414300D01*
 X412050Y-7250D02*X412800Y-8000D01*
-G54D18*G36*
+G54D20*G36*
 X416850Y-2000D02*Y-8000D01*
 X421350D01*
 Y-2000D01*
@@ -1442,13 +1442,13 @@ X488850D01*
 Y-2000D01*
 X484350D01*
 G37*
-G54D17*X200750Y80000D02*Y74000D01*
+G54D19*X200750Y80000D02*Y74000D01*
 X202700Y80000D02*X203750Y78950D01*
 Y75050D01*
 X202700Y74000D02*X203750Y75050D01*
 X200000Y74000D02*X202700D01*
 X200000Y80000D02*X202700D01*
-G54D18*G36*
+G54D20*G36*
 X205550D02*Y74000D01*
 X210050D01*
 Y80000D01*
@@ -1508,13 +1508,13 @@ X261350D01*
 Y80000D01*
 X256850D01*
 G37*
-G54D17*X200000Y93500D02*Y89000D01*
+G54D19*X200000Y93500D02*Y89000D01*
 Y93500D02*X201050Y95000D01*
 X202700D01*
 X203750Y93500D01*
 Y89000D01*
 X200000Y92000D02*X203750D01*
-G54D18*G36*
+G54D20*G36*
 X205550Y95000D02*Y89000D01*
 X210050D01*
 Y95000D01*
@@ -1550,9 +1550,9 @@ X237050D01*
 Y95000D01*
 X232550D01*
 G37*
-G54D17*X200000Y110000D02*X203000D01*
+G54D19*X200000Y110000D02*X203000D01*
 X201500D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X204800Y110000D02*Y104000D01*
 X209300D01*
 Y110000D01*
@@ -1726,10 +1726,10 @@ X374000D01*
 Y110000D01*
 X369500D01*
 G37*
-G54D17*X377600D02*Y104000D01*
+G54D19*X377600D02*Y104000D01*
 Y110000D02*X380600D01*
 X377600Y107300D02*X379850D01*
-G54D18*G36*
+G54D20*G36*
 X382400Y110000D02*Y104000D01*
 X386900D01*
 Y110000D01*
@@ -1789,13 +1789,13 @@ X435500D01*
 Y110000D01*
 X431000D01*
 G37*
-G54D17*X439850D02*Y104000D01*
+G54D19*X439850D02*Y104000D01*
 X441800Y110000D02*X442850Y108950D01*
 Y105050D01*
 X441800Y104000D02*X442850Y105050D01*
 X439100Y104000D02*X441800D01*
 X439100Y110000D02*X441800D01*
-G54D18*G36*
+G54D20*G36*
 X444650D02*Y104000D01*
 X449150D01*
 Y110000D01*
diff --git a/tests/RTT/ref/elem_pins.gbr/elem_pins.topmask.gbr b/tests/RTT/ref/elem_pins.gbr/elem_pins.topmask.gbr
index c7875e7..e3266dc 100644
--- a/tests/RTT/ref/elem_pins.gbr/elem_pins.topmask.gbr
+++ b/tests/RTT/ref/elem_pins.gbr/elem_pins.topmask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: pins with different shapes, TODO:group_name *
+G04 start of page 3 for group 2 layer_idx 0 *
+G04 Title: pins with different shapes, top mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_pins.nelma.em b/tests/RTT/ref/elem_pins.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/elem_pins.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/elem_pins.png b/tests/RTT/ref/elem_pins.png
index 67bb0a0..6fa2151 100644
Binary files a/tests/RTT/ref/elem_pins.png and b/tests/RTT/ref/elem_pins.png differ
diff --git a/tests/RTT/ref/elem_pins.png.text b/tests/RTT/ref/elem_pins.png.text
new file mode 100644
index 0000000..50b7d49
--- /dev/null
+++ b/tests/RTT/ref/elem_pins.png.text
@@ -0,0 +1,17 @@
+r6630
+
+U1
+6 x 6 pixel (5x5) distance from silk inside top corner to pin 1
+pin 1 dimensions 96 x 96 pixels (80x80)
+pin 2 97 pixel circle (80.808)
+pin 1 to pin 2 distance 264 pixels (303.333)
+pin 2 hole 47 pixels (39.167)
+
+U2
+pin 1 extremes 97 pixels (80.833) tall 145 wide (120.833)
+pin 2 extremes 145 pixels (120.833) tall 193 pixels (160.833) wide
+pin 1 to pin 2 distance 167 pixels (139.166)
+pin 1 to pin 2 vertical offset 0 pixels
+
+(mil)
+
diff --git a/tests/RTT/ref/elem_pins.ps.gz b/tests/RTT/ref/elem_pins.ps.gz
index 7d79429..463a751 100644
Binary files a/tests/RTT/ref/elem_pins.ps.gz and b/tests/RTT/ref/elem_pins.ps.gz differ
diff --git a/tests/RTT/ref/elem_pins.remote.gz b/tests/RTT/ref/elem_pins.remote.gz
index 68fa620..f4cb385 100644
Binary files a/tests/RTT/ref/elem_pins.remote.gz and b/tests/RTT/ref/elem_pins.remote.gz differ
diff --git a/tests/RTT/ref/elem_pins.scad b/tests/RTT/ref/elem_pins.scad
new file mode 100644
index 0000000..7a79f9e
--- /dev/null
+++ b/tests/RTT/ref/elem_pins.scad
@@ -0,0 +1,191 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: plated-drill
+layer_pdrill_list=[
+];
+
+
+// END_OF_LAYER layer_pdrill
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(2.540000,0.254000,0.037500,0.635000,-3.175000,90.000000,1,1,1);
+	line_segment_r(10.160000,0.254000,0.037500,5.715000,-4.445000,0.000000,1,1,1);
+	line_segment_r(2.540000,0.254000,0.037500,10.795000,-3.175000,-90.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,2.540000,-1.905000,180.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,8.890000,-1.905000,180.000000,1,1,1);
+	line_segment_r(0.110792,0.254000,0.037500,4.447417,-1.960343,92.499641,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,4.457064,-2.070610,97.500259,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.476285,-2.179616,102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.504933,-2.286532,107.499977,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,4.542790,-2.390545,112.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,4.589569,-2.490862,117.499908,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,4.644913,-2.586720,122.499672,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.708401,-2.677391,127.500198,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.779550,-2.762182,132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.857818,-2.840451,137.499817,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,4.942609,-2.911599,142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.033280,-2.975087,147.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.129138,-3.030431,152.500092,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.229455,-3.077209,157.499954,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.333467,-3.115067,162.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.440383,-3.143715,167.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.549390,-3.162936,172.499741,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.659657,-3.172583,177.500366,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.770343,-3.172583,-177.500366,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.880610,-3.162936,-172.499741,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.989616,-3.143715,-167.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.096532,-3.115067,-162.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.200545,-3.077209,-157.499954,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.300862,-3.030431,-152.500092,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.396720,-2.975087,-147.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.487391,-2.911599,-142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.572183,-2.840451,-137.499817,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.650451,-2.762182,-132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.721599,-2.677391,-127.499794,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.785087,-2.586721,-122.500381,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.840431,-2.490863,-117.499664,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.887209,-2.390545,-112.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.925067,-2.286532,-107.499825,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.953715,-2.179615,-102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.972936,-2.070610,-97.500320,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.982583,-1.960343,-92.499641,1,1,1);
+	line_segment_r(2.540000,0.254000,0.037500,0.635000,-8.255000,90.000000,1,1,1);
+	line_segment_r(10.160000,0.254000,0.037500,5.715000,-9.525000,0.000000,1,1,1);
+	line_segment_r(2.540000,0.254000,0.037500,10.795000,-8.255000,-90.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,2.540000,-6.985000,180.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,8.890000,-6.985000,180.000000,1,1,1);
+	line_segment_r(0.110792,0.254000,0.037500,4.447417,-7.040343,92.499641,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,4.457064,-7.150610,97.500259,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.476285,-7.259616,102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.504933,-7.366532,107.499977,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,4.542790,-7.470545,112.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,4.589569,-7.570862,117.499908,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,4.644913,-7.666720,122.499672,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.708401,-7.757391,127.500198,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.779550,-7.842183,132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,4.857818,-7.920451,137.499817,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,4.942609,-7.991600,142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.033280,-8.055087,147.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.129138,-8.110431,152.500092,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.229455,-8.157209,157.499954,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.333467,-8.195067,162.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.440383,-8.223715,167.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.549390,-8.242936,172.499741,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.659657,-8.252583,177.500366,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.770343,-8.252583,-177.500366,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.880610,-8.242936,-172.499741,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.989616,-8.223715,-167.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.096532,-8.195067,-162.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.200545,-8.157209,-157.499954,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.300862,-8.110431,-152.500092,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.396720,-8.055087,-147.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.487391,-7.991600,-142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.572183,-7.920451,-137.499817,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.650451,-7.842183,-132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.721599,-7.757391,-127.499794,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.785087,-7.666721,-122.500381,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.840431,-7.570862,-117.499664,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.887209,-7.470545,-112.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.925067,-7.366532,-107.499825,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.953715,-7.259615,-102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.972936,-7.150609,-97.500320,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.982583,-7.040343,-92.499641,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,1.905000,-1.079500,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,1.968500,-1.587500,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,2.159000,-1.651000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.349500,-1.587500,-135.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,2.413000,-1.079500,90.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,2.819401,-0.736600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,2.921001,-1.143000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,2.908301,-1.651000,180.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,1.905000,-6.159500,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,1.968500,-6.667500,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,2.159000,-6.731000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.349500,-6.667500,-135.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,2.413000,-6.159500,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.781301,-5.778500,-135.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,3.035301,-5.715000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,3.289301,-5.778500,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,3.352801,-5.969000,90.000000,1,1,1);
+	line_segment_r(0.898026,0.177800,0.037500,3.035301,-6.413500,-135.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,3.035301,-6.731000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/elem_pins.svg b/tests/RTT/ref/elem_pins.svg
index e64ec42..91842d3 100644
--- a/tests/RTT/ref/elem_pins.svg
+++ b/tests/RTT/ref/elem_pins.svg
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 <!--normal-->
  <rect x="0.8890" y="2.1590" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="9.5250" cy="3.1750" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -15,7 +15,7 @@
  <circle cx="1.9050" cy="8.2550" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="9.5250" cy="8.2550" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 <!--normal-->
  <rect x="0.8890" y="2.1590" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="9.5250" cy="3.1750" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -26,7 +26,7 @@
  <circle cx="1.9050" cy="8.2550" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="9.5250" cy="8.2550" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <rect x="0.8890" y="2.1590" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="9.5250" cy="3.1750" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -37,7 +37,7 @@
  <circle cx="1.9050" cy="8.2550" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="9.5250" cy="8.2550" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <rect x="0.8890" y="2.1590" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="9.5250" cy="3.1750" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -48,20 +48,20 @@
  <circle cx="1.9050" cy="8.2550" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="9.5250" cy="8.2550" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="0.6350" y1="1.9050" x2="0.6350" y2="4.4450" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="10.7950" y1="4.4450" x2="0.6350" y2="4.4450" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="10.7950" y1="4.4450" x2="10.7950" y2="1.9050" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="0.6350" y1="1.9050" x2="4.4450" y2="1.9050" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="6.9850" y1="1.9050" x2="10.7950" y2="1.9050" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
- <path d="M 4.4450 1.9050 A 1.2700 1.2700 0 0 0 6.9850 1.9050" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
+ <path d="M 6.98500000 1.90500000 A 1.2700 1.2700 0 0 1 4.4450 1.9050" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
  <line x1="0.6350" y1="6.9850" x2="0.6350" y2="9.5250" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="10.7950" y1="9.5250" x2="0.6350" y2="9.5250" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="10.7950" y1="9.5250" x2="10.7950" y2="6.9850" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="0.6350" y1="6.9850" x2="4.4450" y2="6.9850" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="6.9850" y1="6.9850" x2="10.7950" y2="6.9850" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
- <path d="M 4.4450 6.9850 A 1.2700 1.2700 0 0 0 6.9850 6.9850" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
+ <path d="M 6.98500000 6.98500000 A 1.2700 1.2700 0 0 1 4.4450 6.9850" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
  <line x1="1.9050" y1="0.6350" x2="1.9050" y2="1.5240" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="1.9050" y1="1.5240" x2="2.0320" y2="1.6510" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="2.0320" y1="1.6510" x2="2.2860" y2="1.6510" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
@@ -82,7 +82,7 @@
  <line x1="2.7178" y1="6.7310" x2="3.3528" y2="6.0960" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="2.7178" y1="6.7310" x2="3.3528" y2="6.7310" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
 </g>
-<g id="layer_-4048_plated-drill">
+<g id="layer_-1_plated-drill">
 <!--normal-->
  <circle cx="1.9050" cy="3.1750" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="9.5250" cy="3.1750" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
diff --git a/tests/RTT/ref/elem_sides_smd.bbrd.png b/tests/RTT/ref/elem_sides_smd.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/elem_sides_smd.bbrd.png differ
diff --git a/tests/RTT/ref/elem_sides_smd.dsn b/tests/RTT/ref/elem_sides_smd.dsn
index 1da78b0..3fe37fc 100644
--- a/tests/RTT/ref/elem_sides_smd.dsn
+++ b/tests/RTT/ref/elem_sides_smd.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,19 +33,19 @@
     )
   )
   (placement
-    (component 8
+    (component 9
       (place "R1" 5.715000 9.525000 front 0 (PN 0))
     )
-    (component 16
+    (component 17
       (place "R2" 5.715000 3.810000 back 0 (PN 0))
     )
   )
   (library
-    (image 8
+    (image 9
       (pin Smd_rect_1299972x1899920 "1" -1.499870 0.000000)
       (pin Smd_rect_1299972x1899920 "2" 1.499870 0.000000)
     )
-    (image 16
+    (image 17
       (pin Smd_rect_1299972x1899920 "1" 1.499870 0.000000)
       (pin Smd_rect_1299972x1899920 "2" -1.499870 0.000000)
     )
diff --git a/tests/RTT/ref/elem_sides_smd.eps b/tests/RTT/ref/elem_sides_smd.eps
new file mode 100644
index 0000000..f117132
--- /dev/null
+++ b/tests/RTT/ref/elem_sides_smd.eps
@@ -0,0 +1,55 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: elem_sides_smd.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.05118 setlinewidth
+2 setlinecap
+0.8 0.8 0.8 setrgbcolor
+0.16595 0.33819 0.16595 0.36181 t
+0.28405 0.33819 0.28405 0.36181 t
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.16595 0.11319 0.16595 0.13681 t
+0.28405 0.11319 0.28405 0.13681 t
+% Layer topsilk group 1 drill 0 mask 0
+0.00800 setlinewidth
+1 setlinecap
+0 0 0 setrgbcolor
+0.20138 0.08760 0.24862 0.08760 t
+0.20138 0.16240 0.24862 0.16240 t
+0.00700 setlinewidth
+0.34350 0.09350 0.36350 0.09350 t
+0.36350 0.09350 0.36850 0.09850 t
+0.36850 0.09850 0.36850 0.10850 t
+0.36350 0.11350 0.36850 0.10850 t
+0.34850 0.11350 0.36350 0.11350 t
+0.34850 0.09350 0.34850 0.13350 t
+0.35650 0.11350 0.36850 0.13350 t
+0.38050 0.10150 0.38850 0.09350 t
+0.38850 0.09350 0.38850 0.13350 t
+0.38050 0.13350 0.39550 0.13350 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottom.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottom.gbr
index 7596fd9..72ca01e 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottom.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottom.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group 1 layer_idx 1 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 3 for group 10 layer_idx 1 *
+G04 Title: smd elements on both sides, bottom copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottommask.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottommask.gbr
index d4402a5..c5b733e 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottommask.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottommask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 5 for group 11 layer_idx 0 *
+G04 Title: smd elements on both sides, bottom mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottompaste.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottompaste.gbr
index 9aff108..8da1c04 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottompaste.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottompaste.gbr
@@ -1,5 +1,5 @@
-G04 start of page 9 for group -1 layer_idx -1 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 9 for group 13 layer_idx 0 *
+G04 Title: smd elements on both sides, bottom paste *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottomsilk.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottomsilk.gbr
index 969f973..5cf9191 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottomsilk.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.bottomsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 7 for group 1 layer_idx 7 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 7 for group 12 layer_idx 7 *
+G04 Title: smd elements on both sides, bottom silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.fab.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.fab.gbr
index 466cc68..b1edc5e 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.fab.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 10 for group -1 layer_idx -1 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 10 for group -1 layer_idx 16777221 *
+G04 Title: smd elements on both sides, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.top.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.top.gbr
index 7e0d2c0..3410aa4 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.top.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: smd elements on both sides, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.topmask.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.topmask.gbr
index 0a9d0aa..4a868e2 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.topmask.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.topmask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group -1 layer_idx -1 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 4 for group 2 layer_idx 0 *
+G04 Title: smd elements on both sides, top mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.toppaste.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.toppaste.gbr
index ec06272..a13cff5 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.toppaste.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.toppaste.gbr
@@ -1,5 +1,5 @@
-G04 start of page 8 for group -1 layer_idx -1 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 8 for group 0 layer_idx 0 *
+G04 Title: smd elements on both sides, top paste *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.topsilk.gbr b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.topsilk.gbr
index 79f4234..5d7da8a 100644
--- a/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.topsilk.gbr
+++ b/tests/RTT/ref/elem_sides_smd.gbr/elem_sides_smd.topsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 6 for group 0 layer_idx 8 *
-G04 Title: smd elements on both sides, TODO:group_name *
+G04 start of page 6 for group 1 layer_idx 8 *
+G04 Title: smd elements on both sides, top silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_smd.nelma.em b/tests/RTT/ref/elem_sides_smd.nelma.em
new file mode 100644
index 0000000..40f7fea
--- /dev/null
+++ b/tests/RTT/ref/elem_sides_smd.nelma.em
@@ -0,0 +1,75 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+layer substrate-11 {
+	height = 20
+	z-order = 11
+	material = "composite"
+}
+layer bottom {
+	height = 1
+	z-order = 12
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top",
+		"substrate-11",
+		"bottom"
+	}
+}
diff --git a/tests/RTT/ref/elem_sides_smd.png b/tests/RTT/ref/elem_sides_smd.png
index debde9b..84b0374 100644
Binary files a/tests/RTT/ref/elem_sides_smd.png and b/tests/RTT/ref/elem_sides_smd.png differ
diff --git a/tests/RTT/ref/elem_sides_smd.png.text b/tests/RTT/ref/elem_sides_smd.png.text
new file mode 100644
index 0000000..ddf06b7
--- /dev/null
+++ b/tests/RTT/ref/elem_sides_smd.png.text
@@ -0,0 +1,10 @@
+R1
+pad1 61 x 89 pixels (50.833x74.167)
+pad2 61 x 89 pixels
+pad1 to pad2 81 pixels (67.5)
+
+R2 - on the bottom
+pad1 61 x 89 pixels 
+pad2 61 x 89 pixels
+
+(mils)
diff --git a/tests/RTT/ref/elem_sides_smd.ps.gz b/tests/RTT/ref/elem_sides_smd.ps.gz
index 61883ca..7d74320 100644
Binary files a/tests/RTT/ref/elem_sides_smd.ps.gz and b/tests/RTT/ref/elem_sides_smd.ps.gz differ
diff --git a/tests/RTT/ref/elem_sides_smd.remote.gz b/tests/RTT/ref/elem_sides_smd.remote.gz
index 64f0aaa..7160dc9 100644
Binary files a/tests/RTT/ref/elem_sides_smd.remote.gz and b/tests/RTT/ref/elem_sides_smd.remote.gz differ
diff --git a/tests/RTT/ref/elem_sides_smd.scad b/tests/RTT/ref/elem_sides_smd.scad
new file mode 100644
index 0000000..43ed8fc
--- /dev/null
+++ b/tests/RTT/ref/elem_sides_smd.scad
@@ -0,0 +1,110 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(1.199896,0.203200,0.037500,5.715000,-2.225040,180.000000,1,1,1);
+	line_segment_r(1.199896,0.203200,0.037500,5.715000,-4.124960,180.000000,1,1,1);
+	line_segment_r(0.508000,0.177800,0.037500,8.978900,-2.374900,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,9.296400,-2.438400,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,9.359900,-2.628900,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,9.296400,-2.819400,-135.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,9.042400,-2.882900,180.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,8.851900,-2.882900,90.000000,1,1,1);
+	line_segment_r(0.592425,0.177800,0.037500,9.207500,-3.136900,120.963753,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,9.766301,-2.476500,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,9.867901,-2.882900,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,9.855201,-3.390900,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(1.199896,0.203200,0.037500,5.715000,-9.839960,180.000000,1,1,1);
+	line_segment_r(1.199896,0.203200,0.037500,5.715000,-7.940040,180.000000,1,1,1);
+	line_segment_r(0.508000,0.177800,0.037500,8.978900,-9.690100,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,9.296400,-9.626600,-135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,9.359900,-9.436100,-90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,9.296400,-9.245600,135.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,9.042400,-9.182100,180.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,8.851900,-9.182100,-90.000000,1,1,1);
+	line_segment_r(0.592425,0.177800,0.037500,9.207500,-8.928100,-120.963753,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,9.728201,-9.626600,135.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,9.982201,-9.690100,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,10.236201,-9.626600,-135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,10.299701,-9.436100,-90.000000,1,1,1);
+	line_segment_r(0.898026,0.177800,0.037500,9.982201,-8.991600,135.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,9.982201,-8.674100,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/elem_sides_smd.svg b/tests/RTT/ref/elem_sides_smd.svg
index c0779dd..fa8ef0c 100644
--- a/tests/RTT/ref/elem_sides_smd.svg
+++ b/tests/RTT/ref/elem_sides_smd.svg
@@ -1,24 +1,24 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <line x1="4.2151" y1="8.5900" x2="4.2151" y2="9.1900" stroke-width="1.3000" stroke="#cccccc" stroke-linecap="square"/>
  <line x1="7.2149" y1="8.5900" x2="7.2149" y2="9.1900" stroke-width="1.3000" stroke="#cccccc" stroke-linecap="square"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="4.2151" y1="2.8750" x2="4.2151" y2="3.4750" stroke-width="1.3000" stroke="#4d4d4d" stroke-linecap="square"/>
  <line x1="7.2149" y1="2.8750" x2="7.2149" y2="3.4750" stroke-width="1.3000" stroke="#4d4d4d" stroke-linecap="square"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="5.1151" y1="2.2250" x2="6.3149" y2="2.2250" stroke-width="0.2032" stroke="#000000" stroke-linecap="round"/>
  <line x1="5.1151" y1="4.1250" x2="6.3149" y2="4.1250" stroke-width="0.2032" stroke="#000000" stroke-linecap="round"/>
diff --git a/tests/RTT/ref/elem_sides_trh.bbrd.png b/tests/RTT/ref/elem_sides_trh.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/elem_sides_trh.bbrd.png differ
diff --git a/tests/RTT/ref/elem_sides_trh.dsn b/tests/RTT/ref/elem_sides_trh.dsn
index 2cc921f..fff9175 100644
--- a/tests/RTT/ref/elem_sides_trh.dsn
+++ b/tests/RTT/ref/elem_sides_trh.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,19 +33,19 @@
     )
   )
   (placement
-    (component 8
+    (component 9
       (place "U1" 6.350000 8.890000 front 0 (PN 0))
     )
-    (component 20
+    (component 21
       (place "U2" 6.350000 3.810000 back 0 (PN 0))
     )
   )
   (library
-    (image 8
+    (image 9
       (pin Th_square_2032000 "1" -3.810000 0.000000)
       (pin Th_round_2032000 "2" 3.810000 0.000000)
     )
-    (image 20
+    (image 21
       (pin Th_square_2032000 "1" 3.810000 0.000000)
       (pin Th_round_2032000 "2" -3.810000 0.000000)
     )
diff --git a/tests/RTT/ref/elem_sides_trh.eps b/tests/RTT/ref/elem_sides_trh.eps
new file mode 100644
index 0000000..3a4f233
--- /dev/null
+++ b/tests/RTT/ref/elem_sides_trh.eps
@@ -0,0 +1,95 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: elem_sides_trh.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.11000 0.14000 0.19000 r
+0.40000 0.15000 0.04000 c
+0.06000 0.31000 0.14000 0.39000 r
+0.40000 0.35000 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.15000 0.01968 c
+0.40000 0.15000 0.01968 c
+0.10000 0.35000 0.01968 c
+0.40000 0.35000 0.01968 c
+% Layer group5 group 5 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.11000 0.14000 0.19000 r
+0.40000 0.15000 0.04000 c
+0.06000 0.31000 0.14000 0.39000 r
+0.40000 0.35000 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.15000 0.01968 c
+0.40000 0.15000 0.01968 c
+0.10000 0.35000 0.01968 c
+0.40000 0.35000 0.01968 c
+% Layer group7 group 7 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.11000 0.14000 0.19000 r
+0.40000 0.15000 0.04000 c
+0.06000 0.31000 0.14000 0.39000 r
+0.40000 0.35000 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.15000 0.01968 c
+0.40000 0.15000 0.01968 c
+0.10000 0.35000 0.01968 c
+0.40000 0.35000 0.01968 c
+% Layer top group 3 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.11000 0.14000 0.19000 r
+0.40000 0.15000 0.04000 c
+0.06000 0.31000 0.14000 0.39000 r
+0.40000 0.35000 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.15000 0.01968 c
+0.40000 0.15000 0.01968 c
+0.10000 0.35000 0.01968 c
+0.40000 0.35000 0.01968 c
+% Layer plated-drill group -1 drill 1 mask 0
+0.10000 0.15000 0.01968 c
+0.40000 0.15000 0.01968 c
+0.10000 0.35000 0.01968 c
+0.40000 0.35000 0.01968 c
+% Layer topsilk group 1 drill 0 mask 0
+0.01000 setlinewidth
+0 0 0 setrgbcolor
+0.05000 0.10000 0.05000 0.20000 t
+0.45000 0.20000 0.05000 0.20000 t
+0.45000 0.20000 0.45000 0.10000 t
+0.05000 0.10000 0.20000 0.10000 t
+0.30000 0.10000 0.45000 0.10000 t
+0 180 -0.05000 0.05000 0.25000 0.10000 0.2 a
+0.00700 setlinewidth
+0.10000 0.05000 0.10000 0.08500 t
+0.10000 0.08500 0.10500 0.09000 t
+0.10500 0.09000 0.11500 0.09000 t
+0.11500 0.09000 0.12000 0.08500 t
+0.12000 0.05000 0.12000 0.08500 t
+0.13200 0.05800 0.14000 0.05000 t
+0.14000 0.05000 0.14000 0.09000 t
+0.13200 0.09000 0.14700 0.09000 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.bottommask.gbr b/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.bottommask.gbr
index ed00a46..7dada1f 100644
--- a/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.bottommask.gbr
+++ b/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.bottommask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group -1 layer_idx -1 *
-G04 Title: thru-hole elements on both sides, TODO:group_name *
+G04 start of page 4 for group 11 layer_idx 0 *
+G04 Title: thru-hole elements on both sides, bottom mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.fab.gbr b/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.fab.gbr
index 1fdc3b9..1f6d5cf 100644
--- a/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.fab.gbr
+++ b/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: thru-hole elements on both sides, TODO:group_name *
+G04 start of page 7 for group -1 layer_idx 16777221 *
+G04 Title: thru-hole elements on both sides, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,11 +9,11 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNFAB*%
-%ADD19C,0.0100*%
-%ADD18C,0.0001*%
-%ADD17C,0.0060*%
-%ADD16C,0.0080*%
-G54D16*X10000Y35000D02*Y33400D01*
+%ADD23C,0.0100*%
+%ADD22C,0.0001*%
+%ADD21C,0.0060*%
+%ADD20C,0.0080*%
+G54D20*X10000Y35000D02*Y33400D01*
 Y35000D02*X11387Y35800D01*
 X10000Y35000D02*X8613Y35800D01*
 X40000Y35000D02*Y33400D01*
@@ -28,7 +28,7 @@ X40000Y15000D02*X38613Y15800D01*
 X15000Y106250D02*Y104650D01*
 Y106250D02*X16387Y107050D01*
 X15000Y106250D02*X13613Y107050D01*
-G54D17*X135000Y110000D02*X136500Y107000D01*
+G54D21*X135000Y110000D02*X136500Y107000D01*
 X138000Y110000D01*
 X136500Y107000D02*Y104000D01*
 X139800Y107300D02*X142050D01*
@@ -49,7 +49,7 @@ X144600Y104750D02*X145350Y104000D01*
 X98000Y106250D02*X101000Y110000D01*
 X98000Y106250D02*X101750D01*
 X101000Y110000D02*Y104000D01*
-G54D18*G36*
+G54D22*G36*
 X45000Y110000D02*Y104000D01*
 X49500D01*
 Y110000D01*
@@ -67,16 +67,16 @@ X60300D01*
 Y110000D01*
 X55800D01*
 G37*
-G54D17*X61200Y106250D02*X64200Y110000D01*
+G54D21*X61200Y106250D02*X64200Y110000D01*
 X61200Y106250D02*X64950D01*
 X64200Y110000D02*Y104000D01*
-G54D18*G36*
+G54D22*G36*
 X66750Y110000D02*Y104000D01*
 X71250D01*
 Y110000D01*
 X66750D01*
 G37*
-G54D17*X3000Y125000D02*X3750Y124250D01*
+G54D21*X3000Y125000D02*X3750Y124250D01*
 X750Y125000D02*X3000D01*
 X0Y124250D02*X750Y125000D01*
 X0Y124250D02*Y122750D01*
@@ -87,7 +87,7 @@ Y119750D01*
 X3000Y119000D02*X3750Y119750D01*
 X750Y119000D02*X3000D01*
 X0Y119750D02*X750Y119000D01*
-G54D18*G36*
+G54D22*G36*
 X5550Y125000D02*Y119000D01*
 X10050D01*
 Y125000D01*
@@ -117,14 +117,14 @@ X31650D01*
 Y125000D01*
 X27150D01*
 G37*
-G54D17*X0Y118000D02*X5550D01*
+G54D21*X0Y118000D02*X5550D01*
 X41750Y125000D02*Y119000D01*
 X43700Y125000D02*X44750Y123950D01*
 Y120050D01*
 X43700Y119000D02*X44750Y120050D01*
 X41000Y119000D02*X43700D01*
 X41000Y125000D02*X43700D01*
-G54D18*G36*
+G54D22*G36*
 X46550D02*Y119000D01*
 X51050D01*
 Y125000D01*
@@ -154,10 +154,10 @@ X75350D01*
 Y125000D01*
 X70850D01*
 G37*
-G54D17*X76250D02*X77750D01*
+G54D21*X76250D02*X77750D01*
 X77000D02*Y119000D01*
 X76250D02*X77750D01*
-G54D18*G36*
+G54D22*G36*
 X79550Y125000D02*Y119000D01*
 X84050D01*
 Y125000D01*
@@ -181,13 +181,13 @@ X100250D01*
 Y125000D01*
 X95750D01*
 G37*
-G54D17*X41000Y118000D02*X52550D01*
+G54D21*X41000Y118000D02*X52550D01*
 X96050Y119000D02*X98000D01*
 X95000Y120050D02*X96050Y119000D01*
 X95000Y123950D02*Y120050D01*
 Y123950D02*X96050Y125000D01*
 X98000D01*
-G54D18*G36*
+G54D22*G36*
 X99800D02*Y119000D01*
 X104300D01*
 Y125000D01*
@@ -211,14 +211,14 @@ X120500D01*
 Y125000D01*
 X116000D01*
 G37*
-G54D17*X95000Y118000D02*X99800D01*
+G54D21*X95000Y118000D02*X99800D01*
 X130750Y125000D02*Y119000D01*
 X130000Y125000D02*X133000D01*
 X133750Y124250D01*
 Y122750D01*
 X133000Y122000D02*X133750Y122750D01*
 X130750Y122000D02*X133000D01*
-G54D18*G36*
+G54D22*G36*
 X135550Y125000D02*Y119000D01*
 X140050D01*
 Y125000D01*
@@ -254,10 +254,10 @@ X167050D01*
 Y125000D01*
 X162550D01*
 G37*
-G54D17*X130000Y118000D02*X135550D01*
+G54D21*X130000Y118000D02*X135550D01*
 X0Y140000D02*X3000D01*
 X1500D02*Y134000D01*
-G54D18*G36*
+G54D22*G36*
 X4800Y140000D02*Y134000D01*
 X9300D01*
 Y140000D01*
@@ -299,10 +299,10 @@ X44400D01*
 Y140000D01*
 X39900D01*
 G37*
-G54D17*X48000Y138800D02*X49200Y140000D01*
+G54D21*X48000Y138800D02*X49200Y140000D01*
 Y134000D01*
 X48000D02*X50250D01*
-G54D18*G36*
+G54D22*G36*
 X54750Y140000D02*Y134000D01*
 X59250D01*
 Y140000D01*
@@ -518,10 +518,10 @@ X264450D01*
 Y140000D01*
 X259950D01*
 G37*
-G54D17*X268050Y136250D02*X271050Y140000D01*
+G54D21*X268050Y136250D02*X271050Y140000D01*
 X268050Y136250D02*X271800D01*
 X271050Y140000D02*Y134000D01*
-G54D18*G36*
+G54D22*G36*
 X276300Y140000D02*Y134000D01*
 X280800D01*
 Y140000D01*
@@ -581,15 +581,15 @@ X332100D01*
 Y140000D01*
 X327600D01*
 G37*
-G54D19*X0Y50000D02*X50000D01*
+G54D23*X0Y50000D02*X50000D01*
 X0D02*Y0D01*
 X50000Y50000D02*Y0D01*
 X0D02*X50000D01*
-G54D17*X200000Y65000D02*Y59000D01*
+G54D21*X200000Y65000D02*Y59000D01*
 Y65000D02*X202250Y62000D01*
 X204500Y65000D01*
 Y59000D01*
-G54D18*G36*
+G54D22*G36*
 X206300Y65000D02*Y59000D01*
 X210800D01*
 Y65000D01*
@@ -625,13 +625,13 @@ X237800D01*
 Y65000D01*
 X233300D01*
 G37*
-G54D17*X242150D02*Y59000D01*
+G54D21*X242150D02*Y59000D01*
 X244100Y65000D02*X245150Y63950D01*
 Y60050D01*
 X244100Y59000D02*X245150Y60050D01*
 X241400Y59000D02*X244100D01*
 X241400Y65000D02*X244100D01*
-G54D18*G36*
+G54D22*G36*
 X246950D02*Y59000D01*
 X251450D01*
 Y65000D01*
@@ -691,7 +691,7 @@ X300050D01*
 Y65000D01*
 X295550D01*
 G37*
-G54D17*X303650D02*X306650D01*
+G54D21*X303650D02*X306650D01*
 X303650D02*Y62000D01*
 X304400Y62750D01*
 X305900D01*
@@ -700,7 +700,7 @@ Y59750D01*
 X305900Y59000D02*X306650Y59750D01*
 X304400Y59000D02*X305900D01*
 X303650Y59750D02*X304400Y59000D01*
-G54D18*G36*
+G54D22*G36*
 X308450Y65000D02*Y59000D01*
 X312950D01*
 Y65000D01*
@@ -808,7 +808,7 @@ X410150D01*
 Y65000D01*
 X405650D01*
 G37*
-G54D17*X413750D02*X416750D01*
+G54D21*X413750D02*X416750D01*
 X413750D02*Y62000D01*
 X414500Y62750D01*
 X416000D01*
@@ -817,7 +817,7 @@ Y59750D01*
 X416000Y59000D02*X416750Y59750D01*
 X414500Y59000D02*X416000D01*
 X413750Y59750D02*X414500Y59000D01*
-G54D18*G36*
+G54D22*G36*
 X418550Y65000D02*Y59000D01*
 X423050D01*
 Y65000D01*
@@ -919,7 +919,7 @@ X514850D01*
 Y65000D01*
 X510350D01*
 G37*
-G54D17*X0Y-8000D02*X3000D01*
+G54D21*X0Y-8000D02*X3000D01*
 X3750Y-7250D01*
 Y-5450D02*Y-7250D01*
 X3000Y-4700D02*X3750Y-5450D01*
@@ -929,7 +929,7 @@ X0Y-2000D02*X3000D01*
 X3750Y-2750D01*
 Y-3950D01*
 X3000Y-4700D02*X3750Y-3950D01*
-G54D18*G36*
+G54D22*G36*
 X5550Y-2000D02*Y-8000D01*
 X10050D01*
 Y-2000D01*
@@ -1121,7 +1121,7 @@ X193650D01*
 Y-2000D01*
 X189150D01*
 G37*
-G54D17*X197250Y-7250D02*X198000Y-8000D01*
+G54D21*X197250Y-7250D02*X198000Y-8000D01*
 X197250Y-6050D02*Y-7250D01*
 Y-6050D02*X198300Y-5000D01*
 X199200D01*
@@ -1136,7 +1136,7 @@ X199500D01*
 X200250Y-2750D01*
 Y-3950D01*
 X199200Y-5000D02*X200250Y-3950D01*
-G54D18*G36*
+G54D22*G36*
 X202050Y-2000D02*Y-8000D01*
 X206550D01*
 Y-2000D01*
@@ -1286,7 +1286,7 @@ X349650D01*
 Y-2000D01*
 X345150D01*
 G37*
-G54D17*X353250D02*X356250D01*
+G54D21*X353250D02*X356250D01*
 X353250D02*Y-5000D01*
 X354000Y-4250D01*
 X355500D01*
@@ -1295,7 +1295,7 @@ Y-7250D01*
 X355500Y-8000D02*X356250Y-7250D01*
 X354000Y-8000D02*X355500D01*
 X353250Y-7250D02*X354000Y-8000D01*
-G54D18*G36*
+G54D22*G36*
 X358050Y-2000D02*Y-8000D01*
 X362550D01*
 Y-2000D01*
@@ -1355,7 +1355,7 @@ X411150D01*
 Y-2000D01*
 X406650D01*
 G37*
-G54D17*X412050D02*X415050D01*
+G54D21*X412050D02*X415050D01*
 X412050D02*Y-5000D01*
 X412800Y-4250D01*
 X414300D01*
@@ -1364,7 +1364,7 @@ Y-7250D01*
 X414300Y-8000D02*X415050Y-7250D01*
 X412800Y-8000D02*X414300D01*
 X412050Y-7250D02*X412800Y-8000D01*
-G54D18*G36*
+G54D22*G36*
 X416850Y-2000D02*Y-8000D01*
 X421350D01*
 Y-2000D01*
@@ -1442,13 +1442,13 @@ X488850D01*
 Y-2000D01*
 X484350D01*
 G37*
-G54D17*X200750Y80000D02*Y74000D01*
+G54D21*X200750Y80000D02*Y74000D01*
 X202700Y80000D02*X203750Y78950D01*
 Y75050D01*
 X202700Y74000D02*X203750Y75050D01*
 X200000Y74000D02*X202700D01*
 X200000Y80000D02*X202700D01*
-G54D18*G36*
+G54D22*G36*
 X205550D02*Y74000D01*
 X210050D01*
 Y80000D01*
@@ -1508,13 +1508,13 @@ X261350D01*
 Y80000D01*
 X256850D01*
 G37*
-G54D17*X200000Y93500D02*Y89000D01*
+G54D21*X200000Y93500D02*Y89000D01*
 Y93500D02*X201050Y95000D01*
 X202700D01*
 X203750Y93500D01*
 Y89000D01*
 X200000Y92000D02*X203750D01*
-G54D18*G36*
+G54D22*G36*
 X205550Y95000D02*Y89000D01*
 X210050D01*
 Y95000D01*
@@ -1550,9 +1550,9 @@ X237050D01*
 Y95000D01*
 X232550D01*
 G37*
-G54D17*X200000Y110000D02*X203000D01*
+G54D21*X200000Y110000D02*X203000D01*
 X201500D02*Y104000D01*
-G54D18*G36*
+G54D22*G36*
 X204800Y110000D02*Y104000D01*
 X209300D01*
 Y110000D01*
@@ -1756,10 +1756,10 @@ X403700D01*
 Y110000D01*
 X399200D01*
 G37*
-G54D17*X407300D02*Y104000D01*
+G54D21*X407300D02*Y104000D01*
 Y110000D02*X410300D01*
 X407300Y107300D02*X409550D01*
-G54D18*G36*
+G54D22*G36*
 X412100Y110000D02*Y104000D01*
 X416600D01*
 Y110000D01*
@@ -1819,13 +1819,13 @@ X465200D01*
 Y110000D01*
 X460700D01*
 G37*
-G54D17*X469550D02*Y104000D01*
+G54D21*X469550D02*Y104000D01*
 X471500Y110000D02*X472550Y108950D01*
 Y105050D01*
 X471500Y104000D02*X472550Y105050D01*
 X468800Y104000D02*X471500D01*
 X468800Y110000D02*X471500D01*
-G54D18*G36*
+G54D22*G36*
 X474350D02*Y104000D01*
 X478850D01*
 Y110000D01*
diff --git a/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.topmask.gbr b/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.topmask.gbr
index fa84f32..b476de1 100644
--- a/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.topmask.gbr
+++ b/tests/RTT/ref/elem_sides_trh.gbr/elem_sides_trh.topmask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: thru-hole elements on both sides, TODO:group_name *
+G04 start of page 3 for group 2 layer_idx 0 *
+G04 Title: thru-hole elements on both sides, top mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/elem_sides_trh.nelma.em b/tests/RTT/ref/elem_sides_trh.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/elem_sides_trh.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/elem_sides_trh.png b/tests/RTT/ref/elem_sides_trh.png
index 0e87c23..76b57a1 100644
Binary files a/tests/RTT/ref/elem_sides_trh.png and b/tests/RTT/ref/elem_sides_trh.png differ
diff --git a/tests/RTT/ref/elem_sides_trh.png.text b/tests/RTT/ref/elem_sides_trh.png.text
new file mode 100644
index 0000000..d6275a1
--- /dev/null
+++ b/tests/RTT/ref/elem_sides_trh.png.text
@@ -0,0 +1,17 @@
+r6630
+
+U1
+6 x 6 pixel (5x5) distance from silk inside top corner to pin 1
+pin 1 dimensions 96 x 96 pixels (80x80)
+pin 2 97 pixel diameter circle (80.833)
+pin 1 to pin 2 distance 264 pixels (220)
+
+U2
+pin 1 is 144 pixels (120) down from U1 Pin 1
+pin 1 is 96 x 96 pixels (80x80)
+pin 2 is an 97 pixel circle (80.833)
+pin 1 to pin 2 distance 264 pixels (220)
+
+
+(mil)
+
diff --git a/tests/RTT/ref/elem_sides_trh.ps.gz b/tests/RTT/ref/elem_sides_trh.ps.gz
index 0ff4742..f62c001 100644
Binary files a/tests/RTT/ref/elem_sides_trh.ps.gz and b/tests/RTT/ref/elem_sides_trh.ps.gz differ
diff --git a/tests/RTT/ref/elem_sides_trh.remote.gz b/tests/RTT/ref/elem_sides_trh.remote.gz
index bb465aa..78a3044 100644
Binary files a/tests/RTT/ref/elem_sides_trh.remote.gz and b/tests/RTT/ref/elem_sides_trh.remote.gz differ
diff --git a/tests/RTT/ref/elem_sides_trh.scad b/tests/RTT/ref/elem_sides_trh.scad
new file mode 100644
index 0000000..8480a75
--- /dev/null
+++ b/tests/RTT/ref/elem_sides_trh.scad
@@ -0,0 +1,191 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: plated-drill
+layer_pdrill_list=[
+];
+
+
+// END_OF_LAYER layer_pdrill
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(2.540000,0.254000,0.037500,1.270000,-3.810000,90.000000,1,1,1);
+	line_segment_r(10.160000,0.254000,0.037500,6.350000,-5.080000,0.000000,1,1,1);
+	line_segment_r(2.540000,0.254000,0.037500,11.430000,-3.810000,-90.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,3.175000,-2.540000,180.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,9.525000,-2.540000,180.000000,1,1,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.082417,-2.595344,92.499641,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.092064,-2.705610,97.500259,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.111285,-2.814616,102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.139933,-2.921532,107.499977,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.177791,-3.025545,112.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.224569,-3.125862,117.499908,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.279912,-3.221720,122.499672,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.343400,-3.312391,127.500198,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.414549,-3.397182,132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.492817,-3.475451,137.499817,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.577610,-3.546599,142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.668280,-3.610087,147.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.764138,-3.665431,152.500092,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.864455,-3.712209,157.499954,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.968468,-3.750067,162.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.075384,-3.778715,167.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.184390,-3.797936,172.499741,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.294656,-3.807583,177.500366,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.405344,-3.807583,-177.500366,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.515610,-3.797936,-172.499741,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.624617,-3.778715,-167.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.731533,-3.750067,-162.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.835545,-3.712209,-157.499954,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.935862,-3.665431,-152.500092,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.031720,-3.610087,-147.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.122390,-3.546599,-142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.207182,-3.475451,-137.499817,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.285450,-3.397182,-132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.356599,-3.312391,-127.499794,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.420087,-3.221721,-122.500381,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.475431,-3.125863,-117.499664,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.522210,-3.025545,-112.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.560067,-2.921532,-107.499825,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.588715,-2.814615,-102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.607936,-2.705610,-97.500320,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,7.617583,-2.595344,-92.499641,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,2.540000,-1.714500,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.603500,-2.222500,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,2.794000,-2.286000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.984500,-2.222500,-135.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,3.048000,-1.714500,90.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,3.454401,-1.371600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,3.556001,-1.778000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,3.543301,-2.286000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(2.540000,0.254000,0.037500,1.270000,-8.890000,-90.000000,1,1,1);
+	line_segment_r(10.160000,0.254000,0.037500,6.350000,-7.620000,0.000000,1,1,1);
+	line_segment_r(2.540000,0.254000,0.037500,11.430000,-8.890000,90.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,3.175000,-10.160000,180.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,9.525000,-10.160000,180.000000,1,1,1);
+	line_segment_r(0.110792,0.254000,0.037500,7.617583,-10.104656,-87.500359,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.607936,-9.994390,-82.499741,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.588715,-9.885384,-77.500023,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.560067,-9.778468,-72.500023,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.522210,-9.674455,-67.499954,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.475431,-9.574138,-62.500332,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.420087,-9.478279,-57.500053,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.356599,-9.387609,-52.499798,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.285450,-9.302818,-47.499813,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.207182,-9.224550,-42.500187,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.122391,-9.153400,-37.500202,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.031721,-9.089912,-32.499947,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.935863,-9.034569,-27.499666,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.835545,-8.987790,-22.500048,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.731533,-8.949933,-17.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.624617,-8.921285,-12.499976,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.515610,-8.902064,-7.500256,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.405344,-8.892417,-2.499639,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.294656,-8.892417,2.499639,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.184390,-8.902064,7.500256,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.075384,-8.921285,12.500089,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.968468,-8.949933,17.499821,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.864456,-8.987790,22.499767,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.764138,-9.034568,27.499886,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.668280,-9.089912,32.500225,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.577610,-9.153400,37.499886,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.492817,-9.224550,42.500187,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.414549,-9.302818,47.499813,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.343401,-9.387609,52.500210,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.279913,-9.478280,57.499893,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.224569,-9.574138,62.500095,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.177791,-9.674455,67.499954,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.139933,-9.778468,72.500023,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.111285,-9.885384,77.500023,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.092064,-9.994390,82.499680,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.082417,-10.104656,87.500381,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,2.540000,-10.985500,-90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.603500,-10.477500,-135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,2.794000,-10.414000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.984500,-10.477500,135.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,3.048000,-10.985500,-90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,3.416301,-11.366500,135.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,3.670301,-11.430000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,3.924301,-11.366500,-135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,3.987801,-11.176000,-90.000000,1,1,1);
+	line_segment_r(0.898026,0.177800,0.037500,3.670301,-10.731500,135.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,3.670301,-10.414000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/elem_sides_trh.svg b/tests/RTT/ref/elem_sides_trh.svg
index 5d0a9eb..f57219c 100644
--- a/tests/RTT/ref/elem_sides_trh.svg
+++ b/tests/RTT/ref/elem_sides_trh.svg
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 <!--normal-->
  <rect x="1.5240" y="2.7940" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="3.8100" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -15,7 +15,7 @@
  <circle cx="2.5400" cy="8.8900" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="8.8900" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 <!--normal-->
  <rect x="1.5240" y="2.7940" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="3.8100" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -26,7 +26,7 @@
  <circle cx="2.5400" cy="8.8900" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="8.8900" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <rect x="1.5240" y="2.7940" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="3.8100" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -37,7 +37,7 @@
  <circle cx="2.5400" cy="8.8900" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="8.8900" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <rect x="1.5240" y="2.7940" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="3.8100" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -48,14 +48,14 @@
  <circle cx="2.5400" cy="8.8900" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="8.8900" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="1.2700" y1="2.5400" x2="1.2700" y2="5.0800" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="11.4300" y1="5.0800" x2="1.2700" y2="5.0800" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="11.4300" y1="5.0800" x2="11.4300" y2="2.5400" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="1.2700" y1="2.5400" x2="5.0800" y2="2.5400" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="7.6200" y1="2.5400" x2="11.4300" y2="2.5400" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
- <path d="M 5.0800 2.5400 A 1.2700 1.2700 0 0 0 7.6200 2.5400" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
+ <path d="M 7.62000000 2.54000000 A 1.2700 1.2700 0 0 1 5.0800 2.5400" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
  <line x1="2.5400" y1="1.2700" x2="2.5400" y2="2.1590" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="2.5400" y1="2.1590" x2="2.6670" y2="2.2860" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="2.6670" y1="2.2860" x2="2.9210" y2="2.2860" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
@@ -65,7 +65,7 @@
  <line x1="3.5560" y1="1.2700" x2="3.5560" y2="2.2860" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="3.3528" y1="2.2860" x2="3.7338" y2="2.2860" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
 </g>
-<g id="layer_-4048_plated-drill">
+<g id="layer_-1_plated-drill">
 <!--normal-->
  <circle cx="2.5400" cy="3.8100" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="3.8100" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
diff --git a/tests/RTT/ref/layer_copper.bbrd.png b/tests/RTT/ref/layer_copper.bbrd.png
new file mode 100644
index 0000000..dc12b63
Binary files /dev/null and b/tests/RTT/ref/layer_copper.bbrd.png differ
diff --git a/tests/RTT/ref/layer_copper.dsn b/tests/RTT/ref/layer_copper.dsn
index 3e2a87d..d42cad2 100644
--- a/tests/RTT/ref/layer_copper.dsn
+++ b/tests/RTT/ref/layer_copper.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/layer_copper.eps b/tests/RTT/ref/layer_copper.eps
new file mode 100644
index 0000000..63b040a
--- /dev/null
+++ b/tests/RTT/ref/layer_copper.eps
@@ -0,0 +1,39 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: layer_copper.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0.227451 0.372549 0.803922 setrgbcolor
+0.07500 0.07500 0.40000 0.07500 t
+% Layer group5 group 5 drill 0 mask 0
+0.329412 0.545098 0.329412 setrgbcolor
+0.10000 0.15000 0.32500 0.37500 t
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.545098 0.137255 0.137255 setrgbcolor
+0.05000 0.07500 0.05000 0.35000 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/layer_copper.gbr/layer_copper.bottom.gbr b/tests/RTT/ref/layer_copper.gbr/layer_copper.bottom.gbr
index 532e494..c6b6ef2 100644
--- a/tests/RTT/ref/layer_copper.gbr/layer_copper.bottom.gbr
+++ b/tests/RTT/ref/layer_copper.gbr/layer_copper.bottom.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group 1 layer_idx 1 *
-G04 Title: one line per each type of copper layer, TODO:group_name *
+G04 start of page 4 for group 10 layer_idx 1 *
+G04 Title: one line per each type of copper layer, bottom copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,6 +9,6 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNBOTTOM*%
-%ADD12C,0.0100*%
-G54D12*X7500Y42500D02*X40000D01*
+%ADD13C,0.0100*%
+G54D13*X7500Y42500D02*X40000D01*
 M02*
diff --git a/tests/RTT/ref/layer_copper.gbr/layer_copper.fab.gbr b/tests/RTT/ref/layer_copper.gbr/layer_copper.fab.gbr
index f3767f3..1bb4bd8 100644
--- a/tests/RTT/ref/layer_copper.gbr/layer_copper.fab.gbr
+++ b/tests/RTT/ref/layer_copper.gbr/layer_copper.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: one line per each type of copper layer, TODO:group_name *
+G04 start of page 5 for group -1 layer_idx 16777221 *
+G04 Title: one line per each type of copper layer, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/layer_copper.gbr/layer_copper.group2.gbr b/tests/RTT/ref/layer_copper.gbr/layer_copper.group2.gbr
deleted file mode 100644
index 3a94227..0000000
--- a/tests/RTT/ref/layer_copper.gbr/layer_copper.group2.gbr
+++ /dev/null
@@ -1,14 +0,0 @@
-G04 start of page 4 for group 2 layer_idx 4 *
-G04 Title: one line per each type of copper layer, TODO:group_name *
-G04 Creator: <version>
-G04 CreationDate: <date>
-G04 For:  *
-G04 Format: Gerber/RS-274X *
-G04 PCB-Dimensions: 50000 50000 *
-G04 PCB-Coordinate-Origin: lower left *
-%MOIN*%
-%FSLAX25Y25*%
-%LNGROUP2*%
-%ADD13C,0.0100*%
-G54D13*X10000Y35000D02*X32500Y12500D01*
-M02*
diff --git a/tests/RTT/ref/layer_copper.gbr/layer_copper.group5.gbr b/tests/RTT/ref/layer_copper.gbr/layer_copper.group5.gbr
new file mode 100644
index 0000000..502abc3
--- /dev/null
+++ b/tests/RTT/ref/layer_copper.gbr/layer_copper.group5.gbr
@@ -0,0 +1,14 @@
+G04 start of page 3 for group 5 layer_idx 4 *
+G04 Title: one line per each type of copper layer, Intern *
+G04 Creator: <version>
+G04 CreationDate: <date>
+G04 For:  *
+G04 Format: Gerber/RS-274X *
+G04 PCB-Dimensions: 50000 50000 *
+G04 PCB-Coordinate-Origin: lower left *
+%MOIN*%
+%FSLAX25Y25*%
+%LNGROUP5*%
+%ADD12C,0.0100*%
+G54D12*X10000Y35000D02*X32500Y12500D01*
+M02*
diff --git a/tests/RTT/ref/layer_copper.gbr/layer_copper.top.gbr b/tests/RTT/ref/layer_copper.gbr/layer_copper.top.gbr
index 24a17ac..80cd655 100644
--- a/tests/RTT/ref/layer_copper.gbr/layer_copper.top.gbr
+++ b/tests/RTT/ref/layer_copper.gbr/layer_copper.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: one line per each type of copper layer, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: one line per each type of copper layer, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/layer_copper.nelma.em b/tests/RTT/ref/layer_copper.nelma.em
new file mode 100644
index 0000000..c342e79
--- /dev/null
+++ b/tests/RTT/ref/layer_copper.nelma.em
@@ -0,0 +1,90 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+layer substrate-11 {
+	height = 20
+	z-order = 11
+	material = "composite"
+}
+layer group-1 {
+	height = 1
+	z-order = 12
+	material = "air"
+	objects = {
+
+	}
+}
+layer substrate-13 {
+	height = 20
+	z-order = 13
+	material = "composite"
+}
+layer bottom {
+	height = 1
+	z-order = 14
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top",
+		"substrate-11",
+		"group-1",
+		"substrate-13",
+		"bottom"
+	}
+}
diff --git a/tests/RTT/ref/layer_copper.png b/tests/RTT/ref/layer_copper.png
index 9e8ce3d..105f249 100644
Binary files a/tests/RTT/ref/layer_copper.png and b/tests/RTT/ref/layer_copper.png differ
diff --git a/tests/RTT/ref/layer_copper.png.text b/tests/RTT/ref/layer_copper.png.text
new file mode 100644
index 0000000..787f399
--- /dev/null
+++ b/tests/RTT/ref/layer_copper.png.text
@@ -0,0 +1,11 @@
+r6630
+
+3 lines each on a different layer
+
+highest point on red to highest point on green
+60 x 90 pixels (50x75)
+
+highest point on red to "nose" (left side) of blue
+24 x 6 pixels (20x5)
+
+(mils)
diff --git a/tests/RTT/ref/layer_copper.ps.gz b/tests/RTT/ref/layer_copper.ps.gz
index 9e03ad5..40eb14b 100644
Binary files a/tests/RTT/ref/layer_copper.ps.gz and b/tests/RTT/ref/layer_copper.ps.gz differ
diff --git a/tests/RTT/ref/layer_copper.remote.gz b/tests/RTT/ref/layer_copper.remote.gz
index 6d625a4..024fdb6 100644
Binary files a/tests/RTT/ref/layer_copper.remote.gz and b/tests/RTT/ref/layer_copper.remote.gz differ
diff --git a/tests/RTT/ref/layer_copper.scad b/tests/RTT/ref/layer_copper.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/layer_copper.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/layer_copper.svg b/tests/RTT/ref/layer_copper.svg
index 9218cfd..f8c1260 100644
--- a/tests/RTT/ref/layer_copper.svg
+++ b/tests/RTT/ref/layer_copper.svg
@@ -1,23 +1,23 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 <!--normal-->
  <line x1="2.5400" y1="3.8100" x2="8.2550" y2="9.5250" stroke-width="0.2540" stroke="#548b54" stroke-linecap="round"/>
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <line x1="1.9050" y1="1.9050" x2="10.1600" y2="1.9050" stroke-width="0.2540" stroke="#3a5fcd" stroke-linecap="round"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="1.2700" y1="1.9050" x2="1.2700" y2="8.8900" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/layer_outline.bbrd.png b/tests/RTT/ref/layer_outline.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/layer_outline.bbrd.png differ
diff --git a/tests/RTT/ref/layer_outline.dsn b/tests/RTT/ref/layer_outline.dsn
index 0c90e12..119f467 100644
--- a/tests/RTT/ref/layer_outline.dsn
+++ b/tests/RTT/ref/layer_outline.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/layer_outline.eps b/tests/RTT/ref/layer_outline.eps
new file mode 100644
index 0000000..657fb64
--- /dev/null
+++ b/tests/RTT/ref/layer_outline.eps
@@ -0,0 +1,38 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: layer_outline.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer outline group 9 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0 0.52549 0.545098 setrgbcolor
+0.07500 0.10000 0.07500 0.40000 t
+0.07500 0.40000 0.37500 0.40000 t
+0.37500 0.40000 0.07500 0.10000 t
+% Layer top group 3 drill 0 mask 0
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/layer_outline.gbr/layer_outline.fab.gbr b/tests/RTT/ref/layer_outline.gbr/layer_outline.fab.gbr
index 296ba7b..4534f01 100644
--- a/tests/RTT/ref/layer_outline.gbr/layer_outline.fab.gbr
+++ b/tests/RTT/ref/layer_outline.gbr/layer_outline.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: outline layer triangle, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: outline layer triangle, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/layer_outline.gbr/layer_outline.outline.gbr b/tests/RTT/ref/layer_outline.gbr/layer_outline.outline.gbr
index a62866e..8f61387 100644
--- a/tests/RTT/ref/layer_outline.gbr/layer_outline.outline.gbr
+++ b/tests/RTT/ref/layer_outline.gbr/layer_outline.outline.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 4 layer_idx 6 *
-G04 Title: outline layer triangle, TODO:group_name *
+G04 start of page 2 for group 9 layer_idx 6 *
+G04 Title: outline layer triangle, global outline *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/layer_outline.nelma.em b/tests/RTT/ref/layer_outline.nelma.em
new file mode 100644
index 0000000..80b38a4
--- /dev/null
+++ b/tests/RTT/ref/layer_outline.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer outline {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"outline"
+	}
+}
diff --git a/tests/RTT/ref/layer_outline.png b/tests/RTT/ref/layer_outline.png
index ada51ac..f7e87d4 100644
Binary files a/tests/RTT/ref/layer_outline.png and b/tests/RTT/ref/layer_outline.png differ
diff --git a/tests/RTT/ref/layer_outline.png.text b/tests/RTT/ref/layer_outline.png.text
new file mode 100644
index 0000000..7946157
--- /dev/null
+++ b/tests/RTT/ref/layer_outline.png.text
@@ -0,0 +1,6 @@
+triangle
+base 372 x h 372 (pixels) (310 x 310 mil) measured to the outside of the line
+line thickness is 12  pixels (10mils)
+
+so the actual triangle dimensions are 300 x 300 mil
+
diff --git a/tests/RTT/ref/layer_outline.ps.gz b/tests/RTT/ref/layer_outline.ps.gz
index 43767d5..6281e98 100644
Binary files a/tests/RTT/ref/layer_outline.ps.gz and b/tests/RTT/ref/layer_outline.ps.gz differ
diff --git a/tests/RTT/ref/layer_outline.remote.gz b/tests/RTT/ref/layer_outline.remote.gz
index 2859abc..cade714 100644
Binary files a/tests/RTT/ref/layer_outline.remote.gz and b/tests/RTT/ref/layer_outline.remote.gz differ
diff --git a/tests/RTT/ref/layer_outline.scad b/tests/RTT/ref/layer_outline.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/layer_outline.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/layer_outline.svg b/tests/RTT/ref/layer_outline.svg
index dfe913a..1d27dd3 100644
--- a/tests/RTT/ref/layer_outline.svg
+++ b/tests/RTT/ref/layer_outline.svg
@@ -1,19 +1,19 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <line x1="1.9050" y1="2.5400" x2="1.9050" y2="10.1600" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round"/>
  <line x1="1.9050" y1="10.1600" x2="9.5250" y2="10.1600" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round"/>
  <line x1="9.5250" y1="10.1600" x2="1.9050" y2="2.5400" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/layer_silk.bbrd.png b/tests/RTT/ref/layer_silk.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/layer_silk.bbrd.png differ
diff --git a/tests/RTT/ref/layer_silk.dsn b/tests/RTT/ref/layer_silk.dsn
index f65c09a..4023f18 100644
--- a/tests/RTT/ref/layer_silk.dsn
+++ b/tests/RTT/ref/layer_silk.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/layer_silk.eps b/tests/RTT/ref/layer_silk.eps
new file mode 100644
index 0000000..4a6d395
--- /dev/null
+++ b/tests/RTT/ref/layer_silk.eps
@@ -0,0 +1,35 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: layer_silk.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+% Layer topsilk group 1 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0 0 0 setrgbcolor
+0.05000 0.05000 0.05000 0.42500 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/layer_silk.gbr/layer_silk.bottomsilk.gbr b/tests/RTT/ref/layer_silk.gbr/layer_silk.bottomsilk.gbr
index 6c3a509..3d62a75 100644
--- a/tests/RTT/ref/layer_silk.gbr/layer_silk.bottomsilk.gbr
+++ b/tests/RTT/ref/layer_silk.gbr/layer_silk.bottomsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group 1 layer_idx 7 *
-G04 Title: one line on each silk layer, TODO:group_name *
+G04 start of page 3 for group 12 layer_idx 7 *
+G04 Title: one line on each silk layer, bottom silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/layer_silk.gbr/layer_silk.fab.gbr b/tests/RTT/ref/layer_silk.gbr/layer_silk.fab.gbr
index 8ca3956..eec97fc 100644
--- a/tests/RTT/ref/layer_silk.gbr/layer_silk.fab.gbr
+++ b/tests/RTT/ref/layer_silk.gbr/layer_silk.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group -1 layer_idx -1 *
-G04 Title: one line on each silk layer, TODO:group_name *
+G04 start of page 4 for group -1 layer_idx 16777221 *
+G04 Title: one line on each silk layer, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/layer_silk.gbr/layer_silk.topsilk.gbr b/tests/RTT/ref/layer_silk.gbr/layer_silk.topsilk.gbr
index 3acfda2..dc2afa1 100644
--- a/tests/RTT/ref/layer_silk.gbr/layer_silk.topsilk.gbr
+++ b/tests/RTT/ref/layer_silk.gbr/layer_silk.topsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 8 *
-G04 Title: one line on each silk layer, TODO:group_name *
+G04 start of page 2 for group 1 layer_idx 8 *
+G04 Title: one line on each silk layer, top silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/layer_silk.nelma.em b/tests/RTT/ref/layer_silk.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/layer_silk.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/layer_silk.png b/tests/RTT/ref/layer_silk.png
index df4d309..9022fd2 100644
Binary files a/tests/RTT/ref/layer_silk.png and b/tests/RTT/ref/layer_silk.png differ
diff --git a/tests/RTT/ref/layer_silk.png.text b/tests/RTT/ref/layer_silk.png.text
index a15e370..2a6d79e 100644
--- a/tests/RTT/ref/layer_silk.png.text
+++ b/tests/RTT/ref/layer_silk.png.text
@@ -1,6 +1,8 @@
-
+r6630
 
 line
-width 12 pixels
-length 462 pixels
+width 12 pixels (10)
+length 462 pixels (385)
+
+(mil)
 
diff --git a/tests/RTT/ref/layer_silk.ps.gz b/tests/RTT/ref/layer_silk.ps.gz
index 48b2816..b16bed5 100644
Binary files a/tests/RTT/ref/layer_silk.ps.gz and b/tests/RTT/ref/layer_silk.ps.gz differ
diff --git a/tests/RTT/ref/layer_silk.remote.gz b/tests/RTT/ref/layer_silk.remote.gz
index d0d188d..69e557a 100644
Binary files a/tests/RTT/ref/layer_silk.remote.gz and b/tests/RTT/ref/layer_silk.remote.gz differ
diff --git a/tests/RTT/ref/layer_silk.scad b/tests/RTT/ref/layer_silk.scad
new file mode 100644
index 0000000..7738dd4
--- /dev/null
+++ b/tests/RTT/ref/layer_silk.scad
@@ -0,0 +1,85 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(9.525000,0.254000,0.037500,1.270000,-6.032500,90.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(8.082231,0.254000,0.037500,4.762500,-7.937500,-135.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/layer_silk.svg b/tests/RTT/ref/layer_silk.svg
index 496f815..7f324d8 100644
--- a/tests/RTT/ref/layer_silk.svg
+++ b/tests/RTT/ref/layer_silk.svg
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="1.2700" y1="1.2700" x2="1.2700" y2="10.7950" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
 </g>
diff --git a/tests/RTT/ref/layer_spc.bbrd.png b/tests/RTT/ref/layer_spc.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/layer_spc.bbrd.png differ
diff --git a/tests/RTT/ref/layer_spc.eps b/tests/RTT/ref/layer_spc.eps
new file mode 100644
index 0000000..2ce9c19
--- /dev/null
+++ b/tests/RTT/ref/layer_spc.eps
@@ -0,0 +1,32 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: layer_spc.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 11 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer group9 group 9 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 13 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/layer_spc.gbr/layer_spc.fab.gbr b/tests/RTT/ref/layer_spc.gbr/layer_spc.fab.gbr
index aa3ef01..61244e9 100644
--- a/tests/RTT/ref/layer_spc.gbr/layer_spc.fab.gbr
+++ b/tests/RTT/ref/layer_spc.gbr/layer_spc.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group -1 layer_idx -1 *
-G04 Title: space (and other dangerous characters) in layer name, TODO:group_name *
+G04 start of page 2 for group -1 layer_idx 16777221 *
+G04 Title: space (and other dangerous characters) in layer name, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/layer_spc.nelma.em b/tests/RTT/ref/layer_spc.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/layer_spc.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/layer_spc.png b/tests/RTT/ref/layer_spc.png
index 852eb60..1813f8c 100644
Binary files a/tests/RTT/ref/layer_spc.png and b/tests/RTT/ref/layer_spc.png differ
diff --git a/tests/RTT/ref/layer_spc.png.text b/tests/RTT/ref/layer_spc.png.text
new file mode 100644
index 0000000..305b1fb
--- /dev/null
+++ b/tests/RTT/ref/layer_spc.png.text
@@ -0,0 +1,4 @@
+empty page 600 x 600 pixels (500 x 500)
+
+(mil)
+
diff --git a/tests/RTT/ref/layer_spc.ps.gz b/tests/RTT/ref/layer_spc.ps.gz
index 7c66117..e05468b 100644
Binary files a/tests/RTT/ref/layer_spc.ps.gz and b/tests/RTT/ref/layer_spc.ps.gz differ
diff --git a/tests/RTT/ref/layer_spc.remote.gz b/tests/RTT/ref/layer_spc.remote.gz
index 6764471..b18c979 100644
Binary files a/tests/RTT/ref/layer_spc.remote.gz and b/tests/RTT/ref/layer_spc.remote.gz differ
diff --git a/tests/RTT/ref/layer_spc.scad b/tests/RTT/ref/layer_spc.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/layer_spc.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/layer_spc.svg b/tests/RTT/ref/layer_spc.svg
index 1e3d86f..8916303 100644
--- a/tests/RTT/ref/layer_spc.svg
+++ b/tests/RTT/ref/layer_spc.svg
@@ -1,15 +1,15 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_group9">
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_11_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/line_f_clear.bbrd.png b/tests/RTT/ref/line_f_clear.bbrd.png
new file mode 100644
index 0000000..857cb57
Binary files /dev/null and b/tests/RTT/ref/line_f_clear.bbrd.png differ
diff --git a/tests/RTT/ref/line_f_clear.dsn b/tests/RTT/ref/line_f_clear.dsn
index 8f426d9..42dfab2 100644
--- a/tests/RTT/ref/line_f_clear.dsn
+++ b/tests/RTT/ref/line_f_clear.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/line_f_clear.eps b/tests/RTT/ref/line_f_clear.eps
new file mode 100644
index 0000000..9557261
--- /dev/null
+++ b/tests/RTT/ref/line_f_clear.eps
@@ -0,0 +1,144 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: line_f_clear.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.26250 0.02500 moveto
+0.47500 0.02500 lineto
+0.47500 0.47500 lineto
+0.26250 0.47500 lineto
+0.26250 0.42033 lineto
+0.26457 0.41984 lineto
+0.27140 0.41701 lineto
+0.27771 0.41314 lineto
+0.28334 0.40834 lineto
+0.28814 0.40271 lineto
+0.29201 0.39640 lineto
+0.29484 0.38957 lineto
+0.29656 0.38238 lineto
+0.29700 0.37500 lineto
+0.29700 0.26950 lineto
+0.40000 0.26950 lineto
+0.40306 0.26932 lineto
+0.40604 0.26860 lineto
+0.40888 0.26743 lineto
+0.41150 0.26582 lineto
+0.41383 0.26383 lineto
+0.41582 0.26150 lineto
+0.41743 0.25888 lineto
+0.41860 0.25604 lineto
+0.41932 0.25306 lineto
+0.41956 0.25000 lineto
+0.41932 0.24694 lineto
+0.41860 0.24396 lineto
+0.41743 0.24112 lineto
+0.41582 0.23850 lineto
+0.41383 0.23617 lineto
+0.41150 0.23418 lineto
+0.40888 0.23257 lineto
+0.40604 0.23140 lineto
+0.40306 0.23068 lineto
+0.40000 0.23050 lineto
+0.29700 0.23050 lineto
+0.29700 0.12500 lineto
+0.29656 0.11762 lineto
+0.29484 0.11043 lineto
+0.29201 0.10360 lineto
+0.28814 0.09729 lineto
+0.28334 0.09166 lineto
+0.27771 0.08686 lineto
+0.27140 0.08299 lineto
+0.26457 0.08016 lineto
+0.26250 0.07967 lineto
+fill
+0.02500 0.02500 moveto
+0.26250 0.02500 lineto
+0.26250 0.07967 lineto
+0.25738 0.07844 lineto
+0.25000 0.07786 lineto
+0.24262 0.07844 lineto
+0.23543 0.08016 lineto
+0.22860 0.08299 lineto
+0.22229 0.08686 lineto
+0.21666 0.09166 lineto
+0.21186 0.09729 lineto
+0.20799 0.10360 lineto
+0.20516 0.11043 lineto
+0.20344 0.11762 lineto
+0.20300 0.12500 lineto
+0.20300 0.23050 lineto
+0.12500 0.23050 lineto
+0.12194 0.23068 lineto
+0.11896 0.23140 lineto
+0.11612 0.23257 lineto
+0.11350 0.23418 lineto
+0.11117 0.23617 lineto
+0.10918 0.23850 lineto
+0.10757 0.24112 lineto
+0.10640 0.24396 lineto
+0.10568 0.24694 lineto
+0.10544 0.25000 lineto
+0.10568 0.25306 lineto
+0.10640 0.25604 lineto
+0.10757 0.25888 lineto
+0.10918 0.26150 lineto
+0.11117 0.26383 lineto
+0.11350 0.26582 lineto
+0.11612 0.26743 lineto
+0.11896 0.26860 lineto
+0.12194 0.26932 lineto
+0.12500 0.26950 lineto
+0.20300 0.26950 lineto
+0.20300 0.37500 lineto
+0.20344 0.38238 lineto
+0.20516 0.38957 lineto
+0.20799 0.39640 lineto
+0.21186 0.40271 lineto
+0.21666 0.40834 lineto
+0.22229 0.41314 lineto
+0.22860 0.41701 lineto
+0.23543 0.41984 lineto
+0.24262 0.42156 lineto
+0.25000 0.42214 lineto
+0.25738 0.42156 lineto
+0.26250 0.42033 lineto
+0.26250 0.47500 lineto
+0.02500 0.47500 lineto
+fill
+0.01500 setlinewidth
+0.12500 0.25000 0.40000 0.25000 t
+0.01000 setlinewidth
+0.25000 0.12500 0.25000 0.37500 t
+0.02000 setlinewidth
+0.25000 0.25000 0.40000 0.20000 t
+0.00500 setlinewidth
+0.25000 0.25000 0.15000 0.15000 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/line_f_clear.gbr/line_f_clear.fab.gbr b/tests/RTT/ref/line_f_clear.gbr/line_f_clear.fab.gbr
index d946f35..1b812a0 100644
--- a/tests/RTT/ref/line_f_clear.gbr/line_f_clear.fab.gbr
+++ b/tests/RTT/ref/line_f_clear.gbr/line_f_clear.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Clear and no-clear lines, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Clear and no-clear lines, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_f_clear.gbr/line_f_clear.top.gbr b/tests/RTT/ref/line_f_clear.gbr/line_f_clear.top.gbr
index 9dfe4ae..92d4eed 100644
--- a/tests/RTT/ref/line_f_clear.gbr/line_f_clear.top.gbr
+++ b/tests/RTT/ref/line_f_clear.gbr/line_f_clear.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Clear and no-clear lines, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Clear and no-clear lines, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_f_clear.nelma.em b/tests/RTT/ref/line_f_clear.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/line_f_clear.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/line_f_clear.png b/tests/RTT/ref/line_f_clear.png
index 70da439..aded283 100644
Binary files a/tests/RTT/ref/line_f_clear.png and b/tests/RTT/ref/line_f_clear.png differ
diff --git a/tests/RTT/ref/line_f_clear.png.text b/tests/RTT/ref/line_f_clear.png.text
index 1eaf269..dfed526 100644
--- a/tests/RTT/ref/line_f_clear.png.text
+++ b/tests/RTT/ref/line_f_clear.png.text
@@ -1,18 +1,18 @@
-
+r6630
 
 rectangle
-width 541 pixels
-height 541 pixels
+width 541 pixels (450.833)
+height 541 pixels (450.833)
 
 veritcal line
-width 12 pixels
-length 312 pixels
-clearance 49/51 pixels (left/right)
+width 12 pixels (10)
+length 312 pixels (260)
+clearance 49/50 pixels (left/right) (40.833/41.667)
 
 horizontal line
-width 348 pixels
-length 348 pixels
-clearance 14/15 pixels (top/bottom)
+width 18 pixels (15)
+length 348 pixels (290)
+clearance 14/14 pixels (top/bottom) (11.666/12.5)
 
 left diangonal line
 45 degrees
@@ -20,4 +20,5 @@ left diangonal line
 right diagonal line
 18 degrees
 
+(mil)
 
diff --git a/tests/RTT/ref/line_f_clear.ps.gz b/tests/RTT/ref/line_f_clear.ps.gz
index a6456de..9621d03 100644
Binary files a/tests/RTT/ref/line_f_clear.ps.gz and b/tests/RTT/ref/line_f_clear.ps.gz differ
diff --git a/tests/RTT/ref/line_f_clear.remote.gz b/tests/RTT/ref/line_f_clear.remote.gz
index 97ab8e9..f4b5676 100644
Binary files a/tests/RTT/ref/line_f_clear.remote.gz and b/tests/RTT/ref/line_f_clear.remote.gz differ
diff --git a/tests/RTT/ref/line_f_clear.scad b/tests/RTT/ref/line_f_clear.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/line_f_clear.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/line_f_clear.svg b/tests/RTT/ref/line_f_clear.svg
index 1275afa..965562b 100644
--- a/tests/RTT/ref/line_f_clear.svg
+++ b/tests/RTT/ref/line_f_clear.svg
@@ -1,16 +1,16 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <polygon points="6.6675,0.6350 12.0650,0.6350 12.0650,12.0650 6.6675,12.0650 6.6675,10.6765 6.7200,10.6639 6.8936,10.5920 7.0539,10.4938 7.1967,10.3717 7.3188,10.2289 7.4170,10.0686 7.4889,9.8950 7.5327,9.7123 7.5438,9.5250 7.5438,6.8453 10.1600,6.8453 10.2377,6.8407 10.3135,6.8225 10.3856,6.7927 10.4520,6.7519 10.5113,6.7013 10.5619,6.6420 10.6027,6.5756 10.6325,6.5035 10.6507,6.4277 10.6568,6.3500 10.6507,6.2723 10.6325,6.1965 10.6027,6.1244 10.5619,6.0580 10.5113,5.9987 10.4520,5.948 [...]
  <polygon points="0.6350,0.6350 6.6675,0.6350 6.6675,2.0235 6.5373,1.9923 6.3500,1.9775 6.1627,1.9923 5.9800,2.0361 5.8064,2.1080 5.6461,2.2062 5.5033,2.3283 5.3812,2.4711 5.2830,2.6314 5.2111,2.8050 5.1673,2.9877 5.1562,3.1750 5.1562,5.8547 3.1750,5.8547 3.0973,5.8593 3.0215,5.8775 2.9494,5.9073 2.8830,5.9481 2.8237,5.9987 2.7731,6.0580 2.7323,6.1244 2.7025,6.1965 2.6843,6.2723 2.6782,6.3500 2.6843,6.4277 2.7025,6.5035 2.7323,6.5756 2.7731,6.6420 2.8237,6.7013 2.8830,6.7519 2.9494,6.792 [...]
@@ -19,6 +19,6 @@
  <line x1="6.3500" y1="6.3500" x2="10.1600" y2="5.0800" stroke-width="0.5080" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="6.3500" y1="6.3500" x2="3.8100" y2="3.8100" stroke-width="0.1270" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/line_normal.bbrd.png b/tests/RTT/ref/line_normal.bbrd.png
new file mode 100644
index 0000000..857cb57
Binary files /dev/null and b/tests/RTT/ref/line_normal.bbrd.png differ
diff --git a/tests/RTT/ref/line_normal.dsn b/tests/RTT/ref/line_normal.dsn
index b245c94..910e8c5 100644
--- a/tests/RTT/ref/line_normal.dsn
+++ b/tests/RTT/ref/line_normal.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/line_normal.eps b/tests/RTT/ref/line_normal.eps
new file mode 100644
index 0000000..5278671
--- /dev/null
+++ b/tests/RTT/ref/line_normal.eps
@@ -0,0 +1,41 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: line_normal.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01500 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.12500 0.25000 0.40000 0.25000 t
+0.01000 setlinewidth
+0.25000 0.12500 0.25000 0.37500 t
+0.02000 setlinewidth
+0.25000 0.25000 0.40000 0.20000 t
+0.00500 setlinewidth
+0.25000 0.25000 0.15000 0.15000 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/line_normal.gbr/line_normal.fab.gbr b/tests/RTT/ref/line_normal.gbr/line_normal.fab.gbr
index 7dd57c3..5187cbe 100644
--- a/tests/RTT/ref/line_normal.gbr/line_normal.fab.gbr
+++ b/tests/RTT/ref/line_normal.gbr/line_normal.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Normal lines at different size and angle, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Normal lines at different size and angle, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_normal.gbr/line_normal.top.gbr b/tests/RTT/ref/line_normal.gbr/line_normal.top.gbr
index 99e0bba..3be2afe 100644
--- a/tests/RTT/ref/line_normal.gbr/line_normal.top.gbr
+++ b/tests/RTT/ref/line_normal.gbr/line_normal.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Normal lines at different size and angle, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Normal lines at different size and angle, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_normal.nelma.em b/tests/RTT/ref/line_normal.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/line_normal.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/line_normal.png b/tests/RTT/ref/line_normal.png
index bf6905e..954c23b 100644
Binary files a/tests/RTT/ref/line_normal.png and b/tests/RTT/ref/line_normal.png differ
diff --git a/tests/RTT/ref/line_normal.png.text b/tests/RTT/ref/line_normal.png.text
new file mode 100644
index 0000000..0f97169
--- /dev/null
+++ b/tests/RTT/ref/line_normal.png.text
@@ -0,0 +1,13 @@
+horizontal line
+348 pixels (290)
+18 pixel thickness (15)
+
+vertical line
+312 pixels long (260)
+12 pixel thickness (10)
+
+fine diagonal line
+7.07 pixels (5.892)
+
+thick diagonal line
+unsure of readings
diff --git a/tests/RTT/ref/line_normal.ps.gz b/tests/RTT/ref/line_normal.ps.gz
index 929981b..19e3d9b 100644
Binary files a/tests/RTT/ref/line_normal.ps.gz and b/tests/RTT/ref/line_normal.ps.gz differ
diff --git a/tests/RTT/ref/line_normal.remote.gz b/tests/RTT/ref/line_normal.remote.gz
index 427c128..18e8fa0 100644
Binary files a/tests/RTT/ref/line_normal.remote.gz and b/tests/RTT/ref/line_normal.remote.gz differ
diff --git a/tests/RTT/ref/line_normal.scad b/tests/RTT/ref/line_normal.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/line_normal.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/line_normal.svg b/tests/RTT/ref/line_normal.svg
index 575ed1a..119514a 100644
--- a/tests/RTT/ref/line_normal.svg
+++ b/tests/RTT/ref/line_normal.svg
@@ -1,22 +1,22 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="3.1750" y1="6.3500" x2="10.1600" y2="6.3500" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="6.3500" y1="3.1750" x2="6.3500" y2="9.5250" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="6.3500" y1="6.3500" x2="10.1600" y2="5.0800" stroke-width="0.5080" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="6.3500" y1="6.3500" x2="3.8100" y2="3.8100" stroke-width="0.1270" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/line_offpage.bbrd.png b/tests/RTT/ref/line_offpage.bbrd.png
new file mode 100644
index 0000000..5faf8e1
Binary files /dev/null and b/tests/RTT/ref/line_offpage.bbrd.png differ
diff --git a/tests/RTT/ref/line_offpage.dsn b/tests/RTT/ref/line_offpage.dsn
index 2879e42..cd97686 100644
--- a/tests/RTT/ref/line_offpage.dsn
+++ b/tests/RTT/ref/line_offpage.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/line_offpage.eps b/tests/RTT/ref/line_offpage.eps
new file mode 100644
index 0000000..f64dbbe
--- /dev/null
+++ b/tests/RTT/ref/line_offpage.eps
@@ -0,0 +1,35 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: line_offpage.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.10000 0.20000 0.60000 0.20000 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/line_offpage.gbr/line_offpage.fab.gbr b/tests/RTT/ref/line_offpage.gbr/line_offpage.fab.gbr
index 57a29d2..285acb4 100644
--- a/tests/RTT/ref/line_offpage.gbr/line_offpage.fab.gbr
+++ b/tests/RTT/ref/line_offpage.gbr/line_offpage.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: A single line that extends beyond board boundary, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: A single line that extends beyond board boundary, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_offpage.gbr/line_offpage.top.gbr b/tests/RTT/ref/line_offpage.gbr/line_offpage.top.gbr
index 2bcc5cb..ccad58e 100644
--- a/tests/RTT/ref/line_offpage.gbr/line_offpage.top.gbr
+++ b/tests/RTT/ref/line_offpage.gbr/line_offpage.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: A single line that extends beyond board boundary, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: A single line that extends beyond board boundary, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_offpage.nelma.em b/tests/RTT/ref/line_offpage.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/line_offpage.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/line_offpage.png b/tests/RTT/ref/line_offpage.png
index 65bc1ec..f7c817e 100644
Binary files a/tests/RTT/ref/line_offpage.png and b/tests/RTT/ref/line_offpage.png differ
diff --git a/tests/RTT/ref/line_offpage.png.text b/tests/RTT/ref/line_offpage.png.text
new file mode 100644
index 0000000..2fc8355
--- /dev/null
+++ b/tests/RTT/ref/line_offpage.png.text
@@ -0,0 +1,5 @@
+12 pixel line (10)
+486 pixel [guessing middle of outline] on the page (more off) (405) (this is a pain to measure in gimp because of the edge issues)
+480 pixels if you remove the outline wall thickness (400)
+(mil)
+
diff --git a/tests/RTT/ref/line_offpage.ps.gz b/tests/RTT/ref/line_offpage.ps.gz
index 9175741..7f110d7 100644
Binary files a/tests/RTT/ref/line_offpage.ps.gz and b/tests/RTT/ref/line_offpage.ps.gz differ
diff --git a/tests/RTT/ref/line_offpage.remote.gz b/tests/RTT/ref/line_offpage.remote.gz
index da4143d..afb9fbf 100644
Binary files a/tests/RTT/ref/line_offpage.remote.gz and b/tests/RTT/ref/line_offpage.remote.gz differ
diff --git a/tests/RTT/ref/line_offpage.scad b/tests/RTT/ref/line_offpage.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/line_offpage.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/line_offpage.svg b/tests/RTT/ref/line_offpage.svg
index 08e947e..4e75105 100644
--- a/tests/RTT/ref/line_offpage.svg
+++ b/tests/RTT/ref/line_offpage.svg
@@ -1,19 +1,19 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="2.5400" y1="5.0800" x2="15.2400" y2="5.0800" stroke-width="0.2540" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/line_overlap1.bbrd.png b/tests/RTT/ref/line_overlap1.bbrd.png
new file mode 100644
index 0000000..33949b5
Binary files /dev/null and b/tests/RTT/ref/line_overlap1.bbrd.png differ
diff --git a/tests/RTT/ref/line_overlap1.dsn b/tests/RTT/ref/line_overlap1.dsn
index e4db8bf..a39d7da 100644
--- a/tests/RTT/ref/line_overlap1.dsn
+++ b/tests/RTT/ref/line_overlap1.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/line_overlap1.eps b/tests/RTT/ref/line_overlap1.eps
new file mode 100644
index 0000000..1edaf63
--- /dev/null
+++ b/tests/RTT/ref/line_overlap1.eps
@@ -0,0 +1,36 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: line_overlap1.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01500 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.20000 0.20000 0.25000 0.20000 t
+0.22000 0.20000 0.30000 0.20000 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/line_overlap1.gbr/line_overlap1.fab.gbr b/tests/RTT/ref/line_overlap1.gbr/line_overlap1.fab.gbr
index c70c567..d38359d 100644
--- a/tests/RTT/ref/line_overlap1.gbr/line_overlap1.fab.gbr
+++ b/tests/RTT/ref/line_overlap1.gbr/line_overlap1.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Two lines partially overlapping, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Two lines partially overlapping, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_overlap1.gbr/line_overlap1.top.gbr b/tests/RTT/ref/line_overlap1.gbr/line_overlap1.top.gbr
index e53e028..f7a6852 100644
--- a/tests/RTT/ref/line_overlap1.gbr/line_overlap1.top.gbr
+++ b/tests/RTT/ref/line_overlap1.gbr/line_overlap1.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Two lines partially overlapping, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Two lines partially overlapping, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_overlap1.nelma.em b/tests/RTT/ref/line_overlap1.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/line_overlap1.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/line_overlap1.png b/tests/RTT/ref/line_overlap1.png
index b44c55a..db6f5f5 100644
Binary files a/tests/RTT/ref/line_overlap1.png and b/tests/RTT/ref/line_overlap1.png differ
diff --git a/tests/RTT/ref/line_overlap1.png.text b/tests/RTT/ref/line_overlap1.png.text
new file mode 100644
index 0000000..c436a87
--- /dev/null
+++ b/tests/RTT/ref/line_overlap1.png.text
@@ -0,0 +1,8 @@
+r6630
+
+18 pixel width (15)
+138 pixel length (115)
+
+(it is actually 2 traces that should export as 1)
+
+(mil)
diff --git a/tests/RTT/ref/line_overlap1.ps.gz b/tests/RTT/ref/line_overlap1.ps.gz
index 8500433..5e51cfa 100644
Binary files a/tests/RTT/ref/line_overlap1.ps.gz and b/tests/RTT/ref/line_overlap1.ps.gz differ
diff --git a/tests/RTT/ref/line_overlap1.remote.gz b/tests/RTT/ref/line_overlap1.remote.gz
index 6b261d2..84ea929 100644
Binary files a/tests/RTT/ref/line_overlap1.remote.gz and b/tests/RTT/ref/line_overlap1.remote.gz differ
diff --git a/tests/RTT/ref/line_overlap1.scad b/tests/RTT/ref/line_overlap1.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/line_overlap1.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/line_overlap1.svg b/tests/RTT/ref/line_overlap1.svg
index d700af0..a01baae 100644
--- a/tests/RTT/ref/line_overlap1.svg
+++ b/tests/RTT/ref/line_overlap1.svg
@@ -1,20 +1,20 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="5.0800" y1="5.0800" x2="6.3500" y2="5.0800" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="5.5880" y1="5.0800" x2="7.6200" y2="5.0800" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/line_overlap2.bbrd.png b/tests/RTT/ref/line_overlap2.bbrd.png
new file mode 100644
index 0000000..daf6a28
Binary files /dev/null and b/tests/RTT/ref/line_overlap2.bbrd.png differ
diff --git a/tests/RTT/ref/line_overlap2.dsn b/tests/RTT/ref/line_overlap2.dsn
index b3a2341..4849b54 100644
--- a/tests/RTT/ref/line_overlap2.dsn
+++ b/tests/RTT/ref/line_overlap2.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/line_overlap2.eps b/tests/RTT/ref/line_overlap2.eps
new file mode 100644
index 0000000..1fc644a
--- /dev/null
+++ b/tests/RTT/ref/line_overlap2.eps
@@ -0,0 +1,36 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: line_overlap2.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01500 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.20000 0.20000 0.35000 0.20000 t
+0.22000 0.20000 0.30000 0.20000 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/line_overlap2.gbr/line_overlap2.fab.gbr b/tests/RTT/ref/line_overlap2.gbr/line_overlap2.fab.gbr
index 98127a2..60a4693 100644
--- a/tests/RTT/ref/line_overlap2.gbr/line_overlap2.fab.gbr
+++ b/tests/RTT/ref/line_overlap2.gbr/line_overlap2.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Two lines, one over the other, full cover, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Two lines, one over the other, full cover, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_overlap2.gbr/line_overlap2.top.gbr b/tests/RTT/ref/line_overlap2.gbr/line_overlap2.top.gbr
index 4b231d6..5ffcad5 100644
--- a/tests/RTT/ref/line_overlap2.gbr/line_overlap2.top.gbr
+++ b/tests/RTT/ref/line_overlap2.gbr/line_overlap2.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Two lines, one over the other, full cover, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Two lines, one over the other, full cover, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_overlap2.nelma.em b/tests/RTT/ref/line_overlap2.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/line_overlap2.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/line_overlap2.png b/tests/RTT/ref/line_overlap2.png
index 24bc2ec..4a0cd2d 100644
Binary files a/tests/RTT/ref/line_overlap2.png and b/tests/RTT/ref/line_overlap2.png differ
diff --git a/tests/RTT/ref/line_overlap2.png.text b/tests/RTT/ref/line_overlap2.png.text
new file mode 100644
index 0000000..76d8710
--- /dev/null
+++ b/tests/RTT/ref/line_overlap2.png.text
@@ -0,0 +1,6 @@
+r6630
+
+18 pixel width (15)
+198 pixel length (165)
+
+(it is actually 3 traces that should export as 1)
diff --git a/tests/RTT/ref/line_overlap2.ps.gz b/tests/RTT/ref/line_overlap2.ps.gz
index e737cf5..c39e33f 100644
Binary files a/tests/RTT/ref/line_overlap2.ps.gz and b/tests/RTT/ref/line_overlap2.ps.gz differ
diff --git a/tests/RTT/ref/line_overlap2.remote.gz b/tests/RTT/ref/line_overlap2.remote.gz
index 88a4453..bef2e8b 100644
Binary files a/tests/RTT/ref/line_overlap2.remote.gz and b/tests/RTT/ref/line_overlap2.remote.gz differ
diff --git a/tests/RTT/ref/line_overlap2.scad b/tests/RTT/ref/line_overlap2.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/line_overlap2.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/line_overlap2.svg b/tests/RTT/ref/line_overlap2.svg
index d11d1a7..1e71e1f 100644
--- a/tests/RTT/ref/line_overlap2.svg
+++ b/tests/RTT/ref/line_overlap2.svg
@@ -1,20 +1,20 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="5.0800" y1="5.0800" x2="8.8900" y2="5.0800" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="5.5880" y1="5.0800" x2="7.6200" y2="5.0800" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/line_overlap3.bbrd.png b/tests/RTT/ref/line_overlap3.bbrd.png
new file mode 100644
index 0000000..f4dea51
Binary files /dev/null and b/tests/RTT/ref/line_overlap3.bbrd.png differ
diff --git a/tests/RTT/ref/line_overlap3.dsn b/tests/RTT/ref/line_overlap3.dsn
index 078a754..461590d 100644
--- a/tests/RTT/ref/line_overlap3.dsn
+++ b/tests/RTT/ref/line_overlap3.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/line_overlap3.eps b/tests/RTT/ref/line_overlap3.eps
new file mode 100644
index 0000000..e160aaf
--- /dev/null
+++ b/tests/RTT/ref/line_overlap3.eps
@@ -0,0 +1,36 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: line_overlap3.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01500 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.20000 0.20000 0.35000 0.20000 t
+0.20000 0.20000 0.35000 0.20000 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/line_overlap3.gbr/line_overlap3.fab.gbr b/tests/RTT/ref/line_overlap3.gbr/line_overlap3.fab.gbr
index b555d76..d87e727 100644
--- a/tests/RTT/ref/line_overlap3.gbr/line_overlap3.fab.gbr
+++ b/tests/RTT/ref/line_overlap3.gbr/line_overlap3.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Full overlap: the same line twice, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Full overlap: the same line twice, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_overlap3.gbr/line_overlap3.top.gbr b/tests/RTT/ref/line_overlap3.gbr/line_overlap3.top.gbr
index 876e0d7..e0188f5 100644
--- a/tests/RTT/ref/line_overlap3.gbr/line_overlap3.top.gbr
+++ b/tests/RTT/ref/line_overlap3.gbr/line_overlap3.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Full overlap: the same line twice, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Full overlap: the same line twice, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_overlap3.nelma.em b/tests/RTT/ref/line_overlap3.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/line_overlap3.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/line_overlap3.png b/tests/RTT/ref/line_overlap3.png
index 24bc2ec..4a0cd2d 100644
Binary files a/tests/RTT/ref/line_overlap3.png and b/tests/RTT/ref/line_overlap3.png differ
diff --git a/tests/RTT/ref/line_overlap3.png.text b/tests/RTT/ref/line_overlap3.png.text
new file mode 100644
index 0000000..2f3d434
--- /dev/null
+++ b/tests/RTT/ref/line_overlap3.png.text
@@ -0,0 +1,5 @@
+18 pixel width (15)
+198 pixel length (165)
+
+(mil)
+
diff --git a/tests/RTT/ref/line_overlap3.ps.gz b/tests/RTT/ref/line_overlap3.ps.gz
index 799705d..450887d 100644
Binary files a/tests/RTT/ref/line_overlap3.ps.gz and b/tests/RTT/ref/line_overlap3.ps.gz differ
diff --git a/tests/RTT/ref/line_overlap3.remote.gz b/tests/RTT/ref/line_overlap3.remote.gz
index 7da0186..aa7334c 100644
Binary files a/tests/RTT/ref/line_overlap3.remote.gz and b/tests/RTT/ref/line_overlap3.remote.gz differ
diff --git a/tests/RTT/ref/line_overlap3.scad b/tests/RTT/ref/line_overlap3.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/line_overlap3.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/line_overlap3.svg b/tests/RTT/ref/line_overlap3.svg
index 6d036bc..235e590 100644
--- a/tests/RTT/ref/line_overlap3.svg
+++ b/tests/RTT/ref/line_overlap3.svg
@@ -1,20 +1,20 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="5.0800" y1="5.0800" x2="8.8900" y2="5.0800" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="5.0800" y1="5.0800" x2="8.8900" y2="5.0800" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/line_overlap4.bbrd.png b/tests/RTT/ref/line_overlap4.bbrd.png
new file mode 100644
index 0000000..daf6a28
Binary files /dev/null and b/tests/RTT/ref/line_overlap4.bbrd.png differ
diff --git a/tests/RTT/ref/line_overlap4.dsn b/tests/RTT/ref/line_overlap4.dsn
index dde2bce..1175a64 100644
--- a/tests/RTT/ref/line_overlap4.dsn
+++ b/tests/RTT/ref/line_overlap4.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/line_overlap4.eps b/tests/RTT/ref/line_overlap4.eps
new file mode 100644
index 0000000..02b790e
--- /dev/null
+++ b/tests/RTT/ref/line_overlap4.eps
@@ -0,0 +1,66 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: line_overlap4.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.15000 0.15000 moveto
+0.30000 0.15000 lineto
+0.30000 0.17750 lineto
+0.20000 0.17750 lineto
+0.19647 0.17771 lineto
+0.19303 0.17854 lineto
+0.18975 0.17989 lineto
+0.18673 0.18174 lineto
+0.18404 0.18404 lineto
+0.18174 0.18673 lineto
+0.17989 0.18975 lineto
+0.17854 0.19303 lineto
+0.17771 0.19647 lineto
+0.17743 0.20000 lineto
+0.17771 0.20353 lineto
+0.17854 0.20697 lineto
+0.17989 0.21025 lineto
+0.18174 0.21327 lineto
+0.18404 0.21596 lineto
+0.18673 0.21826 lineto
+0.18975 0.22011 lineto
+0.19303 0.22146 lineto
+0.19647 0.22229 lineto
+0.20000 0.22250 lineto
+0.30000 0.22250 lineto
+0.30000 0.32500 lineto
+0.15000 0.32500 lineto
+fill
+0.00500 setlinewidth
+0.20000 0.20000 0.35000 0.20000 t
+0.01500 setlinewidth
+0.20000 0.20000 0.35000 0.20000 t
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/line_overlap4.gbr/line_overlap4.fab.gbr b/tests/RTT/ref/line_overlap4.gbr/line_overlap4.fab.gbr
index e94f11e..3c9bdfd 100644
--- a/tests/RTT/ref/line_overlap4.gbr/line_overlap4.fab.gbr
+++ b/tests/RTT/ref/line_overlap4.gbr/line_overlap4.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Full overlap: the same line twice with different settings, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Full overlap: the same line twice with different settings, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_overlap4.gbr/line_overlap4.top.gbr b/tests/RTT/ref/line_overlap4.gbr/line_overlap4.top.gbr
index 1ce4670..c9eb82f 100644
--- a/tests/RTT/ref/line_overlap4.gbr/line_overlap4.top.gbr
+++ b/tests/RTT/ref/line_overlap4.gbr/line_overlap4.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Full overlap: the same line twice with different settings, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Full overlap: the same line twice with different settings, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_overlap4.nelma.em b/tests/RTT/ref/line_overlap4.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/line_overlap4.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/line_overlap4.png b/tests/RTT/ref/line_overlap4.png
index cf41506..6ad73ae 100644
Binary files a/tests/RTT/ref/line_overlap4.png and b/tests/RTT/ref/line_overlap4.png differ
diff --git a/tests/RTT/ref/line_overlap4.png.text b/tests/RTT/ref/line_overlap4.png.text
new file mode 100644
index 0000000..d95af3c
--- /dev/null
+++ b/tests/RTT/ref/line_overlap4.png.text
@@ -0,0 +1,6 @@
+18 pixel width (15)
+198 pixel length (165)
+18 pixel clearance (15)
+
+in a poly
+181 x 211 pixels (150.833 x 175.833)
diff --git a/tests/RTT/ref/line_overlap4.ps.gz b/tests/RTT/ref/line_overlap4.ps.gz
index cc6e5e3..ee9512a 100644
Binary files a/tests/RTT/ref/line_overlap4.ps.gz and b/tests/RTT/ref/line_overlap4.ps.gz differ
diff --git a/tests/RTT/ref/line_overlap4.remote.gz b/tests/RTT/ref/line_overlap4.remote.gz
index f6e363d..5685231 100644
Binary files a/tests/RTT/ref/line_overlap4.remote.gz and b/tests/RTT/ref/line_overlap4.remote.gz differ
diff --git a/tests/RTT/ref/line_overlap4.scad b/tests/RTT/ref/line_overlap4.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/line_overlap4.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/line_overlap4.svg b/tests/RTT/ref/line_overlap4.svg
index 56e95c9..09f9d13 100644
--- a/tests/RTT/ref/line_overlap4.svg
+++ b/tests/RTT/ref/line_overlap4.svg
@@ -1,21 +1,21 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <polygon points="3.8100,3.8100 7.6200,3.8100 7.6200,4.5085 5.0800,4.5085 4.9903,4.5138 4.9029,4.5348 4.8197,4.5692 4.7430,4.6162 4.6746,4.6746 4.6162,4.7430 4.5692,4.8197 4.5348,4.9029 4.5138,4.9903 4.5067,5.0800 4.5138,5.1697 4.5348,5.2571 4.5692,5.3403 4.6162,5.4170 4.6746,5.4854 4.7430,5.5438 4.8197,5.5908 4.9029,5.6252 4.9903,5.6462 5.0800,5.6515 7.6200,5.6515 7.6200,8.2550 3.8100,8.2550 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <line x1="5.0800" y1="5.0800" x2="8.8900" y2="5.0800" stroke-width="0.1270" stroke="#8b2323" stroke-linecap="round"/>
  <line x1="5.0800" y1="5.0800" x2="8.8900" y2="5.0800" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/line_zerolen.bbrd.png b/tests/RTT/ref/line_zerolen.bbrd.png
new file mode 100644
index 0000000..d74e1f7
Binary files /dev/null and b/tests/RTT/ref/line_zerolen.bbrd.png differ
diff --git a/tests/RTT/ref/line_zerolen.dsn b/tests/RTT/ref/line_zerolen.dsn
index dffd266..65b1341 100644
--- a/tests/RTT/ref/line_zerolen.dsn
+++ b/tests/RTT/ref/line_zerolen.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/line_zerolen.eps b/tests/RTT/ref/line_zerolen.eps
new file mode 100644
index 0000000..75d5e6a
--- /dev/null
+++ b/tests/RTT/ref/line_zerolen.eps
@@ -0,0 +1,35 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: line_zerolen.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.01500 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.20000 0.20000 0.00750 c
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/line_zerolen.gbr/line_zerolen.fab.gbr b/tests/RTT/ref/line_zerolen.gbr/line_zerolen.fab.gbr
index e1a2655..c50d0e2 100644
--- a/tests/RTT/ref/line_zerolen.gbr/line_zerolen.fab.gbr
+++ b/tests/RTT/ref/line_zerolen.gbr/line_zerolen.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: A single zero length line, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: A single zero length line, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_zerolen.gbr/line_zerolen.top.gbr b/tests/RTT/ref/line_zerolen.gbr/line_zerolen.top.gbr
index 3783e46..40337b4 100644
--- a/tests/RTT/ref/line_zerolen.gbr/line_zerolen.top.gbr
+++ b/tests/RTT/ref/line_zerolen.gbr/line_zerolen.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: A single zero length line, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: A single zero length line, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/line_zerolen.nelma.em b/tests/RTT/ref/line_zerolen.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/line_zerolen.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/line_zerolen.png b/tests/RTT/ref/line_zerolen.png
index 34922b6..53bbcea 100644
Binary files a/tests/RTT/ref/line_zerolen.png and b/tests/RTT/ref/line_zerolen.png differ
diff --git a/tests/RTT/ref/line_zerolen.png.text b/tests/RTT/ref/line_zerolen.png.text
new file mode 100644
index 0000000..a50506b
--- /dev/null
+++ b/tests/RTT/ref/line_zerolen.png.text
@@ -0,0 +1 @@
+19 pixel (15.833) diameter point made of a trace with zero length
diff --git a/tests/RTT/ref/line_zerolen.ps.gz b/tests/RTT/ref/line_zerolen.ps.gz
index c3c3f24..c2282d7 100644
Binary files a/tests/RTT/ref/line_zerolen.ps.gz and b/tests/RTT/ref/line_zerolen.ps.gz differ
diff --git a/tests/RTT/ref/line_zerolen.remote.gz b/tests/RTT/ref/line_zerolen.remote.gz
index 3de3ace..fcb18bb 100644
Binary files a/tests/RTT/ref/line_zerolen.remote.gz and b/tests/RTT/ref/line_zerolen.remote.gz differ
diff --git a/tests/RTT/ref/line_zerolen.scad b/tests/RTT/ref/line_zerolen.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/line_zerolen.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/line_zerolen.svg b/tests/RTT/ref/line_zerolen.svg
index d11b68b..2b7707a 100644
--- a/tests/RTT/ref/line_zerolen.svg
+++ b/tests/RTT/ref/line_zerolen.svg
@@ -1,19 +1,19 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <line x1="5.0800" y1="5.0800" x2="5.0800" y2="5.0800" stroke-width="0.3810" stroke="#8b2323" stroke-linecap="round"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/netlist.bbrd.png b/tests/RTT/ref/netlist.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/netlist.bbrd.png differ
diff --git a/tests/RTT/ref/netlist.dsn b/tests/RTT/ref/netlist.dsn
index ad2dbc6..13f5093 100644
--- a/tests/RTT/ref/netlist.dsn
+++ b/tests/RTT/ref/netlist.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,12 +33,12 @@
     )
   )
   (placement
-    (component 8
+    (component 9
       (place "U1" 6.350000 6.985000 front 0 (PN 0))
     )
   )
   (library
-    (image 8
+    (image 9
       (pin Th_square_2032000 "1" -3.810000 1.270000)
       (pin Th_round_2032000 "4" 3.810000 1.270000)
       (pin Th_round_2032000 "2" -3.810000 -1.270000)
diff --git a/tests/RTT/ref/netlist.eps b/tests/RTT/ref/netlist.eps
new file mode 100644
index 0000000..f04d6af
--- /dev/null
+++ b/tests/RTT/ref/netlist.eps
@@ -0,0 +1,95 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: netlist.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.13500 0.14000 0.21500 r
+0.40000 0.17500 0.04000 c
+0.10000 0.27500 0.04000 c
+0.40000 0.27500 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer group5 group 5 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.13500 0.14000 0.21500 r
+0.40000 0.17500 0.04000 c
+0.10000 0.27500 0.04000 c
+0.40000 0.27500 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer group7 group 7 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.13500 0.14000 0.21500 r
+0.40000 0.17500 0.04000 c
+0.10000 0.27500 0.04000 c
+0.40000 0.27500 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer top group 3 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.13500 0.14000 0.21500 r
+0.40000 0.17500 0.04000 c
+0.10000 0.27500 0.04000 c
+0.40000 0.27500 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer plated-drill group -1 drill 1 mask 0
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer topsilk group 1 drill 0 mask 0
+0.01000 setlinewidth
+0 0 0 setrgbcolor
+0.05000 0.12500 0.05000 0.32500 t
+0.45000 0.32500 0.05000 0.32500 t
+0.45000 0.32500 0.45000 0.12500 t
+0.05000 0.12500 0.20000 0.12500 t
+0.30000 0.12500 0.45000 0.12500 t
+0 180 -0.05000 0.05000 0.25000 0.12500 0.2 a
+0.00700 setlinewidth
+0.10000 0.07500 0.10000 0.11000 t
+0.10000 0.11000 0.10500 0.11500 t
+0.10500 0.11500 0.11500 0.11500 t
+0.11500 0.11500 0.12000 0.11000 t
+0.12000 0.07500 0.12000 0.11000 t
+0.13200 0.08300 0.14000 0.07500 t
+0.14000 0.07500 0.14000 0.11500 t
+0.13200 0.11500 0.14700 0.11500 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/netlist.gbr/netlist.bottommask.gbr b/tests/RTT/ref/netlist.gbr/netlist.bottommask.gbr
index 366e9e1..d2b08d7 100644
--- a/tests/RTT/ref/netlist.gbr/netlist.bottommask.gbr
+++ b/tests/RTT/ref/netlist.gbr/netlist.bottommask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group -1 layer_idx -1 *
-G04 Title: board with minimal netlist, TODO:group_name *
+G04 start of page 4 for group 11 layer_idx 0 *
+G04 Title: board with minimal netlist, bottom mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/netlist.gbr/netlist.fab.gbr b/tests/RTT/ref/netlist.gbr/netlist.fab.gbr
index f94c237..15fcab0 100644
--- a/tests/RTT/ref/netlist.gbr/netlist.fab.gbr
+++ b/tests/RTT/ref/netlist.gbr/netlist.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: board with minimal netlist, TODO:group_name *
+G04 start of page 6 for group -1 layer_idx 16777221 *
+G04 Title: board with minimal netlist, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,11 +9,11 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNFAB*%
-%ADD19C,0.0100*%
-%ADD18C,0.0001*%
-%ADD17C,0.0060*%
-%ADD16C,0.0080*%
-G54D16*X10000Y32500D02*Y30900D01*
+%ADD21C,0.0100*%
+%ADD20C,0.0001*%
+%ADD19C,0.0060*%
+%ADD18C,0.0080*%
+G54D18*X10000Y32500D02*Y30900D01*
 Y32500D02*X11387Y33300D01*
 X10000Y32500D02*X8613Y33300D01*
 X40000Y32500D02*Y30900D01*
@@ -28,7 +28,7 @@ X40000Y22500D02*X38613Y23300D01*
 X15000Y106250D02*Y104650D01*
 Y106250D02*X16387Y107050D01*
 X15000Y106250D02*X13613Y107050D01*
-G54D17*X135000Y110000D02*X136500Y107000D01*
+G54D19*X135000Y110000D02*X136500Y107000D01*
 X138000Y110000D01*
 X136500Y107000D02*Y104000D01*
 X139800Y107300D02*X142050D01*
@@ -49,7 +49,7 @@ X144600Y104750D02*X145350Y104000D01*
 X98000Y106250D02*X101000Y110000D01*
 X98000Y106250D02*X101750D01*
 X101000Y110000D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X45000Y110000D02*Y104000D01*
 X49500D01*
 Y110000D01*
@@ -67,16 +67,16 @@ X60300D01*
 Y110000D01*
 X55800D01*
 G37*
-G54D17*X61200Y106250D02*X64200Y110000D01*
+G54D19*X61200Y106250D02*X64200Y110000D01*
 X61200Y106250D02*X64950D01*
 X64200Y110000D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X66750Y110000D02*Y104000D01*
 X71250D01*
 Y110000D01*
 X66750D01*
 G37*
-G54D17*X3000Y125000D02*X3750Y124250D01*
+G54D19*X3000Y125000D02*X3750Y124250D01*
 X750Y125000D02*X3000D01*
 X0Y124250D02*X750Y125000D01*
 X0Y124250D02*Y122750D01*
@@ -87,7 +87,7 @@ Y119750D01*
 X3000Y119000D02*X3750Y119750D01*
 X750Y119000D02*X3000D01*
 X0Y119750D02*X750Y119000D01*
-G54D18*G36*
+G54D20*G36*
 X5550Y125000D02*Y119000D01*
 X10050D01*
 Y125000D01*
@@ -117,14 +117,14 @@ X31650D01*
 Y125000D01*
 X27150D01*
 G37*
-G54D17*X0Y118000D02*X5550D01*
+G54D19*X0Y118000D02*X5550D01*
 X41750Y125000D02*Y119000D01*
 X43700Y125000D02*X44750Y123950D01*
 Y120050D01*
 X43700Y119000D02*X44750Y120050D01*
 X41000Y119000D02*X43700D01*
 X41000Y125000D02*X43700D01*
-G54D18*G36*
+G54D20*G36*
 X46550D02*Y119000D01*
 X51050D01*
 Y125000D01*
@@ -154,10 +154,10 @@ X75350D01*
 Y125000D01*
 X70850D01*
 G37*
-G54D17*X76250D02*X77750D01*
+G54D19*X76250D02*X77750D01*
 X77000D02*Y119000D01*
 X76250D02*X77750D01*
-G54D18*G36*
+G54D20*G36*
 X79550Y125000D02*Y119000D01*
 X84050D01*
 Y125000D01*
@@ -181,13 +181,13 @@ X100250D01*
 Y125000D01*
 X95750D01*
 G37*
-G54D17*X41000Y118000D02*X52550D01*
+G54D19*X41000Y118000D02*X52550D01*
 X96050Y119000D02*X98000D01*
 X95000Y120050D02*X96050Y119000D01*
 X95000Y123950D02*Y120050D01*
 Y123950D02*X96050Y125000D01*
 X98000D01*
-G54D18*G36*
+G54D20*G36*
 X99800D02*Y119000D01*
 X104300D01*
 Y125000D01*
@@ -211,14 +211,14 @@ X120500D01*
 Y125000D01*
 X116000D01*
 G37*
-G54D17*X95000Y118000D02*X99800D01*
+G54D19*X95000Y118000D02*X99800D01*
 X130750Y125000D02*Y119000D01*
 X130000Y125000D02*X133000D01*
 X133750Y124250D01*
 Y122750D01*
 X133000Y122000D02*X133750Y122750D01*
 X130750Y122000D02*X133000D01*
-G54D18*G36*
+G54D20*G36*
 X135550Y125000D02*Y119000D01*
 X140050D01*
 Y125000D01*
@@ -254,10 +254,10 @@ X167050D01*
 Y125000D01*
 X162550D01*
 G37*
-G54D17*X130000Y118000D02*X135550D01*
+G54D19*X130000Y118000D02*X135550D01*
 X0Y140000D02*X3000D01*
 X1500D02*Y134000D01*
-G54D18*G36*
+G54D20*G36*
 X4800Y140000D02*Y134000D01*
 X9300D01*
 Y140000D01*
@@ -299,10 +299,10 @@ X44400D01*
 Y140000D01*
 X39900D01*
 G37*
-G54D17*X48000Y138800D02*X49200Y140000D01*
+G54D19*X48000Y138800D02*X49200Y140000D01*
 Y134000D01*
 X48000D02*X50250D01*
-G54D18*G36*
+G54D20*G36*
 X54750Y140000D02*Y134000D01*
 X59250D01*
 Y140000D01*
@@ -518,10 +518,10 @@ X264450D01*
 Y140000D01*
 X259950D01*
 G37*
-G54D17*X268050Y136250D02*X271050Y140000D01*
+G54D19*X268050Y136250D02*X271050Y140000D01*
 X268050Y136250D02*X271800D01*
 X271050Y140000D02*Y134000D01*
-G54D18*G36*
+G54D20*G36*
 X276300Y140000D02*Y134000D01*
 X280800D01*
 Y140000D01*
@@ -581,15 +581,15 @@ X332100D01*
 Y140000D01*
 X327600D01*
 G37*
-G54D19*X0Y50000D02*X50000D01*
+G54D21*X0Y50000D02*X50000D01*
 X0D02*Y0D01*
 X50000Y50000D02*Y0D01*
 X0D02*X50000D01*
-G54D17*X200000Y65000D02*Y59000D01*
+G54D19*X200000Y65000D02*Y59000D01*
 Y65000D02*X202250Y62000D01*
 X204500Y65000D01*
 Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X206300Y65000D02*Y59000D01*
 X210800D01*
 Y65000D01*
@@ -625,13 +625,13 @@ X237800D01*
 Y65000D01*
 X233300D01*
 G37*
-G54D17*X242150D02*Y59000D01*
+G54D19*X242150D02*Y59000D01*
 X244100Y65000D02*X245150Y63950D01*
 Y60050D01*
 X244100Y59000D02*X245150Y60050D01*
 X241400Y59000D02*X244100D01*
 X241400Y65000D02*X244100D01*
-G54D18*G36*
+G54D20*G36*
 X246950D02*Y59000D01*
 X251450D01*
 Y65000D01*
@@ -691,7 +691,7 @@ X300050D01*
 Y65000D01*
 X295550D01*
 G37*
-G54D17*X303650D02*X306650D01*
+G54D19*X303650D02*X306650D01*
 X303650D02*Y62000D01*
 X304400Y62750D01*
 X305900D01*
@@ -700,7 +700,7 @@ Y59750D01*
 X305900Y59000D02*X306650Y59750D01*
 X304400Y59000D02*X305900D01*
 X303650Y59750D02*X304400Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X308450Y65000D02*Y59000D01*
 X312950D01*
 Y65000D01*
@@ -808,7 +808,7 @@ X410150D01*
 Y65000D01*
 X405650D01*
 G37*
-G54D17*X413750D02*X416750D01*
+G54D19*X413750D02*X416750D01*
 X413750D02*Y62000D01*
 X414500Y62750D01*
 X416000D01*
@@ -817,7 +817,7 @@ Y59750D01*
 X416000Y59000D02*X416750Y59750D01*
 X414500Y59000D02*X416000D01*
 X413750Y59750D02*X414500Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X418550Y65000D02*Y59000D01*
 X423050D01*
 Y65000D01*
@@ -919,7 +919,7 @@ X514850D01*
 Y65000D01*
 X510350D01*
 G37*
-G54D17*X0Y-8000D02*X3000D01*
+G54D19*X0Y-8000D02*X3000D01*
 X3750Y-7250D01*
 Y-5450D02*Y-7250D01*
 X3000Y-4700D02*X3750Y-5450D01*
@@ -929,7 +929,7 @@ X0Y-2000D02*X3000D01*
 X3750Y-2750D01*
 Y-3950D01*
 X3000Y-4700D02*X3750Y-3950D01*
-G54D18*G36*
+G54D20*G36*
 X5550Y-2000D02*Y-8000D01*
 X10050D01*
 Y-2000D01*
@@ -1121,7 +1121,7 @@ X193650D01*
 Y-2000D01*
 X189150D01*
 G37*
-G54D17*X197250Y-7250D02*X198000Y-8000D01*
+G54D19*X197250Y-7250D02*X198000Y-8000D01*
 X197250Y-6050D02*Y-7250D01*
 Y-6050D02*X198300Y-5000D01*
 X199200D01*
@@ -1136,7 +1136,7 @@ X199500D01*
 X200250Y-2750D01*
 Y-3950D01*
 X199200Y-5000D02*X200250Y-3950D01*
-G54D18*G36*
+G54D20*G36*
 X202050Y-2000D02*Y-8000D01*
 X206550D01*
 Y-2000D01*
@@ -1286,7 +1286,7 @@ X349650D01*
 Y-2000D01*
 X345150D01*
 G37*
-G54D17*X353250D02*X356250D01*
+G54D19*X353250D02*X356250D01*
 X353250D02*Y-5000D01*
 X354000Y-4250D01*
 X355500D01*
@@ -1295,7 +1295,7 @@ Y-7250D01*
 X355500Y-8000D02*X356250Y-7250D01*
 X354000Y-8000D02*X355500D01*
 X353250Y-7250D02*X354000Y-8000D01*
-G54D18*G36*
+G54D20*G36*
 X358050Y-2000D02*Y-8000D01*
 X362550D01*
 Y-2000D01*
@@ -1355,7 +1355,7 @@ X411150D01*
 Y-2000D01*
 X406650D01*
 G37*
-G54D17*X412050D02*X415050D01*
+G54D19*X412050D02*X415050D01*
 X412050D02*Y-5000D01*
 X412800Y-4250D01*
 X414300D01*
@@ -1364,7 +1364,7 @@ Y-7250D01*
 X414300Y-8000D02*X415050Y-7250D01*
 X412800Y-8000D02*X414300D01*
 X412050Y-7250D02*X412800Y-8000D01*
-G54D18*G36*
+G54D20*G36*
 X416850Y-2000D02*Y-8000D01*
 X421350D01*
 Y-2000D01*
@@ -1442,13 +1442,13 @@ X488850D01*
 Y-2000D01*
 X484350D01*
 G37*
-G54D17*X200750Y80000D02*Y74000D01*
+G54D19*X200750Y80000D02*Y74000D01*
 X202700Y80000D02*X203750Y78950D01*
 Y75050D01*
 X202700Y74000D02*X203750Y75050D01*
 X200000Y74000D02*X202700D01*
 X200000Y80000D02*X202700D01*
-G54D18*G36*
+G54D20*G36*
 X205550D02*Y74000D01*
 X210050D01*
 Y80000D01*
@@ -1508,13 +1508,13 @@ X261350D01*
 Y80000D01*
 X256850D01*
 G37*
-G54D17*X200000Y93500D02*Y89000D01*
+G54D19*X200000Y93500D02*Y89000D01*
 Y93500D02*X201050Y95000D01*
 X202700D01*
 X203750Y93500D01*
 Y89000D01*
 X200000Y92000D02*X203750D01*
-G54D18*G36*
+G54D20*G36*
 X205550Y95000D02*Y89000D01*
 X210050D01*
 Y95000D01*
@@ -1550,9 +1550,9 @@ X237050D01*
 Y95000D01*
 X232550D01*
 G37*
-G54D17*X200000Y110000D02*X203000D01*
+G54D19*X200000Y110000D02*X203000D01*
 X201500D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X204800Y110000D02*Y104000D01*
 X209300D01*
 Y110000D01*
@@ -1726,10 +1726,10 @@ X374000D01*
 Y110000D01*
 X369500D01*
 G37*
-G54D17*X377600D02*Y104000D01*
+G54D19*X377600D02*Y104000D01*
 Y110000D02*X380600D01*
 X377600Y107300D02*X379850D01*
-G54D18*G36*
+G54D20*G36*
 X382400Y110000D02*Y104000D01*
 X386900D01*
 Y110000D01*
@@ -1789,13 +1789,13 @@ X435500D01*
 Y110000D01*
 X431000D01*
 G37*
-G54D17*X439850D02*Y104000D01*
+G54D19*X439850D02*Y104000D01*
 X441800Y110000D02*X442850Y108950D01*
 Y105050D01*
 X441800Y104000D02*X442850Y105050D01*
 X439100Y104000D02*X441800D01*
 X439100Y110000D02*X441800D01*
-G54D18*G36*
+G54D20*G36*
 X444650D02*Y104000D01*
 X449150D01*
 Y110000D01*
diff --git a/tests/RTT/ref/netlist.gbr/netlist.topmask.gbr b/tests/RTT/ref/netlist.gbr/netlist.topmask.gbr
index bae0237..236d11d 100644
--- a/tests/RTT/ref/netlist.gbr/netlist.topmask.gbr
+++ b/tests/RTT/ref/netlist.gbr/netlist.topmask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: board with minimal netlist, TODO:group_name *
+G04 start of page 3 for group 2 layer_idx 0 *
+G04 Title: board with minimal netlist, top mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/netlist.nelma.em b/tests/RTT/ref/netlist.nelma.em
new file mode 100644
index 0000000..8e03e9d
--- /dev/null
+++ b/tests/RTT/ref/netlist.nelma.em
@@ -0,0 +1,61 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+net bar {
+	objects = {
+
+	}
+}
+net foo {
+	objects = {
+
+	}
+}
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/netlist.png b/tests/RTT/ref/netlist.png
index 8f68bb1..20c2843 100644
Binary files a/tests/RTT/ref/netlist.png and b/tests/RTT/ref/netlist.png differ
diff --git a/tests/RTT/ref/netlist.png.text b/tests/RTT/ref/netlist.png.text
new file mode 100644
index 0000000..dbefb36
--- /dev/null
+++ b/tests/RTT/ref/netlist.png.text
@@ -0,0 +1,15 @@
+r6630
+
+One component U1
+
+U1 (4pin dip)
+Silk line thickness 12 pix (10)
+Inside silk screen corner to Pin1 top corner 6 x 6 pix (5 x 5 mil)
+Pin1 96 x 96 pix (80 x 80)
+Pin1 hole 47 pix (39.166) in diameter
+Pin2 to Pin1 distance 24 pix (20)
+Pin2 97 pix (80.833) circle
+Pin2 to Pin3 distance 263 pix (219.166)
+Pin2 hole 47 pix (39.166) in diameter
+
+
diff --git a/tests/RTT/ref/netlist.ps.gz b/tests/RTT/ref/netlist.ps.gz
index 49713d8..5a5b46a 100644
Binary files a/tests/RTT/ref/netlist.ps.gz and b/tests/RTT/ref/netlist.ps.gz differ
diff --git a/tests/RTT/ref/netlist.remote.gz b/tests/RTT/ref/netlist.remote.gz
index 454b3fa..33b61a5 100644
Binary files a/tests/RTT/ref/netlist.remote.gz and b/tests/RTT/ref/netlist.remote.gz differ
diff --git a/tests/RTT/ref/netlist.scad b/tests/RTT/ref/netlist.scad
new file mode 100644
index 0000000..845ab1c
--- /dev/null
+++ b/tests/RTT/ref/netlist.scad
@@ -0,0 +1,139 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: plated-drill
+layer_pdrill_list=[
+];
+
+
+// END_OF_LAYER layer_pdrill
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(5.080000,0.254000,0.037500,1.270000,-5.715000,90.000000,1,1,1);
+	line_segment_r(10.160000,0.254000,0.037500,6.350000,-8.255000,0.000000,1,1,1);
+	line_segment_r(5.080000,0.254000,0.037500,11.430000,-5.715000,-90.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,3.175000,-3.175000,180.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,9.525000,-3.175000,180.000000,1,1,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.082417,-3.230344,92.499641,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.092064,-3.340610,97.500259,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.111285,-3.449616,102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.139933,-3.556532,107.499977,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.177791,-3.660545,112.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.224569,-3.760862,117.499908,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.279912,-3.856720,122.499672,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.343400,-3.947391,127.500198,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.414549,-4.032183,132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.492817,-4.110450,137.499817,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.577610,-4.181600,142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.668280,-4.245088,147.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.764138,-4.300431,152.500092,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.864455,-4.347209,157.499954,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.968468,-4.385067,162.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.075384,-4.413715,167.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.184390,-4.432936,172.499741,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.294656,-4.442583,177.500366,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.405344,-4.442583,-177.500366,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.515610,-4.432936,-172.499741,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.624617,-4.413715,-167.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.731533,-4.385067,-162.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.835545,-4.347209,-157.499954,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.935862,-4.300431,-152.500092,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.031720,-4.245088,-147.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.122390,-4.181600,-142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.207182,-4.110450,-137.499817,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.285450,-4.032183,-132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.356599,-3.947391,-127.499794,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.420087,-3.856721,-122.500381,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.475431,-3.760863,-117.499664,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.522210,-3.660545,-112.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.560067,-3.556532,-107.499825,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.588715,-3.449615,-102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.607936,-3.340610,-97.500320,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,7.617583,-3.230344,-92.499641,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,2.540000,-2.349500,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.603500,-2.857500,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,2.794000,-2.921000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.984500,-2.857500,-135.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,3.048000,-2.349500,90.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,3.454401,-2.006600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,3.556001,-2.413000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,3.543301,-2.921000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/netlist.svg b/tests/RTT/ref/netlist.svg
index db15ae8..8764b43 100644
--- a/tests/RTT/ref/netlist.svg
+++ b/tests/RTT/ref/netlist.svg
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 <!--normal-->
  <rect x="1.5240" y="3.4290" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -15,7 +15,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 <!--normal-->
  <rect x="1.5240" y="3.4290" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -26,7 +26,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <rect x="1.5240" y="3.4290" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -37,7 +37,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <rect x="1.5240" y="3.4290" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -48,14 +48,14 @@
  <circle cx="2.5400" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="1.2700" y1="3.1750" x2="1.2700" y2="8.2550" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="11.4300" y1="8.2550" x2="1.2700" y2="8.2550" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="11.4300" y1="8.2550" x2="11.4300" y2="3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="1.2700" y1="3.1750" x2="5.0800" y2="3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="7.6200" y1="3.1750" x2="11.4300" y2="3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
- <path d="M 5.0800 3.1750 A 1.2700 1.2700 0 0 0 7.6200 3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
+ <path d="M 7.62000000 3.17500000 A 1.2700 1.2700 0 0 1 5.0800 3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
  <line x1="2.5400" y1="1.9050" x2="2.5400" y2="2.7940" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="2.5400" y1="2.7940" x2="2.6670" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="2.6670" y1="2.9210" x2="2.9210" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
@@ -65,7 +65,7 @@
  <line x1="3.5560" y1="1.9050" x2="3.5560" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="3.3528" y1="2.9210" x2="3.7338" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
 </g>
-<g id="layer_-4048_plated-drill">
+<g id="layer_-1_plated-drill">
 <!--normal-->
  <circle cx="2.5400" cy="4.4450" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
diff --git a/tests/RTT/ref/netlist_ba.bbrd.png b/tests/RTT/ref/netlist_ba.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/netlist_ba.bbrd.png differ
diff --git a/tests/RTT/ref/netlist_ba.dsn b/tests/RTT/ref/netlist_ba.dsn
index 0f0c1c5..b5923de 100644
--- a/tests/RTT/ref/netlist_ba.dsn
+++ b/tests/RTT/ref/netlist_ba.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,12 +33,12 @@
     )
   )
   (placement
-    (component 8
+    (component 9
       (place "U1" 6.350000 6.985000 front 0 (PN 0))
     )
   )
   (library
-    (image 8
+    (image 9
       (pin Th_square_2032000 "1" -3.810000 1.270000)
       (pin Th_round_2032000 "4" 3.810000 1.270000)
       (pin Th_round_2032000 "2" -3.810000 -1.270000)
diff --git a/tests/RTT/ref/netlist_ba.eps b/tests/RTT/ref/netlist_ba.eps
new file mode 100644
index 0000000..5c8289d
--- /dev/null
+++ b/tests/RTT/ref/netlist_ba.eps
@@ -0,0 +1,95 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: netlist_ba.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.13500 0.14000 0.21500 r
+0.40000 0.17500 0.04000 c
+0.10000 0.27500 0.04000 c
+0.40000 0.27500 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer group5 group 5 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.13500 0.14000 0.21500 r
+0.40000 0.17500 0.04000 c
+0.10000 0.27500 0.04000 c
+0.40000 0.27500 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer group7 group 7 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.13500 0.14000 0.21500 r
+0.40000 0.17500 0.04000 c
+0.10000 0.27500 0.04000 c
+0.40000 0.27500 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer top group 3 drill 0 mask 0
+0.301961 0.301961 0.301961 setrgbcolor
+0.06000 0.13500 0.14000 0.21500 r
+0.40000 0.17500 0.04000 c
+0.10000 0.27500 0.04000 c
+0.40000 0.27500 0.04000 c
+1 1 1 setrgbcolor
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer plated-drill group -1 drill 1 mask 0
+0.10000 0.17500 0.01968 c
+0.40000 0.17500 0.01968 c
+0.10000 0.27500 0.01968 c
+0.40000 0.27500 0.01968 c
+% Layer topsilk group 1 drill 0 mask 0
+0.01000 setlinewidth
+0 0 0 setrgbcolor
+0.05000 0.12500 0.05000 0.32500 t
+0.45000 0.32500 0.05000 0.32500 t
+0.45000 0.32500 0.45000 0.12500 t
+0.05000 0.12500 0.20000 0.12500 t
+0.30000 0.12500 0.45000 0.12500 t
+0 180 -0.05000 0.05000 0.25000 0.12500 0.2 a
+0.00700 setlinewidth
+0.10000 0.07500 0.10000 0.11000 t
+0.10000 0.11000 0.10500 0.11500 t
+0.10500 0.11500 0.11500 0.11500 t
+0.11500 0.11500 0.12000 0.11000 t
+0.12000 0.07500 0.12000 0.11000 t
+0.13200 0.08300 0.14000 0.07500 t
+0.14000 0.07500 0.14000 0.11500 t
+0.13200 0.11500 0.14700 0.11500 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/netlist_ba.gbr/netlist_ba.bottommask.gbr b/tests/RTT/ref/netlist_ba.gbr/netlist_ba.bottommask.gbr
index de1b800..a3683cc 100644
--- a/tests/RTT/ref/netlist_ba.gbr/netlist_ba.bottommask.gbr
+++ b/tests/RTT/ref/netlist_ba.gbr/netlist_ba.bottommask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group -1 layer_idx -1 *
-G04 Title: board with minimal netlist and some back-annotation changes, TODO:group_name *
+G04 start of page 4 for group 11 layer_idx 0 *
+G04 Title: board with minimal netlist and some back-annotation changes, bottom mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/netlist_ba.gbr/netlist_ba.fab.gbr b/tests/RTT/ref/netlist_ba.gbr/netlist_ba.fab.gbr
index 2f38212..33da3ef 100644
--- a/tests/RTT/ref/netlist_ba.gbr/netlist_ba.fab.gbr
+++ b/tests/RTT/ref/netlist_ba.gbr/netlist_ba.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: board with minimal netlist and some back-annotation changes, TODO:group_name *
+G04 start of page 6 for group -1 layer_idx 16777221 *
+G04 Title: board with minimal netlist and some back-annotation changes, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
@@ -9,11 +9,11 @@ G04 PCB-Coordinate-Origin: lower left *
 %MOIN*%
 %FSLAX25Y25*%
 %LNFAB*%
-%ADD19C,0.0100*%
-%ADD18C,0.0001*%
-%ADD17C,0.0060*%
-%ADD16C,0.0080*%
-G54D16*X10000Y32500D02*Y30900D01*
+%ADD21C,0.0100*%
+%ADD20C,0.0001*%
+%ADD19C,0.0060*%
+%ADD18C,0.0080*%
+G54D18*X10000Y32500D02*Y30900D01*
 Y32500D02*X11387Y33300D01*
 X10000Y32500D02*X8613Y33300D01*
 X40000Y32500D02*Y30900D01*
@@ -28,7 +28,7 @@ X40000Y22500D02*X38613Y23300D01*
 X15000Y106250D02*Y104650D01*
 Y106250D02*X16387Y107050D01*
 X15000Y106250D02*X13613Y107050D01*
-G54D17*X135000Y110000D02*X136500Y107000D01*
+G54D19*X135000Y110000D02*X136500Y107000D01*
 X138000Y110000D01*
 X136500Y107000D02*Y104000D01*
 X139800Y107300D02*X142050D01*
@@ -49,7 +49,7 @@ X144600Y104750D02*X145350Y104000D01*
 X98000Y106250D02*X101000Y110000D01*
 X98000Y106250D02*X101750D01*
 X101000Y110000D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X45000Y110000D02*Y104000D01*
 X49500D01*
 Y110000D01*
@@ -67,16 +67,16 @@ X60300D01*
 Y110000D01*
 X55800D01*
 G37*
-G54D17*X61200Y106250D02*X64200Y110000D01*
+G54D19*X61200Y106250D02*X64200Y110000D01*
 X61200Y106250D02*X64950D01*
 X64200Y110000D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X66750Y110000D02*Y104000D01*
 X71250D01*
 Y110000D01*
 X66750D01*
 G37*
-G54D17*X3000Y125000D02*X3750Y124250D01*
+G54D19*X3000Y125000D02*X3750Y124250D01*
 X750Y125000D02*X3000D01*
 X0Y124250D02*X750Y125000D01*
 X0Y124250D02*Y122750D01*
@@ -87,7 +87,7 @@ Y119750D01*
 X3000Y119000D02*X3750Y119750D01*
 X750Y119000D02*X3000D01*
 X0Y119750D02*X750Y119000D01*
-G54D18*G36*
+G54D20*G36*
 X5550Y125000D02*Y119000D01*
 X10050D01*
 Y125000D01*
@@ -117,14 +117,14 @@ X31650D01*
 Y125000D01*
 X27150D01*
 G37*
-G54D17*X0Y118000D02*X5550D01*
+G54D19*X0Y118000D02*X5550D01*
 X41750Y125000D02*Y119000D01*
 X43700Y125000D02*X44750Y123950D01*
 Y120050D01*
 X43700Y119000D02*X44750Y120050D01*
 X41000Y119000D02*X43700D01*
 X41000Y125000D02*X43700D01*
-G54D18*G36*
+G54D20*G36*
 X46550D02*Y119000D01*
 X51050D01*
 Y125000D01*
@@ -154,10 +154,10 @@ X75350D01*
 Y125000D01*
 X70850D01*
 G37*
-G54D17*X76250D02*X77750D01*
+G54D19*X76250D02*X77750D01*
 X77000D02*Y119000D01*
 X76250D02*X77750D01*
-G54D18*G36*
+G54D20*G36*
 X79550Y125000D02*Y119000D01*
 X84050D01*
 Y125000D01*
@@ -181,13 +181,13 @@ X100250D01*
 Y125000D01*
 X95750D01*
 G37*
-G54D17*X41000Y118000D02*X52550D01*
+G54D19*X41000Y118000D02*X52550D01*
 X96050Y119000D02*X98000D01*
 X95000Y120050D02*X96050Y119000D01*
 X95000Y123950D02*Y120050D01*
 Y123950D02*X96050Y125000D01*
 X98000D01*
-G54D18*G36*
+G54D20*G36*
 X99800D02*Y119000D01*
 X104300D01*
 Y125000D01*
@@ -211,14 +211,14 @@ X120500D01*
 Y125000D01*
 X116000D01*
 G37*
-G54D17*X95000Y118000D02*X99800D01*
+G54D19*X95000Y118000D02*X99800D01*
 X130750Y125000D02*Y119000D01*
 X130000Y125000D02*X133000D01*
 X133750Y124250D01*
 Y122750D01*
 X133000Y122000D02*X133750Y122750D01*
 X130750Y122000D02*X133000D01*
-G54D18*G36*
+G54D20*G36*
 X135550Y125000D02*Y119000D01*
 X140050D01*
 Y125000D01*
@@ -254,10 +254,10 @@ X167050D01*
 Y125000D01*
 X162550D01*
 G37*
-G54D17*X130000Y118000D02*X135550D01*
+G54D19*X130000Y118000D02*X135550D01*
 X0Y140000D02*X3000D01*
 X1500D02*Y134000D01*
-G54D18*G36*
+G54D20*G36*
 X4800Y140000D02*Y134000D01*
 X9300D01*
 Y140000D01*
@@ -299,10 +299,10 @@ X44400D01*
 Y140000D01*
 X39900D01*
 G37*
-G54D17*X48000Y138800D02*X49200Y140000D01*
+G54D19*X48000Y138800D02*X49200Y140000D01*
 Y134000D01*
 X48000D02*X50250D01*
-G54D18*G36*
+G54D20*G36*
 X54750Y140000D02*Y134000D01*
 X59250D01*
 Y140000D01*
@@ -518,10 +518,10 @@ X264450D01*
 Y140000D01*
 X259950D01*
 G37*
-G54D17*X268050Y136250D02*X271050Y140000D01*
+G54D19*X268050Y136250D02*X271050Y140000D01*
 X268050Y136250D02*X271800D01*
 X271050Y140000D02*Y134000D01*
-G54D18*G36*
+G54D20*G36*
 X276300Y140000D02*Y134000D01*
 X280800D01*
 Y140000D01*
@@ -581,15 +581,15 @@ X332100D01*
 Y140000D01*
 X327600D01*
 G37*
-G54D19*X0Y50000D02*X50000D01*
+G54D21*X0Y50000D02*X50000D01*
 X0D02*Y0D01*
 X50000Y50000D02*Y0D01*
 X0D02*X50000D01*
-G54D17*X200000Y65000D02*Y59000D01*
+G54D19*X200000Y65000D02*Y59000D01*
 Y65000D02*X202250Y62000D01*
 X204500Y65000D01*
 Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X206300Y65000D02*Y59000D01*
 X210800D01*
 Y65000D01*
@@ -625,13 +625,13 @@ X237800D01*
 Y65000D01*
 X233300D01*
 G37*
-G54D17*X242150D02*Y59000D01*
+G54D19*X242150D02*Y59000D01*
 X244100Y65000D02*X245150Y63950D01*
 Y60050D01*
 X244100Y59000D02*X245150Y60050D01*
 X241400Y59000D02*X244100D01*
 X241400Y65000D02*X244100D01*
-G54D18*G36*
+G54D20*G36*
 X246950D02*Y59000D01*
 X251450D01*
 Y65000D01*
@@ -691,7 +691,7 @@ X300050D01*
 Y65000D01*
 X295550D01*
 G37*
-G54D17*X303650D02*X306650D01*
+G54D19*X303650D02*X306650D01*
 X303650D02*Y62000D01*
 X304400Y62750D01*
 X305900D01*
@@ -700,7 +700,7 @@ Y59750D01*
 X305900Y59000D02*X306650Y59750D01*
 X304400Y59000D02*X305900D01*
 X303650Y59750D02*X304400Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X308450Y65000D02*Y59000D01*
 X312950D01*
 Y65000D01*
@@ -808,7 +808,7 @@ X410150D01*
 Y65000D01*
 X405650D01*
 G37*
-G54D17*X413750D02*X416750D01*
+G54D19*X413750D02*X416750D01*
 X413750D02*Y62000D01*
 X414500Y62750D01*
 X416000D01*
@@ -817,7 +817,7 @@ Y59750D01*
 X416000Y59000D02*X416750Y59750D01*
 X414500Y59000D02*X416000D01*
 X413750Y59750D02*X414500Y59000D01*
-G54D18*G36*
+G54D20*G36*
 X418550Y65000D02*Y59000D01*
 X423050D01*
 Y65000D01*
@@ -919,7 +919,7 @@ X514850D01*
 Y65000D01*
 X510350D01*
 G37*
-G54D17*X0Y-8000D02*X3000D01*
+G54D19*X0Y-8000D02*X3000D01*
 X3750Y-7250D01*
 Y-5450D02*Y-7250D01*
 X3000Y-4700D02*X3750Y-5450D01*
@@ -929,7 +929,7 @@ X0Y-2000D02*X3000D01*
 X3750Y-2750D01*
 Y-3950D01*
 X3000Y-4700D02*X3750Y-3950D01*
-G54D18*G36*
+G54D20*G36*
 X5550Y-2000D02*Y-8000D01*
 X10050D01*
 Y-2000D01*
@@ -1121,7 +1121,7 @@ X193650D01*
 Y-2000D01*
 X189150D01*
 G37*
-G54D17*X197250Y-7250D02*X198000Y-8000D01*
+G54D19*X197250Y-7250D02*X198000Y-8000D01*
 X197250Y-6050D02*Y-7250D01*
 Y-6050D02*X198300Y-5000D01*
 X199200D01*
@@ -1136,7 +1136,7 @@ X199500D01*
 X200250Y-2750D01*
 Y-3950D01*
 X199200Y-5000D02*X200250Y-3950D01*
-G54D18*G36*
+G54D20*G36*
 X202050Y-2000D02*Y-8000D01*
 X206550D01*
 Y-2000D01*
@@ -1286,7 +1286,7 @@ X349650D01*
 Y-2000D01*
 X345150D01*
 G37*
-G54D17*X353250D02*X356250D01*
+G54D19*X353250D02*X356250D01*
 X353250D02*Y-5000D01*
 X354000Y-4250D01*
 X355500D01*
@@ -1295,7 +1295,7 @@ Y-7250D01*
 X355500Y-8000D02*X356250Y-7250D01*
 X354000Y-8000D02*X355500D01*
 X353250Y-7250D02*X354000Y-8000D01*
-G54D18*G36*
+G54D20*G36*
 X358050Y-2000D02*Y-8000D01*
 X362550D01*
 Y-2000D01*
@@ -1355,7 +1355,7 @@ X411150D01*
 Y-2000D01*
 X406650D01*
 G37*
-G54D17*X412050D02*X415050D01*
+G54D19*X412050D02*X415050D01*
 X412050D02*Y-5000D01*
 X412800Y-4250D01*
 X414300D01*
@@ -1364,7 +1364,7 @@ Y-7250D01*
 X414300Y-8000D02*X415050Y-7250D01*
 X412800Y-8000D02*X414300D01*
 X412050Y-7250D02*X412800Y-8000D01*
-G54D18*G36*
+G54D20*G36*
 X416850Y-2000D02*Y-8000D01*
 X421350D01*
 Y-2000D01*
@@ -1442,13 +1442,13 @@ X488850D01*
 Y-2000D01*
 X484350D01*
 G37*
-G54D17*X200750Y80000D02*Y74000D01*
+G54D19*X200750Y80000D02*Y74000D01*
 X202700Y80000D02*X203750Y78950D01*
 Y75050D01*
 X202700Y74000D02*X203750Y75050D01*
 X200000Y74000D02*X202700D01*
 X200000Y80000D02*X202700D01*
-G54D18*G36*
+G54D20*G36*
 X205550D02*Y74000D01*
 X210050D01*
 Y80000D01*
@@ -1508,13 +1508,13 @@ X261350D01*
 Y80000D01*
 X256850D01*
 G37*
-G54D17*X200000Y93500D02*Y89000D01*
+G54D19*X200000Y93500D02*Y89000D01*
 Y93500D02*X201050Y95000D01*
 X202700D01*
 X203750Y93500D01*
 Y89000D01*
 X200000Y92000D02*X203750D01*
-G54D18*G36*
+G54D20*G36*
 X205550Y95000D02*Y89000D01*
 X210050D01*
 Y95000D01*
@@ -1550,9 +1550,9 @@ X237050D01*
 Y95000D01*
 X232550D01*
 G37*
-G54D17*X200000Y110000D02*X203000D01*
+G54D19*X200000Y110000D02*X203000D01*
 X201500D02*Y104000D01*
-G54D18*G36*
+G54D20*G36*
 X204800Y110000D02*Y104000D01*
 X209300D01*
 Y110000D01*
@@ -1900,10 +1900,10 @@ X541400D01*
 Y110000D01*
 X536900D01*
 G37*
-G54D17*X545000D02*Y104000D01*
+G54D19*X545000D02*Y104000D01*
 Y110000D02*X548000D01*
 X545000Y107300D02*X547250D01*
-G54D18*G36*
+G54D20*G36*
 X549800Y110000D02*Y104000D01*
 X554300D01*
 Y110000D01*
@@ -1963,13 +1963,13 @@ X602900D01*
 Y110000D01*
 X598400D01*
 G37*
-G54D17*X607250D02*Y104000D01*
+G54D19*X607250D02*Y104000D01*
 X609200Y110000D02*X610250Y108950D01*
 Y105050D01*
 X609200Y104000D02*X610250Y105050D01*
 X606500Y104000D02*X609200D01*
 X606500Y110000D02*X609200D01*
-G54D18*G36*
+G54D20*G36*
 X612050D02*Y104000D01*
 X616550D01*
 Y110000D01*
diff --git a/tests/RTT/ref/netlist_ba.gbr/netlist_ba.topmask.gbr b/tests/RTT/ref/netlist_ba.gbr/netlist_ba.topmask.gbr
index 1f85f39..91bbc1c 100644
--- a/tests/RTT/ref/netlist_ba.gbr/netlist_ba.topmask.gbr
+++ b/tests/RTT/ref/netlist_ba.gbr/netlist_ba.topmask.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: board with minimal netlist and some back-annotation changes, TODO:group_name *
+G04 start of page 3 for group 2 layer_idx 0 *
+G04 Title: board with minimal netlist and some back-annotation changes, top mask *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/netlist_ba.nelma.em b/tests/RTT/ref/netlist_ba.nelma.em
new file mode 100644
index 0000000..8e03e9d
--- /dev/null
+++ b/tests/RTT/ref/netlist_ba.nelma.em
@@ -0,0 +1,61 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+net bar {
+	objects = {
+
+	}
+}
+net foo {
+	objects = {
+
+	}
+}
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/netlist_ba.png b/tests/RTT/ref/netlist_ba.png
index 8f68bb1..20c2843 100644
Binary files a/tests/RTT/ref/netlist_ba.png and b/tests/RTT/ref/netlist_ba.png differ
diff --git a/tests/RTT/ref/netlist_ba.png.text b/tests/RTT/ref/netlist_ba.png.text
new file mode 100644
index 0000000..dbefb36
--- /dev/null
+++ b/tests/RTT/ref/netlist_ba.png.text
@@ -0,0 +1,15 @@
+r6630
+
+One component U1
+
+U1 (4pin dip)
+Silk line thickness 12 pix (10)
+Inside silk screen corner to Pin1 top corner 6 x 6 pix (5 x 5 mil)
+Pin1 96 x 96 pix (80 x 80)
+Pin1 hole 47 pix (39.166) in diameter
+Pin2 to Pin1 distance 24 pix (20)
+Pin2 97 pix (80.833) circle
+Pin2 to Pin3 distance 263 pix (219.166)
+Pin2 hole 47 pix (39.166) in diameter
+
+
diff --git a/tests/RTT/ref/netlist_ba.ps.gz b/tests/RTT/ref/netlist_ba.ps.gz
index 6652f28..a7729a2 100644
Binary files a/tests/RTT/ref/netlist_ba.ps.gz and b/tests/RTT/ref/netlist_ba.ps.gz differ
diff --git a/tests/RTT/ref/netlist_ba.remote.gz b/tests/RTT/ref/netlist_ba.remote.gz
index 7a47664..15294f9 100644
Binary files a/tests/RTT/ref/netlist_ba.remote.gz and b/tests/RTT/ref/netlist_ba.remote.gz differ
diff --git a/tests/RTT/ref/netlist_ba.scad b/tests/RTT/ref/netlist_ba.scad
new file mode 100644
index 0000000..845ab1c
--- /dev/null
+++ b/tests/RTT/ref/netlist_ba.scad
@@ -0,0 +1,139 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: plated-drill
+layer_pdrill_list=[
+];
+
+
+// END_OF_LAYER layer_pdrill
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(5.080000,0.254000,0.037500,1.270000,-5.715000,90.000000,1,1,1);
+	line_segment_r(10.160000,0.254000,0.037500,6.350000,-8.255000,0.000000,1,1,1);
+	line_segment_r(5.080000,0.254000,0.037500,11.430000,-5.715000,-90.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,3.175000,-3.175000,180.000000,1,1,1);
+	line_segment_r(3.810000,0.254000,0.037500,9.525000,-3.175000,180.000000,1,1,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.082417,-3.230344,92.499641,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.092064,-3.340610,97.500259,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.111285,-3.449616,102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.139933,-3.556532,107.499977,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.177791,-3.660545,112.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.224569,-3.760862,117.499908,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.279912,-3.856720,122.499672,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.343400,-3.947391,127.500198,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.414549,-4.032183,132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.492817,-4.110450,137.499817,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.577610,-4.181600,142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.668280,-4.245088,147.500046,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,5.764138,-4.300431,152.500092,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,5.864455,-4.347209,157.499954,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,5.968468,-4.385067,162.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.075384,-4.413715,167.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.184390,-4.432936,172.499741,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.294656,-4.442583,177.500366,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.405344,-4.442583,-177.500366,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.515610,-4.432936,-172.499741,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.624617,-4.413715,-167.500031,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,6.731533,-4.385067,-162.500031,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,6.835545,-4.347209,-157.499954,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,6.935862,-4.300431,-152.500092,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.031720,-4.245088,-147.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.122390,-4.181600,-142.500107,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.207182,-4.110450,-137.499817,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.285450,-4.032183,-132.500183,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.356599,-3.947391,-127.499794,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.420087,-3.856721,-122.500381,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.475431,-3.760863,-117.499664,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.522210,-3.660545,-112.500046,1,0,1);
+	line_segment_r(0.110794,0.254000,0.037500,7.560067,-3.556532,-107.499825,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.588715,-3.449615,-102.499977,1,0,1);
+	line_segment_r(0.110793,0.254000,0.037500,7.607936,-3.340610,-97.500320,1,0,1);
+	line_segment_r(0.110792,0.254000,0.037500,7.617583,-3.230344,-92.499641,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,2.540000,-2.349500,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.603500,-2.857500,135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,2.794000,-2.921000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,2.984500,-2.857500,-135.000000,1,1,1);
+	line_segment_r(0.889000,0.177800,0.037500,3.048000,-2.349500,90.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,3.454401,-2.006600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,3.556001,-2.413000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,3.543301,-2.921000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/netlist_ba.svg b/tests/RTT/ref/netlist_ba.svg
index db15ae8..8764b43 100644
--- a/tests/RTT/ref/netlist_ba.svg
+++ b/tests/RTT/ref/netlist_ba.svg
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 <!--normal-->
  <rect x="1.5240" y="3.4290" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -15,7 +15,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 <!--normal-->
  <rect x="1.5240" y="3.4290" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -26,7 +26,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <rect x="1.5240" y="3.4290" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -37,7 +37,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <rect x="1.5240" y="3.4290" width="2.0320" height="2.0320" fill="#4d4d4d" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="1.0160" stroke-width="0.2540" fill="#4d4d4d" stroke="none"/>
@@ -48,14 +48,14 @@
  <circle cx="2.5400" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="6.9850" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="1.2700" y1="3.1750" x2="1.2700" y2="8.2550" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="11.4300" y1="8.2550" x2="1.2700" y2="8.2550" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="11.4300" y1="8.2550" x2="11.4300" y2="3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="1.2700" y1="3.1750" x2="5.0800" y2="3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
  <line x1="7.6200" y1="3.1750" x2="11.4300" y2="3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round"/>
- <path d="M 5.0800 3.1750 A 1.2700 1.2700 0 0 0 7.6200 3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
+ <path d="M 7.62000000 3.17500000 A 1.2700 1.2700 0 0 1 5.0800 3.1750" stroke-width="0.2540" stroke="#000000" stroke-linecap="round" fill="none"/>
  <line x1="2.5400" y1="1.9050" x2="2.5400" y2="2.7940" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="2.5400" y1="2.7940" x2="2.6670" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="2.6670" y1="2.9210" x2="2.9210" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
@@ -65,7 +65,7 @@
  <line x1="3.5560" y1="1.9050" x2="3.5560" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="3.3528" y1="2.9210" x2="3.7338" y2="2.9210" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
 </g>
-<g id="layer_-4048_plated-drill">
+<g id="layer_-1_plated-drill">
 <!--normal-->
  <circle cx="2.5400" cy="4.4450" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="10.1600" cy="4.4450" r="0.5000" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
diff --git a/tests/RTT/ref/poly_hole.bbrd.png b/tests/RTT/ref/poly_hole.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/poly_hole.bbrd.png differ
diff --git a/tests/RTT/ref/poly_hole.dsn b/tests/RTT/ref/poly_hole.dsn
index febe955..458af37 100644
--- a/tests/RTT/ref/poly_hole.dsn
+++ b/tests/RTT/ref/poly_hole.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/poly_hole.eps b/tests/RTT/ref/poly_hole.eps
new file mode 100644
index 0000000..9cb9d26
--- /dev/null
+++ b/tests/RTT/ref/poly_hole.eps
@@ -0,0 +1,112 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: poly_hole.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.06250 0.02500 moveto
+0.12500 0.02500 lineto
+0.06250 0.08750 lineto
+0.06250 0.06250 lineto
+0.07500 0.05000 lineto
+0.06250 0.05000 lineto
+fill
+0.02500 0.02500 moveto
+0.06250 0.02500 lineto
+0.06250 0.05000 lineto
+0.05000 0.05000 lineto
+0.05000 0.07500 lineto
+0.06250 0.06250 lineto
+0.06250 0.08750 lineto
+0.02500 0.12500 lineto
+fill
+0.10000 0.07500 moveto
+0.15000 0.02500 lineto
+0.15000 0.15000 lineto
+0.10000 0.15000 lineto
+0.10000 0.12500 lineto
+0.12500 0.12500 lineto
+0.12500 0.10000 lineto
+0.10000 0.10000 lineto
+fill
+0.02500 0.15000 moveto
+0.10000 0.07500 lineto
+0.10000 0.10000 lineto
+0.07500 0.12500 lineto
+0.10000 0.12500 lineto
+0.10000 0.15000 lineto
+fill
+0.30000 0.02500 moveto
+0.42500 0.15000 lineto
+0.30000 0.15000 lineto
+0.30000 0.12500 lineto
+0.32500 0.12500 lineto
+0.32500 0.07500 lineto
+0.30000 0.07500 lineto
+fill
+0.17500 0.15000 moveto
+0.30000 0.02500 lineto
+0.30000 0.07500 lineto
+0.27500 0.07500 lineto
+0.27500 0.12500 lineto
+0.30000 0.12500 lineto
+0.30000 0.15000 lineto
+fill
+0.16250 0.18750 moveto
+0.30000 0.20000 lineto
+0.16250 0.28250 lineto
+0.16250 0.25000 lineto
+0.17500 0.25000 lineto
+0.17500 0.22500 lineto
+0.16250 0.22500 lineto
+fill
+0.10000 0.18182 moveto
+0.16250 0.18750 lineto
+0.16250 0.22500 lineto
+0.15000 0.22500 lineto
+0.15000 0.25000 lineto
+0.16250 0.25000 lineto
+0.16250 0.28250 lineto
+0.10000 0.32000 lineto
+0.10000 0.30000 lineto
+0.12500 0.27500 lineto
+0.12500 0.25000 lineto
+0.10000 0.22500 lineto
+fill
+0.02500 0.17500 moveto
+0.10000 0.18182 lineto
+0.10000 0.22500 lineto
+0.07500 0.22500 lineto
+0.07500 0.27500 lineto
+0.10000 0.30000 lineto
+0.10000 0.32000 lineto
+0.05000 0.35000 lineto
+fill
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/poly_hole.gbr/poly_hole.fab.gbr b/tests/RTT/ref/poly_hole.gbr/poly_hole.fab.gbr
index 8908930..db95780 100644
--- a/tests/RTT/ref/poly_hole.gbr/poly_hole.fab.gbr
+++ b/tests/RTT/ref/poly_hole.gbr/poly_hole.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Polygons with holes, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Polygons with holes, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/poly_hole.gbr/poly_hole.top.gbr b/tests/RTT/ref/poly_hole.gbr/poly_hole.top.gbr
index 1e6bfa2..a60107b 100644
--- a/tests/RTT/ref/poly_hole.gbr/poly_hole.top.gbr
+++ b/tests/RTT/ref/poly_hole.gbr/poly_hole.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Polygons with holes, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Polygons with holes, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/poly_hole.nelma.em b/tests/RTT/ref/poly_hole.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/poly_hole.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/poly_hole.png b/tests/RTT/ref/poly_hole.png
index dd628dc..8f29219 100644
Binary files a/tests/RTT/ref/poly_hole.png and b/tests/RTT/ref/poly_hole.png differ
diff --git a/tests/RTT/ref/poly_hole.png.text b/tests/RTT/ref/poly_hole.png.text
new file mode 100644
index 0000000..76794ad
--- /dev/null
+++ b/tests/RTT/ref/poly_hole.png.text
@@ -0,0 +1,18 @@
+r6630
+
+500 x 500 mil outline
+
+upper left triangle
+Top left corner to top left cutout corner 30 pixels down 31 pixels over
+cutout 29 pixels (24.166) wide
+cutout 29 pixels (24.166) high
+
+upper right triangle
+bottom right corner to bottom right on cutout 31 x 31 pixels
+cutout 59 pixels (49.167) wide <- this is not a measurement error. we count the edge pixel
+cutout 30 pixels (25) high
+
+far right piramid
+cutout 59 x 60 (49.166 x 50) pixels
+cutout located 60 (50) pixels down from the apex
+
diff --git a/tests/RTT/ref/poly_hole.ps.gz b/tests/RTT/ref/poly_hole.ps.gz
index 7c15916..8e17332 100644
Binary files a/tests/RTT/ref/poly_hole.ps.gz and b/tests/RTT/ref/poly_hole.ps.gz differ
diff --git a/tests/RTT/ref/poly_hole.remote.gz b/tests/RTT/ref/poly_hole.remote.gz
index a0346ff..f993b45 100644
Binary files a/tests/RTT/ref/poly_hole.remote.gz and b/tests/RTT/ref/poly_hole.remote.gz differ
diff --git a/tests/RTT/ref/poly_hole.scad b/tests/RTT/ref/poly_hole.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/poly_hole.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/poly_hole.svg b/tests/RTT/ref/poly_hole.svg
index 7f49d45..118220d 100644
--- a/tests/RTT/ref/poly_hole.svg
+++ b/tests/RTT/ref/poly_hole.svg
@@ -1,16 +1,16 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <polygon points="1.5875,0.6350 3.1750,0.6350 1.5875,2.2225 1.5875,1.5875 1.9050,1.2700 1.5875,1.2700 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <polygon points="0.6350,0.6350 1.5875,0.6350 1.5875,1.2700 1.2700,1.2700 1.2700,1.9050 1.5875,1.5875 1.5875,2.2225 0.6350,3.1750 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
@@ -22,6 +22,6 @@
  <polygon points="2.5400,4.6182 4.1275,4.7625 4.1275,5.7150 3.8100,5.7150 3.8100,6.3500 4.1275,6.3500 4.1275,7.1755 2.5400,8.1280 2.5400,7.6200 3.1750,6.9850 3.1750,6.3500 2.5400,5.7150 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <polygon points="0.6350,4.4450 2.5400,4.6182 2.5400,5.7150 1.9050,5.7150 1.9050,6.9850 2.5400,7.6200 2.5400,8.1280 1.2700,8.8900 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/poly_rect.bbrd.png b/tests/RTT/ref/poly_rect.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/poly_rect.bbrd.png differ
diff --git a/tests/RTT/ref/poly_rect.dsn b/tests/RTT/ref/poly_rect.dsn
index 74a8aa5..17213d6 100644
--- a/tests/RTT/ref/poly_rect.dsn
+++ b/tests/RTT/ref/poly_rect.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/poly_rect.eps b/tests/RTT/ref/poly_rect.eps
new file mode 100644
index 0000000..17ea608
--- /dev/null
+++ b/tests/RTT/ref/poly_rect.eps
@@ -0,0 +1,54 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: poly_rect.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.05000 0.02500 moveto
+0.07500 0.02500 lineto
+0.07500 0.45000 lineto
+0.05000 0.45000 lineto
+fill
+0.12500 0.02500 moveto
+0.47500 0.02500 lineto
+0.47500 0.05000 lineto
+0.12500 0.05000 lineto
+fill
+0.42500 0.42500 moveto
+0.45000 0.42500 lineto
+0.45000 0.45000 lineto
+0.42500 0.45000 lineto
+fill
+0.12500 0.07500 moveto
+0.40000 0.07500 lineto
+0.40000 0.45000 lineto
+0.12500 0.45000 lineto
+fill
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/poly_rect.gbr/poly_rect.fab.gbr b/tests/RTT/ref/poly_rect.gbr/poly_rect.fab.gbr
index f97949e..a6fce81 100644
--- a/tests/RTT/ref/poly_rect.gbr/poly_rect.fab.gbr
+++ b/tests/RTT/ref/poly_rect.gbr/poly_rect.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Normal rectangular polygons, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Normal rectangular polygons, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/poly_rect.gbr/poly_rect.top.gbr b/tests/RTT/ref/poly_rect.gbr/poly_rect.top.gbr
index 4c374e9..269c2dd 100644
--- a/tests/RTT/ref/poly_rect.gbr/poly_rect.top.gbr
+++ b/tests/RTT/ref/poly_rect.gbr/poly_rect.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Normal rectangular polygons, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Normal rectangular polygons, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/poly_rect.nelma.em b/tests/RTT/ref/poly_rect.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/poly_rect.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/poly_rect.png b/tests/RTT/ref/poly_rect.png
index c10d47f..b07c124 100644
Binary files a/tests/RTT/ref/poly_rect.png and b/tests/RTT/ref/poly_rect.png differ
diff --git a/tests/RTT/ref/poly_rect.png.text b/tests/RTT/ref/poly_rect.png.text
new file mode 100644
index 0000000..2e153ca
--- /dev/null
+++ b/tests/RTT/ref/poly_rect.png.text
@@ -0,0 +1,17 @@
+r6630
+
+outline 500 x 500 mils
+
+vertical polygon
+31 x 511 pixels (25.833 x 425.833)
+
+horizontal polygon
+421 x 31 pixels (350.833 x 25.833)
+
+giant middle polygon
+331 x 451 pixels (275.833 x 375.833)
+
+smallest polygon (bottom right)
+31 x 31 pixels (25.833 x 25.833)
+
+
diff --git a/tests/RTT/ref/poly_rect.ps.gz b/tests/RTT/ref/poly_rect.ps.gz
index 6b515a3..7aa8421 100644
Binary files a/tests/RTT/ref/poly_rect.ps.gz and b/tests/RTT/ref/poly_rect.ps.gz differ
diff --git a/tests/RTT/ref/poly_rect.remote.gz b/tests/RTT/ref/poly_rect.remote.gz
index 9757c2d..7e044e5 100644
Binary files a/tests/RTT/ref/poly_rect.remote.gz and b/tests/RTT/ref/poly_rect.remote.gz differ
diff --git a/tests/RTT/ref/poly_rect.scad b/tests/RTT/ref/poly_rect.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/poly_rect.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/poly_rect.svg b/tests/RTT/ref/poly_rect.svg
index f8abece..f6934a1 100644
--- a/tests/RTT/ref/poly_rect.svg
+++ b/tests/RTT/ref/poly_rect.svg
@@ -1,22 +1,22 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <polygon points="1.2700,0.6350 1.9050,0.6350 1.9050,11.4300 1.2700,11.4300 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <polygon points="3.1750,0.6350 12.0650,0.6350 12.0650,1.2700 3.1750,1.2700 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <polygon points="10.7950,10.7950 11.4300,10.7950 11.4300,11.4300 10.7950,11.4300 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <polygon points="3.1750,1.9050 10.1600,1.9050 10.1600,11.4300 3.1750,11.4300 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/poly_triangle.bbrd.png b/tests/RTT/ref/poly_triangle.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/poly_triangle.bbrd.png differ
diff --git a/tests/RTT/ref/poly_triangle.dsn b/tests/RTT/ref/poly_triangle.dsn
index cdd0bf8..9e2c26f 100644
--- a/tests/RTT/ref/poly_triangle.dsn
+++ b/tests/RTT/ref/poly_triangle.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/poly_triangle.eps b/tests/RTT/ref/poly_triangle.eps
new file mode 100644
index 0000000..45b6e39
--- /dev/null
+++ b/tests/RTT/ref/poly_triangle.eps
@@ -0,0 +1,50 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: poly_triangle.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.545098 0.137255 0.137255 setrgbcolor
+0.02500 0.02500 moveto
+0.12500 0.02500 lineto
+0.02500 0.12500 lineto
+fill
+0.02500 0.15000 moveto
+0.15000 0.02500 lineto
+0.15000 0.15000 lineto
+fill
+0.17500 0.15000 moveto
+0.30000 0.02500 lineto
+0.42500 0.15000 lineto
+fill
+0.02500 0.17500 moveto
+0.30000 0.20000 lineto
+0.05000 0.35000 lineto
+fill
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/poly_triangle.gbr/poly_triangle.fab.gbr b/tests/RTT/ref/poly_triangle.gbr/poly_triangle.fab.gbr
index 33befd8..b616367 100644
--- a/tests/RTT/ref/poly_triangle.gbr/poly_triangle.fab.gbr
+++ b/tests/RTT/ref/poly_triangle.gbr/poly_triangle.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: Normal triangular polygons, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: Normal triangular polygons, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/poly_triangle.gbr/poly_triangle.top.gbr b/tests/RTT/ref/poly_triangle.gbr/poly_triangle.top.gbr
index 8afed97..fcaecc0 100644
--- a/tests/RTT/ref/poly_triangle.gbr/poly_triangle.top.gbr
+++ b/tests/RTT/ref/poly_triangle.gbr/poly_triangle.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: Normal triangular polygons, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: Normal triangular polygons, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/poly_triangle.nelma.em b/tests/RTT/ref/poly_triangle.nelma.em
new file mode 100644
index 0000000..ef73a4f
--- /dev/null
+++ b/tests/RTT/ref/poly_triangle.nelma.em
@@ -0,0 +1,60 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top"
+	}
+}
diff --git a/tests/RTT/ref/poly_triangle.png b/tests/RTT/ref/poly_triangle.png
index f1464e1..d7dd366 100644
Binary files a/tests/RTT/ref/poly_triangle.png and b/tests/RTT/ref/poly_triangle.png differ
diff --git a/tests/RTT/ref/poly_triangle.png.text b/tests/RTT/ref/poly_triangle.png.text
index 93d4e43..35e0f3e 100644
--- a/tests/RTT/ref/poly_triangle.png.text
+++ b/tests/RTT/ref/poly_triangle.png.text
@@ -1,31 +1,33 @@
+r6630
 
 upper left triangle
-121 pixels wide
-121 pixels tall
+121 pixels (100.833) wide
+121 pixels (100.83) tall
 
 gap from lower left triangle to upper left triangle
-29 pixels horizontally
-29 pixels vertically
+29 pixels (24.166) horizontally
+29 pixels (24.166) vertically
 
 lower left triangle
-151 pixels wide
-151 pixels tall
+151 pixels (125.833) wide
+151 pixels (125.833) tall
 
 gap from lower left triangle to far right piramid
-29 pixels
+29 pixels (24.166)
 
 far right piramid
-151 pixels height
-301 pixels base
+151 pixels (125.833) height
+301 pixels (250.833) base
 
 bottom triangle
-331 pixels across
-211 pixels up
+331 pixels (275.833) across
+211 pixels (175.833) up
 top edge
-332.4 pixels long 5.18 degrees
+332.4 pixels (277) long 5.18 degrees
 side edge
-213.1 pixels long 91.91 degrees
+213.1 pixels (177.5833) long 91.91 degrees
 bottom edge
-351.2 pixels long 31.02 degrees
+351.2 pixels (292.666) long 31.02 degrees
 
+(mil)
 
diff --git a/tests/RTT/ref/poly_triangle.ps.gz b/tests/RTT/ref/poly_triangle.ps.gz
index 49a2b22..ff4921d 100644
Binary files a/tests/RTT/ref/poly_triangle.ps.gz and b/tests/RTT/ref/poly_triangle.ps.gz differ
diff --git a/tests/RTT/ref/poly_triangle.remote.gz b/tests/RTT/ref/poly_triangle.remote.gz
index 2b7aa12..1984700 100644
Binary files a/tests/RTT/ref/poly_triangle.remote.gz and b/tests/RTT/ref/poly_triangle.remote.gz differ
diff --git a/tests/RTT/ref/poly_triangle.scad b/tests/RTT/ref/poly_triangle.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/poly_triangle.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/poly_triangle.svg b/tests/RTT/ref/poly_triangle.svg
index 138453e..b982042 100644
--- a/tests/RTT/ref/poly_triangle.svg
+++ b/tests/RTT/ref/poly_triangle.svg
@@ -1,22 +1,22 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <polygon points="0.6350,0.6350 3.1750,0.6350 0.6350,3.1750 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <polygon points="0.6350,3.8100 3.8100,0.6350 3.8100,3.8100 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <polygon points="4.4450,3.8100 7.6200,0.6350 10.7950,3.8100 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
  <polygon points="0.6350,4.4450 7.6200,5.0800 1.2700,8.8900 " stroke-width="0.075" stroke="#8b2323" fill="#8b2323"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/rat.bbrd.png b/tests/RTT/ref/rat.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/rat.bbrd.png differ
diff --git a/tests/RTT/ref/rat.dsn b/tests/RTT/ref/rat.dsn
index 784636f..0891a93 100644
--- a/tests/RTT/ref/rat.dsn
+++ b/tests/RTT/ref/rat.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/rat.eps b/tests/RTT/ref/rat.eps
new file mode 100644
index 0000000..d85db70
--- /dev/null
+++ b/tests/RTT/ref/rat.eps
@@ -0,0 +1,31 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: rat.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/rat.gbr/rat.fab.gbr b/tests/RTT/ref/rat.gbr/rat.fab.gbr
index a7fbbeb..f1d3597 100644
--- a/tests/RTT/ref/rat.gbr/rat.fab.gbr
+++ b/tests/RTT/ref/rat.gbr/rat.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group -1 layer_idx -1 *
-G04 Title: a rat line, TODO:group_name *
+G04 start of page 2 for group -1 layer_idx 16777221 *
+G04 Title: a rat line, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/rat.nelma.em b/tests/RTT/ref/rat.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/rat.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/rat.png b/tests/RTT/ref/rat.png
index 852eb60..673e79f 100644
Binary files a/tests/RTT/ref/rat.png and b/tests/RTT/ref/rat.png differ
diff --git a/tests/RTT/ref/rat.png.text b/tests/RTT/ref/rat.png.text
new file mode 100644
index 0000000..798e8ce
--- /dev/null
+++ b/tests/RTT/ref/rat.png.text
@@ -0,0 +1,6 @@
+r6731
+
+outline thickness 6 x 7 pixels (top/left) (5/5.833)
+
+outline (inside lines) 587 x 589 pixels (489.167 x 490.833)
+
diff --git a/tests/RTT/ref/rat.ps.gz b/tests/RTT/ref/rat.ps.gz
index 0a9d0ae..73506b4 100644
Binary files a/tests/RTT/ref/rat.ps.gz and b/tests/RTT/ref/rat.ps.gz differ
diff --git a/tests/RTT/ref/rat.remote.gz b/tests/RTT/ref/rat.remote.gz
index c2b9853..969022b 100644
Binary files a/tests/RTT/ref/rat.remote.gz and b/tests/RTT/ref/rat.remote.gz differ
diff --git a/tests/RTT/ref/rat.scad b/tests/RTT/ref/rat.scad
new file mode 100644
index 0000000..fa3be87
--- /dev/null
+++ b/tests/RTT/ref/rat.scad
@@ -0,0 +1,83 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/rat.svg b/tests/RTT/ref/rat.svg
index 6ac2399..a483669 100644
--- a/tests/RTT/ref/rat.svg
+++ b/tests/RTT/ref/rat.svg
@@ -1,17 +1,17 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
 </svg>
diff --git a/tests/RTT/ref/text_rot.bbrd.png b/tests/RTT/ref/text_rot.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/text_rot.bbrd.png differ
diff --git a/tests/RTT/ref/text_rot.dsn b/tests/RTT/ref/text_rot.dsn
index 36a7164..1924dbc 100644
--- a/tests/RTT/ref/text_rot.dsn
+++ b/tests/RTT/ref/text_rot.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/text_rot.eps b/tests/RTT/ref/text_rot.eps
new file mode 100644
index 0000000..9291332
--- /dev/null
+++ b/tests/RTT/ref/text_rot.eps
@@ -0,0 +1,81 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: text_rot.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+% Layer topsilk group 1 drill 0 mask 0
+0.00700 setlinewidth
+1 setlinecap
+0 0 0 setrgbcolor
+0.22500 0.16000 0.22500 0.19000 t
+0.22500 0.16000 0.23200 0.15000 t
+0.23200 0.15000 0.24300 0.15000 t
+0.24300 0.15000 0.25000 0.16000 t
+0.25000 0.16000 0.25000 0.19000 t
+0.22500 0.17000 0.25000 0.17000 t
+0.26200 0.15800 0.27000 0.15000 t
+0.27000 0.15000 0.27000 0.19000 t
+0.26200 0.19000 0.27700 0.19000 t
+0.16000 0.27500 0.19000 0.27500 t
+0.16000 0.27500 0.15000 0.26800 t
+0.15000 0.25700 0.15000 0.26800 t
+0.15000 0.25700 0.16000 0.25000 t
+0.16000 0.25000 0.19000 0.25000 t
+0.17000 0.25000 0.17000 0.27500 t
+0.15500 0.23800 0.15000 0.23300 t
+0.15000 0.21800 0.15000 0.23300 t
+0.15000 0.21800 0.15500 0.21300 t
+0.15500 0.21300 0.16500 0.21300 t
+0.19000 0.23800 0.16500 0.21300 t
+0.19000 0.21300 0.19000 0.23800 t
+0.27500 0.31000 0.27500 0.34000 t
+0.27500 0.34000 0.26800 0.35000 t
+0.25700 0.35000 0.26800 0.35000 t
+0.25700 0.35000 0.25000 0.34000 t
+0.25000 0.31000 0.25000 0.34000 t
+0.25000 0.33000 0.27500 0.33000 t
+0.23800 0.34500 0.23300 0.35000 t
+0.22300 0.35000 0.23300 0.35000 t
+0.22300 0.35000 0.21800 0.34500 t
+0.22300 0.31000 0.21800 0.31500 t
+0.22300 0.31000 0.23300 0.31000 t
+0.23800 0.31500 0.23300 0.31000 t
+0.22300 0.33200 0.23300 0.33200 t
+0.21800 0.33700 0.21800 0.34500 t
+0.21800 0.31500 0.21800 0.32700 t
+0.21800 0.32700 0.22300 0.33200 t
+0.21800 0.33700 0.22300 0.33200 t
+0.31000 0.22500 0.34000 0.22500 t
+0.34000 0.22500 0.35000 0.23200 t
+0.35000 0.23200 0.35000 0.24300 t
+0.35000 0.24300 0.34000 0.25000 t
+0.31000 0.25000 0.34000 0.25000 t
+0.33000 0.22500 0.33000 0.25000 t
+0.32500 0.26200 0.35000 0.28200 t
+0.32500 0.26200 0.32500 0.28700 t
+0.31000 0.28200 0.35000 0.28200 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/text_rot.gbr/text_rot.fab.gbr b/tests/RTT/ref/text_rot.gbr/text_rot.fab.gbr
index c31989b..1490a92 100644
--- a/tests/RTT/ref/text_rot.gbr/text_rot.fab.gbr
+++ b/tests/RTT/ref/text_rot.gbr/text_rot.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: text rotations, TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: text rotations, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/text_rot.gbr/text_rot.topsilk.gbr b/tests/RTT/ref/text_rot.gbr/text_rot.topsilk.gbr
index e5e44fe..b547133 100644
--- a/tests/RTT/ref/text_rot.gbr/text_rot.topsilk.gbr
+++ b/tests/RTT/ref/text_rot.gbr/text_rot.topsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 8 *
-G04 Title: text rotations, TODO:group_name *
+G04 start of page 2 for group 1 layer_idx 8 *
+G04 Title: text rotations, top silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/text_rot.nelma.em b/tests/RTT/ref/text_rot.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/text_rot.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/text_rot.png b/tests/RTT/ref/text_rot.png
index 78335a2..800bc0b 100644
Binary files a/tests/RTT/ref/text_rot.png and b/tests/RTT/ref/text_rot.png differ
diff --git a/tests/RTT/ref/text_rot.png.text b/tests/RTT/ref/text_rot.png.text
new file mode 100644
index 0000000..e475f15
--- /dev/null
+++ b/tests/RTT/ref/text_rot.png.text
@@ -0,0 +1,13 @@
+r6731
+
+A's are all 8 pixels thick
+1 8 (6.67) pixels thick
+2 8 pixels thick
+3 8 pixels thick
+4 8 pixels thick
+
+All text is spaced @ 6 pixels (5)
+
+136 pixels (113.333) from under A2 to under A4
+136 pixels from under A1 to under A3
+
diff --git a/tests/RTT/ref/text_rot.ps.gz b/tests/RTT/ref/text_rot.ps.gz
index dedbdb1..61bea2a 100644
Binary files a/tests/RTT/ref/text_rot.ps.gz and b/tests/RTT/ref/text_rot.ps.gz differ
diff --git a/tests/RTT/ref/text_rot.remote.gz b/tests/RTT/ref/text_rot.remote.gz
index 58794d1..6a11c99 100644
Binary files a/tests/RTT/ref/text_rot.remote.gz and b/tests/RTT/ref/text_rot.remote.gz differ
diff --git a/tests/RTT/ref/text_rot.scad b/tests/RTT/ref/text_rot.scad
new file mode 100644
index 0000000..adeb376
--- /dev/null
+++ b/tests/RTT/ref/text_rot.scad
@@ -0,0 +1,130 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(0.762000,0.177800,0.037500,5.715000,-4.445000,90.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,5.803900,-3.937000,-124.992020,1,1,1);
+	line_segment_r(0.279400,0.177800,0.037500,6.032500,-3.810000,180.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,6.261100,-3.937000,124.992020,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,6.350000,-4.445000,90.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,6.032500,-4.318000,180.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,6.756401,-3.911600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,6.858001,-4.318000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,6.845301,-4.826000,180.000000,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,4.445000,-6.985000,180.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,3.937000,-6.896100,-34.992020,1,1,1);
+	line_segment_r(0.279400,0.177800,0.037500,3.810000,-6.667500,90.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,3.937000,-6.438900,-145.007980,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,4.445000,-6.350000,180.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,4.318000,-6.667500,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,3.873500,-5.981699,-45.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,3.810000,-5.727699,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,3.873500,-5.473699,-135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,4.064000,-5.410199,180.000000,1,1,1);
+	line_segment_r(0.898026,0.177800,0.037500,4.508500,-5.727699,-45.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,4.826000,-5.727699,90.000000,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,6.985000,-8.255000,90.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,6.896100,-8.763000,55.007980,1,1,1);
+	line_segment_r(0.279400,0.177800,0.037500,6.667500,-8.890000,180.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,6.438900,-8.763000,-55.007980,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,6.350000,-8.255000,90.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,6.667500,-8.382000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,5.981699,-8.826500,45.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,5.791199,-8.890000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,5.600699,-8.826500,-45.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,5.600699,-7.937500,45.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,5.791199,-7.874000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,5.981699,-7.937500,-45.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,5.791199,-8.432800,180.000000,1,1,1);
+	line_segment_r(0.203200,0.177800,0.037500,5.537199,-8.661400,90.000000,1,1,1);
+	line_segment_r(0.304800,0.177800,0.037500,5.537199,-8.153400,90.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,5.600699,-8.369300,135.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,5.600699,-8.496300,-135.000000,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,8.255000,-5.715000,180.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,8.763000,-5.803900,145.007980,1,1,1);
+	line_segment_r(0.279400,0.177800,0.037500,8.890000,-6.032500,90.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,8.763000,-6.261100,34.992020,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,8.255000,-6.350000,180.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,8.382000,-6.032500,90.000000,1,1,1);
+	line_segment_r(0.813197,0.177800,0.037500,8.572500,-6.908801,141.340195,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,8.255000,-6.972301,90.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,8.382000,-7.162801,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/text_rot.svg b/tests/RTT/ref/text_rot.svg
index 587caae..1d536a0 100644
--- a/tests/RTT/ref/text_rot.svg
+++ b/tests/RTT/ref/text_rot.svg
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="5.7150" y1="4.0640" x2="5.7150" y2="4.8260" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="5.7150" y1="4.0640" x2="5.8928" y2="3.8100" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
diff --git a/tests/RTT/ref/text_scale.bbrd.png b/tests/RTT/ref/text_scale.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/text_scale.bbrd.png differ
diff --git a/tests/RTT/ref/text_scale.dsn b/tests/RTT/ref/text_scale.dsn
index 1b0ee22..7388c6e 100644
--- a/tests/RTT/ref/text_scale.dsn
+++ b/tests/RTT/ref/text_scale.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/text_scale.eps b/tests/RTT/ref/text_scale.eps
new file mode 100644
index 0000000..8d888c9
--- /dev/null
+++ b/tests/RTT/ref/text_scale.eps
@@ -0,0 +1,73 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: text_scale.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+% Layer topsilk group 1 drill 0 mask 0
+0.00700 setlinewidth
+1 setlinecap
+0 0 0 setrgbcolor
+0.05000 0.03500 0.05000 0.06500 t
+0.05000 0.03500 0.05700 0.02500 t
+0.05700 0.02500 0.06800 0.02500 t
+0.06800 0.02500 0.07500 0.03500 t
+0.07500 0.03500 0.07500 0.06500 t
+0.05000 0.04500 0.07500 0.04500 t
+0.08700 0.03300 0.09500 0.02500 t
+0.09500 0.02500 0.09500 0.06500 t
+0.08700 0.06500 0.10200 0.06500 t
+0.05000 0.20100 0.05000 0.20400 t
+0.05000 0.20100 0.05070 0.20000 t
+0.05070 0.20000 0.05180 0.20000 t
+0.05180 0.20000 0.05250 0.20100 t
+0.05250 0.20100 0.05250 0.20400 t
+0.05000 0.20200 0.05250 0.20200 t
+0.05370 0.20050 0.05420 0.20000 t
+0.05420 0.20000 0.05570 0.20000 t
+0.05570 0.20000 0.05620 0.20050 t
+0.05620 0.20050 0.05620 0.20150 t
+0.05370 0.20400 0.05620 0.20150 t
+0.05370 0.20400 0.05620 0.20400 t
+0.01280 setlinewidth
+0.05000 0.33200 0.05000 0.42800 t
+0.05000 0.33200 0.07240 0.30000 t
+0.07240 0.30000 0.10760 0.30000 t
+0.10760 0.30000 0.13000 0.33200 t
+0.13000 0.33200 0.13000 0.42800 t
+0.05000 0.36400 0.13000 0.36400 t
+0.16840 0.31600 0.18440 0.30000 t
+0.18440 0.30000 0.21640 0.30000 t
+0.21640 0.30000 0.23240 0.31600 t
+0.21640 0.42800 0.23240 0.41200 t
+0.18440 0.42800 0.21640 0.42800 t
+0.16840 0.41200 0.18440 0.42800 t
+0.18440 0.35760 0.21640 0.35760 t
+0.23240 0.31600 0.23240 0.34160 t
+0.23240 0.37360 0.23240 0.41200 t
+0.23240 0.37360 0.21640 0.35760 t
+0.23240 0.34160 0.21640 0.35760 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/text_scale.gbr/text_scale.fab.gbr b/tests/RTT/ref/text_scale.gbr/text_scale.fab.gbr
index 2f0d1e0..b90254f 100644
--- a/tests/RTT/ref/text_scale.gbr/text_scale.fab.gbr
+++ b/tests/RTT/ref/text_scale.gbr/text_scale.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group -1 layer_idx -1 *
-G04 Title: text sizes (scales), TODO:group_name *
+G04 start of page 3 for group -1 layer_idx 16777221 *
+G04 Title: text sizes (scales), <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/text_scale.gbr/text_scale.topsilk.gbr b/tests/RTT/ref/text_scale.gbr/text_scale.topsilk.gbr
index 783eee5..73507eb 100644
--- a/tests/RTT/ref/text_scale.gbr/text_scale.topsilk.gbr
+++ b/tests/RTT/ref/text_scale.gbr/text_scale.topsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 8 *
-G04 Title: text sizes (scales), TODO:group_name *
+G04 start of page 2 for group 1 layer_idx 8 *
+G04 Title: text sizes (scales), top silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/text_scale.nelma.em b/tests/RTT/ref/text_scale.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/text_scale.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/text_scale.png b/tests/RTT/ref/text_scale.png
index 7f8e38b..621040f 100644
Binary files a/tests/RTT/ref/text_scale.png and b/tests/RTT/ref/text_scale.png differ
diff --git a/tests/RTT/ref/text_scale.png.text b/tests/RTT/ref/text_scale.png.text
index 4e3d99e..1136250 100644
--- a/tests/RTT/ref/text_scale.png.text
+++ b/tests/RTT/ref/text_scale.png.text
@@ -1,23 +1,23 @@
 
 top text A1
-A line width 8 pixels
-A width 38 pixels
-A height 56 pixels
-1 line width 8 pixels
-1 width 26 pixels
-1 height 56 pixels
+A line width 8 (6.666) pixels
+A width 38 pixels (31.666)
+A height 56 pixels (46.666)
+1 line width 8 pixels (6.666)
+1 width 26 pixels (21.666)
+1 height 56 pixels (46.666)
 
-gap from A to 1 is 7 pixels
+gap from A to 1 is 6 pixels (5)
 
 dot thing in the page
-13 pixels tall
-16 pixels wide
+13 pixels (10.833) tall
+15 pixels (12.5) wide
 
 bottom text A3 
-A line width 15 pixels
-A width 111 pixels
-A height 173 pixels
-3 line width 15 pixels
-3 width 91 pixels
-3 height 169 pixels
+A line width 15 pixels (12.5)
+A width 111 pixels (92.5)
+A height 169 pixels (140.833)
+3 line width 15 pixels (12.5)
+3 width 92 pixels (75.833)
+3 height 169 pixels (140.833)
 
diff --git a/tests/RTT/ref/text_scale.ps.gz b/tests/RTT/ref/text_scale.ps.gz
index 8045b28..65e2ca9 100644
Binary files a/tests/RTT/ref/text_scale.ps.gz and b/tests/RTT/ref/text_scale.ps.gz differ
diff --git a/tests/RTT/ref/text_scale.remote.gz b/tests/RTT/ref/text_scale.remote.gz
index eab86be..ed9d730 100644
Binary files a/tests/RTT/ref/text_scale.remote.gz and b/tests/RTT/ref/text_scale.remote.gz differ
diff --git a/tests/RTT/ref/text_scale.scad b/tests/RTT/ref/text_scale.scad
new file mode 100644
index 0000000..0a6c44d
--- /dev/null
+++ b/tests/RTT/ref/text_scale.scad
@@ -0,0 +1,121 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(0.762000,0.177800,0.037500,1.270000,-1.270000,90.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,1.358900,-0.762000,-124.992020,1,1,1);
+	line_segment_r(0.279400,0.177800,0.037500,1.587500,-0.635000,180.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,1.816100,-0.762000,124.992020,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,1.905000,-1.270000,90.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,1.587500,-1.143000,180.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,2.311401,-0.736600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,2.413001,-1.143000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,2.400301,-1.651000,180.000000,1,1,1);
+	line_segment_r(0.076200,0.177800,0.037500,1.270000,-5.143500,90.000000,1,1,1);
+	line_segment_r(0.031005,0.177800,0.037500,1.278890,-5.092700,-124.992020,1,1,1);
+	line_segment_r(0.027940,0.177800,0.037500,1.301750,-5.080000,180.000000,1,1,1);
+	line_segment_r(0.031005,0.177800,0.037500,1.324610,-5.092700,124.992020,1,1,1);
+	line_segment_r(0.076200,0.177800,0.037500,1.333500,-5.143500,90.000000,1,1,1);
+	line_segment_r(0.063500,0.177800,0.037500,1.301750,-5.130800,180.000000,1,1,1);
+	line_segment_r(0.017961,0.177800,0.037500,1.370330,-5.086350,-135.000000,1,1,1);
+	line_segment_r(0.038100,0.177800,0.037500,1.395730,-5.080000,180.000000,1,1,1);
+	line_segment_r(0.017961,0.177800,0.037500,1.421130,-5.086350,135.000000,1,1,1);
+	line_segment_r(0.025400,0.177800,0.037500,1.427480,-5.105400,90.000000,1,1,1);
+	line_segment_r(0.089803,0.177800,0.037500,1.395730,-5.149850,-135.000000,1,1,1);
+	line_segment_r(0.063500,0.177800,0.037500,1.395730,-5.181600,180.000000,1,1,1);
+	line_segment_r(2.438400,0.325120,0.037500,1.270000,-9.652000,90.000000,1,1,1);
+	line_segment_r(0.992149,0.325120,0.037500,1.554480,-8.026400,-124.992020,1,1,1);
+	line_segment_r(0.894080,0.325120,0.037500,2.286000,-7.620000,180.000000,1,1,1);
+	line_segment_r(0.992149,0.325120,0.037500,3.017520,-8.026400,124.992020,1,1,1);
+	line_segment_r(2.438400,0.325120,0.037500,3.302000,-9.652000,90.000000,1,1,1);
+	line_segment_r(2.032000,0.325120,0.037500,2.286000,-9.245600,180.000000,1,1,1);
+	line_segment_r(0.574736,0.325120,0.037500,4.480563,-7.823200,-135.000000,1,1,1);
+	line_segment_r(0.812800,0.325120,0.037500,5.090163,-7.620000,180.000000,1,1,1);
+	line_segment_r(0.574736,0.325120,0.037500,5.699763,-7.823200,135.000000,1,1,1);
+	line_segment_r(0.574736,0.325120,0.037500,5.699763,-10.668000,-135.000000,1,1,1);
+	line_segment_r(0.812800,0.325120,0.037500,5.090163,-10.871200,180.000000,1,1,1);
+	line_segment_r(0.574736,0.325120,0.037500,4.480563,-10.668000,135.000000,1,1,1);
+	line_segment_r(0.812800,0.325120,0.037500,5.090163,-9.083040,180.000000,1,1,1);
+	line_segment_r(0.650240,0.325120,0.037500,5.902963,-8.351520,90.000000,1,1,1);
+	line_segment_r(0.975360,0.325120,0.037500,5.902963,-9.977120,90.000000,1,1,1);
+	line_segment_r(0.574736,0.325120,0.037500,5.699763,-9.286240,-45.000000,1,1,1);
+	line_segment_r(0.574736,0.325120,0.037500,5.699763,-8.879840,45.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/text_scale.svg b/tests/RTT/ref/text_scale.svg
index df07e76..650e96e 100644
--- a/tests/RTT/ref/text_scale.svg
+++ b/tests/RTT/ref/text_scale.svg
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="1.2700" y1="0.8890" x2="1.2700" y2="1.6510" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="1.2700" y1="0.8890" x2="1.4478" y2="0.6350" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
diff --git a/tests/RTT/ref/text_sides.bbrd.png b/tests/RTT/ref/text_sides.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/text_sides.bbrd.png differ
diff --git a/tests/RTT/ref/text_sides.dsn b/tests/RTT/ref/text_sides.dsn
index 484c1a7..7c3a358 100644
--- a/tests/RTT/ref/text_sides.dsn
+++ b/tests/RTT/ref/text_sides.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
diff --git a/tests/RTT/ref/text_sides.eps b/tests/RTT/ref/text_sides.eps
new file mode 100644
index 0000000..9df6649
--- /dev/null
+++ b/tests/RTT/ref/text_sides.eps
@@ -0,0 +1,43 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: text_sides.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+% Layer group5 group 5 drill 0 mask 0
+% Layer group7 group 7 drill 0 mask 0
+% Layer top group 3 drill 0 mask 0
+% Layer topsilk group 1 drill 0 mask 0
+0.00700 setlinewidth
+1 setlinecap
+0 0 0 setrgbcolor
+0.22500 0.18500 0.22500 0.21500 t
+0.22500 0.18500 0.23200 0.17500 t
+0.23200 0.17500 0.24300 0.17500 t
+0.24300 0.17500 0.25000 0.18500 t
+0.25000 0.18500 0.25000 0.21500 t
+0.22500 0.19500 0.25000 0.19500 t
+0.26200 0.18300 0.27000 0.17500 t
+0.27000 0.17500 0.27000 0.21500 t
+0.26200 0.21500 0.27700 0.21500 t
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/text_sides.gbr/text_sides.bottomsilk.gbr b/tests/RTT/ref/text_sides.gbr/text_sides.bottomsilk.gbr
index 0fea6f0..a918b8d 100644
--- a/tests/RTT/ref/text_sides.gbr/text_sides.bottomsilk.gbr
+++ b/tests/RTT/ref/text_sides.gbr/text_sides.bottomsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group 1 layer_idx 7 *
-G04 Title: text on both sides, TODO:group_name *
+G04 start of page 3 for group 12 layer_idx 7 *
+G04 Title: text on both sides, bottom silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/text_sides.gbr/text_sides.fab.gbr b/tests/RTT/ref/text_sides.gbr/text_sides.fab.gbr
index 6372d54..102467e 100644
--- a/tests/RTT/ref/text_sides.gbr/text_sides.fab.gbr
+++ b/tests/RTT/ref/text_sides.gbr/text_sides.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 4 for group -1 layer_idx -1 *
-G04 Title: text on both sides, TODO:group_name *
+G04 start of page 4 for group -1 layer_idx 16777221 *
+G04 Title: text on both sides, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/text_sides.gbr/text_sides.topsilk.gbr b/tests/RTT/ref/text_sides.gbr/text_sides.topsilk.gbr
index 2f4d9c2..ea980c0 100644
--- a/tests/RTT/ref/text_sides.gbr/text_sides.topsilk.gbr
+++ b/tests/RTT/ref/text_sides.gbr/text_sides.topsilk.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 8 *
-G04 Title: text on both sides, TODO:group_name *
+G04 start of page 2 for group 1 layer_idx 8 *
+G04 Title: text on both sides, top silk *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/text_sides.nelma.em b/tests/RTT/ref/text_sides.nelma.em
new file mode 100644
index 0000000..6f3fa01
--- /dev/null
+++ b/tests/RTT/ref/text_sides.nelma.em
@@ -0,0 +1,51 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom"
+	}
+}
diff --git a/tests/RTT/ref/text_sides.png b/tests/RTT/ref/text_sides.png
index 3d8dbef..3973cc2 100644
Binary files a/tests/RTT/ref/text_sides.png and b/tests/RTT/ref/text_sides.png differ
diff --git a/tests/RTT/ref/text_sides.png.text b/tests/RTT/ref/text_sides.png.text
new file mode 100644
index 0000000..54bf20b
--- /dev/null
+++ b/tests/RTT/ref/text_sides.png.text
@@ -0,0 +1,8 @@
+r6731
+
+??? between the bottom of A1 and bottom of A2
+(underside text is missing in png file!)
+
+all text is 8 pixels thick (6.666)
+
+(mil)
diff --git a/tests/RTT/ref/text_sides.ps.gz b/tests/RTT/ref/text_sides.ps.gz
index 2e4b300..b04b8a5 100644
Binary files a/tests/RTT/ref/text_sides.ps.gz and b/tests/RTT/ref/text_sides.ps.gz differ
diff --git a/tests/RTT/ref/text_sides.remote.gz b/tests/RTT/ref/text_sides.remote.gz
index f013a5c..8aac29e 100644
Binary files a/tests/RTT/ref/text_sides.remote.gz and b/tests/RTT/ref/text_sides.remote.gz differ
diff --git a/tests/RTT/ref/text_sides.scad b/tests/RTT/ref/text_sides.scad
new file mode 100644
index 0000000..aa052cd
--- /dev/null
+++ b/tests/RTT/ref/text_sides.scad
@@ -0,0 +1,104 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(0.762000,0.177800,0.037500,5.715000,-5.080000,90.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,5.803900,-4.572000,-124.992020,1,1,1);
+	line_segment_r(0.279400,0.177800,0.037500,6.032500,-4.445000,180.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,6.261100,-4.572000,124.992020,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,6.350000,-5.080000,90.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,6.032500,-4.953000,180.000000,1,1,1);
+	line_segment_r(0.287368,0.177800,0.037500,6.756401,-4.546600,-135.000000,1,1,1);
+	line_segment_r(1.016000,0.177800,0.037500,6.858001,-4.953000,90.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,6.845301,-5.461000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+	line_segment_r(0.762000,0.177800,0.037500,5.715000,-6.985000,-90.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,5.803900,-7.493000,124.992020,1,1,1);
+	line_segment_r(0.279400,0.177800,0.037500,6.032500,-7.620000,180.000000,1,1,1);
+	line_segment_r(0.310046,0.177800,0.037500,6.261100,-7.493000,-124.992020,1,1,1);
+	line_segment_r(0.762000,0.177800,0.037500,6.350000,-6.985000,-90.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,6.032500,-7.112000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,6.718301,-7.556500,135.000000,1,1,1);
+	line_segment_r(0.381000,0.177800,0.037500,6.972301,-7.620000,180.000000,1,1,1);
+	line_segment_r(0.179605,0.177800,0.037500,7.226301,-7.556500,-135.000000,1,1,1);
+	line_segment_r(0.254000,0.177800,0.037500,7.289801,-7.366000,-90.000000,1,1,1);
+	line_segment_r(0.898026,0.177800,0.037500,6.972301,-6.921500,135.000000,1,1,1);
+	line_segment_r(0.635000,0.177800,0.037500,6.972301,-6.604000,180.000000,1,1,1);
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/text_sides.svg b/tests/RTT/ref/text_sides.svg
index 49f2538..14e376a 100644
--- a/tests/RTT/ref/text_sides.svg
+++ b/tests/RTT/ref/text_sides.svg
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 <!--normal-->
  <line x1="5.7150" y1="4.6990" x2="5.7150" y2="5.4610" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
  <line x1="5.7150" y1="4.6990" x2="5.8928" y2="4.4450" stroke-width="0.1778" stroke="#000000" stroke-linecap="round"/>
diff --git a/tests/RTT/ref/thermal_last.bbrd.png b/tests/RTT/ref/thermal_last.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/thermal_last.bbrd.png differ
diff --git a/tests/RTT/ref/thermal_last.dsn b/tests/RTT/ref/thermal_last.dsn
index 2cd40da..48dd9ee 100644
--- a/tests/RTT/ref/thermal_last.dsn
+++ b/tests/RTT/ref/thermal_last.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,12 +33,12 @@
     )
   )
   (placement
-    (component 5
-      (place 5 2.540000 10.160000 front 0 (PN 0))
+    (component 6
+      (place 6 2.540000 10.160000 front 0 (PN 0))
     )
   )
   (library
-    (image 5
+    (image 6
       (pin Th_round_3015995 1 0 0)
     )
     (padstack Th_round_3015995
diff --git a/tests/RTT/ref/thermal_last.eps b/tests/RTT/ref/thermal_last.eps
new file mode 100644
index 0000000..4f1a258
--- /dev/null
+++ b/tests/RTT/ref/thermal_last.eps
@@ -0,0 +1,195 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: thermal_last.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.498039 0.498039 0.498039 setrgbcolor
+0.10000 0.10000 0.03937 c
+1 1 1 setrgbcolor
+0.10000 0.10000 0.01575 c
+% Layer group5 group 5 drill 0 mask 0
+0.329412 0.545098 0.329412 setrgbcolor
+0.02500 0.02500 moveto
+0.12500 0.02500 lineto
+0.12500 0.04609 lineto
+0.11840 0.04336 lineto
+0.10932 0.04118 lineto
+0.10000 0.04045 lineto
+0.09068 0.04118 lineto
+0.08160 0.04336 lineto
+0.07296 0.04694 lineto
+0.06560 0.05145 lineto
+0.08014 0.06600 lineto
+0.08207 0.06481 lineto
+0.08780 0.06244 lineto
+0.09382 0.06099 lineto
+0.10000 0.06051 lineto
+0.10618 0.06099 lineto
+0.11220 0.06244 lineto
+0.11793 0.06481 lineto
+0.11986 0.06600 lineto
+0.12500 0.06086 lineto
+0.12500 0.12500 lineto
+0.06086 0.12500 lineto
+0.06600 0.11986 lineto
+0.06481 0.11793 lineto
+0.06244 0.11220 lineto
+0.06099 0.10618 lineto
+0.06051 0.10000 lineto
+0.06099 0.09382 lineto
+0.06244 0.08780 lineto
+0.06481 0.08207 lineto
+0.06600 0.08014 lineto
+0.05145 0.06560 lineto
+0.04694 0.07296 lineto
+0.04336 0.08160 lineto
+0.04118 0.09068 lineto
+0.04045 0.10000 lineto
+0.04118 0.10932 lineto
+0.04336 0.11840 lineto
+0.04609 0.12500 lineto
+0.02500 0.12500 lineto
+fill
+0.498039 0.498039 0.498039 setrgbcolor
+0.10000 0.10000 0.03937 c
+1 1 1 setrgbcolor
+0.10000 0.10000 0.01575 c
+% Layer group7 group 7 drill 0 mask 0
+0.545098 0.45098 0.333333 setrgbcolor
+0.07500 0.07500 moveto
+0.13830 0.07500 lineto
+0.13826 0.07504 lineto
+0.13732 0.07630 lineto
+0.13658 0.07770 lineto
+0.13608 0.07920 lineto
+0.13581 0.08076 lineto
+0.13579 0.08234 lineto
+0.13602 0.08390 lineto
+0.13652 0.08540 lineto
+0.13778 0.08892 lineto
+0.13866 0.09256 lineto
+0.13919 0.09626 lineto
+0.13937 0.10000 lineto
+0.13919 0.10374 lineto
+0.13866 0.10744 lineto
+0.13778 0.11108 lineto
+0.13656 0.11461 lineto
+0.13606 0.11611 lineto
+0.13583 0.11766 lineto
+0.13585 0.11924 lineto
+0.13612 0.12079 lineto
+0.13662 0.12228 lineto
+0.13736 0.12367 lineto
+0.13830 0.12493 lineto
+0.13942 0.12603 lineto
+0.14071 0.12694 lineto
+0.14212 0.12764 lineto
+0.14362 0.12811 lineto
+0.14518 0.12833 lineto
+0.14675 0.12832 lineto
+0.14831 0.12805 lineto
+0.14980 0.12754 lineto
+0.15119 0.12681 lineto
+0.15245 0.12587 lineto
+0.15355 0.12475 lineto
+0.15446 0.12346 lineto
+0.15513 0.12204 lineto
+0.15704 0.11672 lineto
+0.15837 0.11123 lineto
+0.15917 0.10564 lineto
+0.15944 0.10000 lineto
+0.15917 0.09436 lineto
+0.15837 0.08877 lineto
+0.15704 0.08328 lineto
+0.15519 0.07794 lineto
+0.15450 0.07652 lineto
+0.15358 0.07523 lineto
+0.15336 0.07500 lineto
+0.17500 0.07500 lineto
+0.17500 0.17500 lineto
+0.07500 0.17500 lineto
+0.07500 0.15330 lineto
+0.07525 0.15355 lineto
+0.07654 0.15446 lineto
+0.07796 0.15513 lineto
+0.08328 0.15704 lineto
+0.08877 0.15837 lineto
+0.09436 0.15917 lineto
+0.10000 0.15944 lineto
+0.10564 0.15917 lineto
+0.11123 0.15837 lineto
+0.11672 0.15704 lineto
+0.12206 0.15519 lineto
+0.12348 0.15450 lineto
+0.12477 0.15358 lineto
+0.12591 0.15248 lineto
+0.12685 0.15121 lineto
+0.12759 0.14981 lineto
+0.12809 0.14832 lineto
+0.12836 0.14676 lineto
+0.12838 0.14518 lineto
+0.12815 0.14361 lineto
+0.12768 0.14210 lineto
+0.12698 0.14069 lineto
+0.12607 0.13939 lineto
+0.12496 0.13826 lineto
+0.12370 0.13732 lineto
+0.12230 0.13658 lineto
+0.12080 0.13608 lineto
+0.11924 0.13581 lineto
+0.11766 0.13579 lineto
+0.11610 0.13602 lineto
+0.11460 0.13652 lineto
+0.11108 0.13778 lineto
+0.10744 0.13866 lineto
+0.10374 0.13919 lineto
+0.10000 0.13937 lineto
+0.09626 0.13919 lineto
+0.09256 0.13866 lineto
+0.08892 0.13778 lineto
+0.08539 0.13656 lineto
+0.08389 0.13606 lineto
+0.08234 0.13583 lineto
+0.08076 0.13585 lineto
+0.07921 0.13612 lineto
+0.07772 0.13662 lineto
+0.07633 0.13736 lineto
+0.07507 0.13830 lineto
+0.07500 0.13836 lineto
+fill
+0.498039 0.498039 0.498039 setrgbcolor
+0.10000 0.10000 0.03937 c
+1 1 1 setrgbcolor
+0.10000 0.10000 0.01575 c
+% Layer top group 3 drill 0 mask 0
+0.498039 0.498039 0.498039 setrgbcolor
+0.10000 0.10000 0.03937 c
+1 1 1 setrgbcolor
+0.10000 0.10000 0.01575 c
+% Layer plated-drill group -1 drill 1 mask 0
+0.10000 0.10000 0.01575 c
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/thermal_last.gbr/thermal_last.fab.gbr b/tests/RTT/ref/thermal_last.gbr/thermal_last.fab.gbr
index a26ae2c..d48ab06 100644
--- a/tests/RTT/ref/thermal_last.gbr/thermal_last.fab.gbr
+++ b/tests/RTT/ref/thermal_last.gbr/thermal_last.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: thermals on the last 2 layers - catch off-by-one bugs due to the 0-base index of thermals, TODO:group_name *
+G04 start of page 5 for group -1 layer_idx 16777221 *
+G04 Title: thermals on the last 2 layers - catch off-by-one bugs due to the 0-base index of thermals, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/thermal_last.gbr/thermal_last.group2.gbr b/tests/RTT/ref/thermal_last.gbr/thermal_last.group2.gbr
deleted file mode 100644
index bfd2252..0000000
--- a/tests/RTT/ref/thermal_last.gbr/thermal_last.group2.gbr
+++ /dev/null
@@ -1,58 +0,0 @@
-G04 start of page 2 for group 2 layer_idx 4 *
-G04 Title: thermals on the last 2 layers - catch off-by-one bugs due to the 0-base index of thermals, TODO:group_name *
-G04 Creator: <version>
-G04 CreationDate: <date>
-G04 For:  *
-G04 Format: Gerber/RS-274X *
-G04 PCB-Dimensions: 50000 50000 *
-G04 PCB-Coordinate-Origin: lower left *
-%MOIN*%
-%FSLAX25Y25*%
-%LNGROUP2*%
-%ADD13C,0.0315*%
-%ADD12C,0.0787*%
-%ADD11C,0.0001*%
-G54D11*G36*
-X2500Y47500D02*X12500D01*
-Y45391D01*
-X11840Y45664D01*
-X10932Y45882D01*
-X10000Y45955D01*
-X9068Y45882D01*
-X8160Y45664D01*
-X7296Y45306D01*
-X6560Y44855D01*
-X8014Y43400D01*
-X8207Y43519D01*
-X8780Y43756D01*
-X9382Y43901D01*
-X10000Y43949D01*
-X10618Y43901D01*
-X11220Y43756D01*
-X11793Y43519D01*
-X11986Y43400D01*
-X12500Y43914D01*
-Y37500D01*
-X6086D01*
-X6600Y38014D01*
-X6481Y38207D01*
-X6244Y38780D01*
-X6099Y39382D01*
-X6051Y40000D01*
-X6099Y40618D01*
-X6244Y41220D01*
-X6481Y41793D01*
-X6600Y41986D01*
-X5145Y43440D01*
-X4694Y42704D01*
-X4336Y41840D01*
-X4118Y40932D01*
-X4045Y40000D01*
-X4118Y39068D01*
-X4336Y38160D01*
-X4609Y37500D01*
-X2500D01*
-Y47500D01*
-G37*
-G54D12*X10000Y40000D03*
-G54D13*M02*
diff --git a/tests/RTT/ref/thermal_last.gbr/thermal_last.group3.gbr b/tests/RTT/ref/thermal_last.gbr/thermal_last.group3.gbr
deleted file mode 100644
index 9ae4c0e..0000000
--- a/tests/RTT/ref/thermal_last.gbr/thermal_last.group3.gbr
+++ /dev/null
@@ -1,118 +0,0 @@
-G04 start of page 3 for group 3 layer_idx 5 *
-G04 Title: thermals on the last 2 layers - catch off-by-one bugs due to the 0-base index of thermals, TODO:group_name *
-G04 Creator: <version>
-G04 CreationDate: <date>
-G04 For:  *
-G04 Format: Gerber/RS-274X *
-G04 PCB-Dimensions: 50000 50000 *
-G04 PCB-Coordinate-Origin: lower left *
-%MOIN*%
-%FSLAX25Y25*%
-%LNGROUP3*%
-%ADD16C,0.0315*%
-%ADD15C,0.0787*%
-%ADD14C,0.0001*%
-G54D14*G36*
-X7500Y42500D02*X13830D01*
-X13826Y42496D01*
-X13732Y42370D01*
-X13658Y42230D01*
-X13608Y42080D01*
-X13581Y41924D01*
-X13579Y41766D01*
-X13602Y41610D01*
-X13652Y41460D01*
-X13778Y41108D01*
-X13866Y40744D01*
-X13919Y40374D01*
-X13937Y40000D01*
-X13919Y39626D01*
-X13866Y39256D01*
-X13778Y38892D01*
-X13656Y38539D01*
-X13606Y38389D01*
-X13583Y38234D01*
-X13585Y38076D01*
-X13612Y37921D01*
-X13662Y37772D01*
-X13736Y37633D01*
-X13830Y37507D01*
-X13942Y37397D01*
-X14071Y37306D01*
-X14212Y37236D01*
-X14362Y37189D01*
-X14518Y37167D01*
-X14675Y37168D01*
-X14831Y37195D01*
-X14980Y37246D01*
-X15119Y37319D01*
-X15245Y37413D01*
-X15355Y37525D01*
-X15446Y37654D01*
-X15513Y37796D01*
-X15704Y38328D01*
-X15837Y38877D01*
-X15917Y39436D01*
-X15944Y40000D01*
-X15917Y40564D01*
-X15837Y41123D01*
-X15704Y41672D01*
-X15519Y42206D01*
-X15450Y42348D01*
-X15358Y42477D01*
-X15336Y42500D01*
-X17500D01*
-Y32500D01*
-X7500D01*
-Y34670D01*
-X7525Y34645D01*
-X7654Y34554D01*
-X7796Y34487D01*
-X8328Y34296D01*
-X8877Y34163D01*
-X9436Y34083D01*
-X10000Y34056D01*
-X10564Y34083D01*
-X11123Y34163D01*
-X11672Y34296D01*
-X12206Y34481D01*
-X12348Y34550D01*
-X12477Y34642D01*
-X12591Y34752D01*
-X12685Y34879D01*
-X12759Y35019D01*
-X12809Y35168D01*
-X12836Y35324D01*
-X12838Y35482D01*
-X12815Y35639D01*
-X12768Y35790D01*
-X12698Y35931D01*
-X12607Y36061D01*
-X12496Y36174D01*
-X12370Y36268D01*
-X12230Y36342D01*
-X12080Y36392D01*
-X11924Y36419D01*
-X11766Y36421D01*
-X11610Y36398D01*
-X11460Y36348D01*
-X11108Y36222D01*
-X10744Y36134D01*
-X10374Y36081D01*
-X10000Y36063D01*
-X9626Y36081D01*
-X9256Y36134D01*
-X8892Y36222D01*
-X8539Y36344D01*
-X8389Y36394D01*
-X8234Y36417D01*
-X8076Y36415D01*
-X7921Y36388D01*
-X7772Y36338D01*
-X7633Y36264D01*
-X7507Y36170D01*
-X7500Y36164D01*
-Y42500D01*
-G37*
-G54D15*X10000Y40000D03*
-G54D16*M02*
diff --git a/tests/RTT/ref/thermal_last.gbr/thermal_last.group5.gbr b/tests/RTT/ref/thermal_last.gbr/thermal_last.group5.gbr
new file mode 100644
index 0000000..bd77edb
--- /dev/null
+++ b/tests/RTT/ref/thermal_last.gbr/thermal_last.group5.gbr
@@ -0,0 +1,58 @@
+G04 start of page 2 for group 5 layer_idx 4 *
+G04 Title: thermals on the last 2 layers - catch off-by-one bugs due to the 0-base index of thermals, Intern *
+G04 Creator: <version>
+G04 CreationDate: <date>
+G04 For:  *
+G04 Format: Gerber/RS-274X *
+G04 PCB-Dimensions: 50000 50000 *
+G04 PCB-Coordinate-Origin: lower left *
+%MOIN*%
+%FSLAX25Y25*%
+%LNGROUP5*%
+%ADD13C,0.0315*%
+%ADD12C,0.0787*%
+%ADD11C,0.0001*%
+G54D11*G36*
+X2500Y47500D02*X12500D01*
+Y45391D01*
+X11840Y45664D01*
+X10932Y45882D01*
+X10000Y45955D01*
+X9068Y45882D01*
+X8160Y45664D01*
+X7296Y45306D01*
+X6560Y44855D01*
+X8014Y43400D01*
+X8207Y43519D01*
+X8780Y43756D01*
+X9382Y43901D01*
+X10000Y43949D01*
+X10618Y43901D01*
+X11220Y43756D01*
+X11793Y43519D01*
+X11986Y43400D01*
+X12500Y43914D01*
+Y37500D01*
+X6086D01*
+X6600Y38014D01*
+X6481Y38207D01*
+X6244Y38780D01*
+X6099Y39382D01*
+X6051Y40000D01*
+X6099Y40618D01*
+X6244Y41220D01*
+X6481Y41793D01*
+X6600Y41986D01*
+X5145Y43440D01*
+X4694Y42704D01*
+X4336Y41840D01*
+X4118Y40932D01*
+X4045Y40000D01*
+X4118Y39068D01*
+X4336Y38160D01*
+X4609Y37500D01*
+X2500D01*
+Y47500D01*
+G37*
+G54D12*X10000Y40000D03*
+G54D13*M02*
diff --git a/tests/RTT/ref/thermal_last.gbr/thermal_last.group7.gbr b/tests/RTT/ref/thermal_last.gbr/thermal_last.group7.gbr
new file mode 100644
index 0000000..4e8317b
--- /dev/null
+++ b/tests/RTT/ref/thermal_last.gbr/thermal_last.group7.gbr
@@ -0,0 +1,118 @@
+G04 start of page 3 for group 7 layer_idx 5 *
+G04 Title: thermals on the last 2 layers - catch off-by-one bugs due to the 0-base index of thermals, Intern *
+G04 Creator: <version>
+G04 CreationDate: <date>
+G04 For:  *
+G04 Format: Gerber/RS-274X *
+G04 PCB-Dimensions: 50000 50000 *
+G04 PCB-Coordinate-Origin: lower left *
+%MOIN*%
+%FSLAX25Y25*%
+%LNGROUP7*%
+%ADD16C,0.0315*%
+%ADD15C,0.0787*%
+%ADD14C,0.0001*%
+G54D14*G36*
+X7500Y42500D02*X13830D01*
+X13826Y42496D01*
+X13732Y42370D01*
+X13658Y42230D01*
+X13608Y42080D01*
+X13581Y41924D01*
+X13579Y41766D01*
+X13602Y41610D01*
+X13652Y41460D01*
+X13778Y41108D01*
+X13866Y40744D01*
+X13919Y40374D01*
+X13937Y40000D01*
+X13919Y39626D01*
+X13866Y39256D01*
+X13778Y38892D01*
+X13656Y38539D01*
+X13606Y38389D01*
+X13583Y38234D01*
+X13585Y38076D01*
+X13612Y37921D01*
+X13662Y37772D01*
+X13736Y37633D01*
+X13830Y37507D01*
+X13942Y37397D01*
+X14071Y37306D01*
+X14212Y37236D01*
+X14362Y37189D01*
+X14518Y37167D01*
+X14675Y37168D01*
+X14831Y37195D01*
+X14980Y37246D01*
+X15119Y37319D01*
+X15245Y37413D01*
+X15355Y37525D01*
+X15446Y37654D01*
+X15513Y37796D01*
+X15704Y38328D01*
+X15837Y38877D01*
+X15917Y39436D01*
+X15944Y40000D01*
+X15917Y40564D01*
+X15837Y41123D01*
+X15704Y41672D01*
+X15519Y42206D01*
+X15450Y42348D01*
+X15358Y42477D01*
+X15336Y42500D01*
+X17500D01*
+Y32500D01*
+X7500D01*
+Y34670D01*
+X7525Y34645D01*
+X7654Y34554D01*
+X7796Y34487D01*
+X8328Y34296D01*
+X8877Y34163D01*
+X9436Y34083D01*
+X10000Y34056D01*
+X10564Y34083D01*
+X11123Y34163D01*
+X11672Y34296D01*
+X12206Y34481D01*
+X12348Y34550D01*
+X12477Y34642D01*
+X12591Y34752D01*
+X12685Y34879D01*
+X12759Y35019D01*
+X12809Y35168D01*
+X12836Y35324D01*
+X12838Y35482D01*
+X12815Y35639D01*
+X12768Y35790D01*
+X12698Y35931D01*
+X12607Y36061D01*
+X12496Y36174D01*
+X12370Y36268D01*
+X12230Y36342D01*
+X12080Y36392D01*
+X11924Y36419D01*
+X11766Y36421D01*
+X11610Y36398D01*
+X11460Y36348D01*
+X11108Y36222D01*
+X10744Y36134D01*
+X10374Y36081D01*
+X10000Y36063D01*
+X9626Y36081D01*
+X9256Y36134D01*
+X8892Y36222D01*
+X8539Y36344D01*
+X8389Y36394D01*
+X8234Y36417D01*
+X8076Y36415D01*
+X7921Y36388D01*
+X7772Y36338D01*
+X7633Y36264D01*
+X7507Y36170D01*
+X7500Y36164D01*
+Y42500D01*
+G37*
+G54D15*X10000Y40000D03*
+G54D16*M02*
diff --git a/tests/RTT/ref/thermal_last.nelma.em b/tests/RTT/ref/thermal_last.nelma.em
new file mode 100644
index 0000000..e0b6718
--- /dev/null
+++ b/tests/RTT/ref/thermal_last.nelma.em
@@ -0,0 +1,75 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer group-1 {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+layer substrate-11 {
+	height = 20
+	z-order = 11
+	material = "composite"
+}
+layer group-1 {
+	height = 1
+	z-order = 12
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"group-1",
+		"substrate-11",
+		"group-1"
+	}
+}
diff --git a/tests/RTT/ref/thermal_last.png b/tests/RTT/ref/thermal_last.png
index 473ba89..0c01191 100644
Binary files a/tests/RTT/ref/thermal_last.png and b/tests/RTT/ref/thermal_last.png differ
diff --git a/tests/RTT/ref/thermal_last.png.text b/tests/RTT/ref/thermal_last.png.text
new file mode 100644
index 0000000..0950d12
--- /dev/null
+++ b/tests/RTT/ref/thermal_last.png.text
@@ -0,0 +1,10 @@
+r6731
+
+121 x 121 pixels (100.833 x 100.833) for both polygons
+
+via copper width 95 pixels (79.166)
+Via drill width 39 pixels (32.5)
+clearance 23 pixels (19.166)
+
+
+
diff --git a/tests/RTT/ref/thermal_last.ps.gz b/tests/RTT/ref/thermal_last.ps.gz
index ce830c6..57be1c7 100644
Binary files a/tests/RTT/ref/thermal_last.ps.gz and b/tests/RTT/ref/thermal_last.ps.gz differ
diff --git a/tests/RTT/ref/thermal_last.remote.gz b/tests/RTT/ref/thermal_last.remote.gz
index 210355c..589c117 100644
Binary files a/tests/RTT/ref/thermal_last.remote.gz and b/tests/RTT/ref/thermal_last.remote.gz differ
diff --git a/tests/RTT/ref/thermal_last.scad b/tests/RTT/ref/thermal_last.scad
new file mode 100644
index 0000000..55cc190
--- /dev/null
+++ b/tests/RTT/ref/thermal_last.scad
@@ -0,0 +1,90 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: plated-drill
+layer_pdrill_list=[
+];
+
+
+// END_OF_LAYER layer_pdrill
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/thermal_last.svg b/tests/RTT/ref/thermal_last.svg
index ca5299c..6a838e8 100644
--- a/tests/RTT/ref/thermal_last.svg
+++ b/tests/RTT/ref/thermal_last.svg
@@ -1,34 +1,34 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 <!--normal-->
  <polygon points="1.9050,1.9050 3.5128,1.9050 3.5119,1.9059 3.4879,1.9381 3.4692,1.9737 3.4563,2.0117 3.4495,2.0513 3.4490,2.0914 3.4548,2.1312 3.4675,2.1692 3.4996,2.2586 3.5220,2.3510 3.5355,2.4451 3.5400,2.5400 3.5355,2.6349 3.5220,2.7290 3.4996,2.8214 3.4686,2.9112 3.4559,2.9491 3.4502,2.9886 3.4507,3.0286 3.4574,3.0680 3.4702,3.1059 3.4888,3.1413 3.5127,3.1733 3.5414,3.2012 3.5740,3.2243 3.6098,3.2421 3.6480,3.2539 3.6876,3.2597 3.7275,3.2592 3.7670,3.2525 3.8048,3.2396 3.8402,3.221 [...]
  <circle cx="2.5400" cy="2.5400" r="1.0000" stroke-width="0.2540" fill="#7f7f7f" stroke="none"/>
  <circle cx="2.5400" cy="2.5400" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 <!--normal-->
  <polygon points="0.6350,0.6350 3.1750,0.6350 3.1750,1.1708 3.0074,1.1014 2.7766,1.0460 2.5400,1.0274 2.3034,1.0460 2.0726,1.1014 1.8533,1.1922 1.6661,1.3069 2.0355,1.6763 2.0846,1.6462 2.2300,1.5860 2.3831,1.5493 2.5400,1.5369 2.6969,1.5493 2.8500,1.5860 2.9954,1.6462 3.0445,1.6763 3.1750,1.5458 3.1750,3.1750 1.5458,3.1750 1.6763,3.0445 1.6462,2.9954 1.5860,2.8500 1.5493,2.6969 1.5369,2.5400 1.5493,2.3831 1.5860,2.2300 1.6462,2.0846 1.6763,2.0355 1.3069,1.6661 1.1922,1.8533 1.1014,2.072 [...]
  <circle cx="2.5400" cy="2.5400" r="1.0000" stroke-width="0.2540" fill="#7f7f7f" stroke="none"/>
  <circle cx="2.5400" cy="2.5400" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <circle cx="2.5400" cy="2.5400" r="1.0000" stroke-width="0.2540" fill="#7f7f7f" stroke="none"/>
  <circle cx="2.5400" cy="2.5400" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <circle cx="2.5400" cy="2.5400" r="1.0000" stroke-width="0.2540" fill="#7f7f7f" stroke="none"/>
  <circle cx="2.5400" cy="2.5400" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
-<g id="layer_-4048_plated-drill">
+<g id="layer_-1_plated-drill">
 <!--normal-->
  <circle cx="2.5400" cy="2.5400" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
diff --git a/tests/RTT/ref/thermal_layer.bbrd.png b/tests/RTT/ref/thermal_layer.bbrd.png
new file mode 100644
index 0000000..3938732
Binary files /dev/null and b/tests/RTT/ref/thermal_layer.bbrd.png differ
diff --git a/tests/RTT/ref/thermal_layer.dsn b/tests/RTT/ref/thermal_layer.dsn
index 26baf48..39650f2 100644
--- a/tests/RTT/ref/thermal_layer.dsn
+++ b/tests/RTT/ref/thermal_layer.dsn
@@ -16,9 +16,6 @@
     (layer "inner2"
       (type signal)
     )
-    (layer "outline"
-      (type signal)
-    )
     (layer "solder1"
       (type signal)
     )
@@ -36,23 +33,20 @@
     )
   )
   (placement
-    (component 5
-      (place 5 2.540000 10.160000 front 0 (PN 0))
-    )
     (component 6
-      (place 6 6.985000 10.160000 front 0 (PN 0))
+      (place 6 2.540000 10.160000 front 0 (PN 0))
     )
     (component 7
-      (place 7 2.540000 5.715000 front 0 (PN 0))
+      (place 7 6.985000 10.160000 front 0 (PN 0))
     )
     (component 8
-      (place 8 6.985000 5.715000 front 0 (PN 0))
+      (place 8 2.540000 5.715000 front 0 (PN 0))
+    )
+    (component 9
+      (place 9 6.985000 5.715000 front 0 (PN 0))
     )
   )
   (library
-    (image 5
-      (pin Th_round_3015995 1 0 0)
-    )
     (image 6
       (pin Th_round_3015995 1 0 0)
     )
@@ -62,6 +56,9 @@
     (image 8
       (pin Th_round_3015995 1 0 0)
     )
+    (image 9
+      (pin Th_round_3015995 1 0 0)
+    )
     (padstack Th_round_3015995
       (shape (circle signal 3.015995))
       (attach off)
diff --git a/tests/RTT/ref/thermal_layer.eps b/tests/RTT/ref/thermal_layer.eps
new file mode 100644
index 0000000..cf562fd
--- /dev/null
+++ b/tests/RTT/ref/thermal_layer.eps
@@ -0,0 +1,417 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 37.000000 37.000000
+%%Pages: 1
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page: 1 1
+%%BeginDocument: thermal_layer.eps
+
+72 72 scale
+1 dup neg scale
+1 dup scale
+0.00000 -0.50000 translate
+/nclip { -0.01000 -0.01000 moveto -0.01000 0.51000 lineto 0.51000 0.51000 lineto 0.51000 -0.01000 lineto -0.01000 -0.01000 lineto eoclip newpath } def
+/t { moveto lineto stroke } bind def
+/tc { moveto lineto strokepath nclip } bind def
+/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def
+     x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def
+/c { 0 360 arc fill } bind def
+/cc { 0 360 arc nclip } bind def
+/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def
+% Layer bottom group 10 drill 0 mask 0
+0.00000 setlinewidth
+1 setlinecap
+0.227451 0.372549 0.803922 setrgbcolor
+0.07500 0.07500 moveto
+0.13914 0.07500 lineto
+0.13400 0.08014 lineto
+0.13519 0.08207 lineto
+0.13756 0.08780 lineto
+0.13901 0.09382 lineto
+0.13937 0.10000 lineto
+0.13901 0.10618 lineto
+0.13756 0.11220 lineto
+0.13519 0.11793 lineto
+0.13400 0.11986 lineto
+0.14855 0.13440 lineto
+0.15306 0.12704 lineto
+0.15664 0.11840 lineto
+0.15882 0.10932 lineto
+0.15937 0.10000 lineto
+0.15882 0.09068 lineto
+0.15664 0.08160 lineto
+0.15391 0.07500 lineto
+0.17500 0.07500 lineto
+0.17500 0.17500 lineto
+0.07500 0.17500 lineto
+0.07500 0.15391 lineto
+0.08160 0.15664 lineto
+0.09068 0.15882 lineto
+0.10000 0.15955 lineto
+0.10932 0.15882 lineto
+0.11840 0.15664 lineto
+0.12704 0.15306 lineto
+0.13440 0.14855 lineto
+0.11986 0.13400 lineto
+0.11793 0.13519 lineto
+0.11220 0.13756 lineto
+0.10618 0.13901 lineto
+0.10000 0.13949 lineto
+0.09382 0.13901 lineto
+0.08780 0.13756 lineto
+0.08207 0.13519 lineto
+0.08014 0.13400 lineto
+0.07500 0.13914 lineto
+fill
+0.07500 0.25000 moveto
+0.17500 0.25000 lineto
+0.17500 0.35000 lineto
+0.07500 0.35000 lineto
+fill
+0.498039 0.498039 0.498039 setrgbcolor
+0.10000 0.10000 0.03937 c
+0.27500 0.10000 0.03937 c
+0.10000 0.27500 0.03937 c
+0.27500 0.27500 0.03937 c
+1 1 1 setrgbcolor
+0.10000 0.10000 0.01575 c
+0.27500 0.10000 0.01575 c
+0.10000 0.27500 0.01575 c
+0.27500 0.27500 0.01575 c
+% Layer group5 group 5 drill 0 mask 0
+0.498039 0.498039 0.498039 setrgbcolor
+0.10000 0.10000 0.03937 c
+0.27500 0.10000 0.03937 c
+0.10000 0.27500 0.03937 c
+0.27500 0.27500 0.03937 c
+1 1 1 setrgbcolor
+0.10000 0.10000 0.01575 c
+0.27500 0.10000 0.01575 c
+0.10000 0.27500 0.01575 c
+0.27500 0.27500 0.01575 c
+% Layer group7 group 7 drill 0 mask 0
+0.498039 0.498039 0.498039 setrgbcolor
+0.10000 0.10000 0.03937 c
+0.27500 0.10000 0.03937 c
+0.10000 0.27500 0.03937 c
+0.27500 0.27500 0.03937 c
+1 1 1 setrgbcolor
+0.10000 0.10000 0.01575 c
+0.27500 0.10000 0.01575 c
+0.10000 0.27500 0.01575 c
+0.27500 0.27500 0.01575 c
+% Layer top group 3 drill 0 mask 0
+0.0627451 0.305882 0.545098 setrgbcolor
+0.25000 0.07500 moveto
+0.31414 0.07500 lineto
+0.30900 0.08014 lineto
+0.31019 0.08207 lineto
+0.31256 0.08780 lineto
+0.31401 0.09382 lineto
+0.31437 0.10000 lineto
+0.31401 0.10618 lineto
+0.31256 0.11220 lineto
+0.31019 0.11793 lineto
+0.30900 0.11986 lineto
+0.32355 0.13440 lineto
+0.32806 0.12704 lineto
+0.33164 0.11840 lineto
+0.33382 0.10932 lineto
+0.33437 0.10000 lineto
+0.33382 0.09068 lineto
+0.33164 0.08160 lineto
+0.32891 0.07500 lineto
+0.35000 0.07500 lineto
+0.35000 0.17500 lineto
+0.25000 0.17500 lineto
+0.25000 0.15391 lineto
+0.25660 0.15664 lineto
+0.26568 0.15882 lineto
+0.27500 0.15955 lineto
+0.28432 0.15882 lineto
+0.29340 0.15664 lineto
+0.30204 0.15306 lineto
+0.30940 0.14855 lineto
+0.29486 0.13400 lineto
+0.29293 0.13519 lineto
+0.28720 0.13756 lineto
+0.28118 0.13901 lineto
+0.27500 0.13949 lineto
+0.26882 0.13901 lineto
+0.26280 0.13756 lineto
+0.25707 0.13519 lineto
+0.25514 0.13400 lineto
+0.25000 0.13914 lineto
+fill
+0.25000 0.25000 moveto
+0.35000 0.25000 lineto
+0.35000 0.35000 lineto
+0.25000 0.35000 lineto
+fill
+0.545098 0.137255 0.137255 setrgbcolor
+0.02500 0.02500 moveto
+0.12500 0.02500 lineto
+0.12500 0.04670 lineto
+0.12475 0.04645 lineto
+0.12346 0.04554 lineto
+0.12204 0.04487 lineto
+0.11672 0.04296 lineto
+0.11123 0.04163 lineto
+0.10564 0.04083 lineto
+0.10000 0.04056 lineto
+0.09436 0.04083 lineto
+0.08877 0.04163 lineto
+0.08328 0.04296 lineto
+0.07794 0.04481 lineto
+0.07652 0.04550 lineto
+0.07523 0.04642 lineto
+0.07409 0.04752 lineto
+0.07315 0.04879 lineto
+0.07241 0.05019 lineto
+0.07191 0.05168 lineto
+0.07164 0.05324 lineto
+0.07162 0.05482 lineto
+0.07185 0.05639 lineto
+0.07232 0.05790 lineto
+0.07302 0.05931 lineto
+0.07393 0.06061 lineto
+0.07504 0.06174 lineto
+0.07630 0.06268 lineto
+0.07770 0.06342 lineto
+0.07920 0.06392 lineto
+0.08076 0.06419 lineto
+0.08234 0.06421 lineto
+0.08390 0.06398 lineto
+0.08540 0.06348 lineto
+0.08892 0.06222 lineto
+0.09256 0.06134 lineto
+0.09626 0.06081 lineto
+0.10000 0.06063 lineto
+0.10374 0.06081 lineto
+0.10744 0.06134 lineto
+0.11108 0.06222 lineto
+0.11461 0.06344 lineto
+0.11611 0.06394 lineto
+0.11766 0.06417 lineto
+0.11924 0.06415 lineto
+0.12079 0.06388 lineto
+0.12228 0.06338 lineto
+0.12367 0.06264 lineto
+0.12493 0.06170 lineto
+0.12500 0.06164 lineto
+0.12500 0.12500 lineto
+0.06170 0.12500 lineto
+0.06174 0.12496 lineto
+0.06268 0.12370 lineto
+0.06342 0.12230 lineto
+0.06392 0.12080 lineto
+0.06419 0.11924 lineto
+0.06421 0.11766 lineto
+0.06398 0.11610 lineto
+0.06348 0.11460 lineto
+0.06222 0.11108 lineto
+0.06134 0.10744 lineto
+0.06081 0.10374 lineto
+0.06063 0.10000 lineto
+0.06081 0.09626 lineto
+0.06134 0.09256 lineto
+0.06222 0.08892 lineto
+0.06344 0.08539 lineto
+0.06394 0.08389 lineto
+0.06417 0.08234 lineto
+0.06415 0.08076 lineto
+0.06388 0.07921 lineto
+0.06338 0.07772 lineto
+0.06264 0.07633 lineto
+0.06170 0.07507 lineto
+0.06058 0.07397 lineto
+0.05929 0.07306 lineto
+0.05788 0.07236 lineto
+0.05638 0.07189 lineto
+0.05482 0.07167 lineto
+0.05325 0.07168 lineto
+0.05169 0.07195 lineto
+0.05020 0.07246 lineto
+0.04881 0.07319 lineto
+0.04755 0.07413 lineto
+0.04645 0.07525 lineto
+0.04554 0.07654 lineto
+0.04487 0.07796 lineto
+0.04296 0.08328 lineto
+0.04163 0.08877 lineto
+0.04083 0.09436 lineto
+0.04056 0.10000 lineto
+0.04083 0.10564 lineto
+0.04163 0.11123 lineto
+0.04296 0.11672 lineto
+0.04481 0.12206 lineto
+0.04550 0.12348 lineto
+0.04642 0.12477 lineto
+0.04664 0.12500 lineto
+0.02500 0.12500 lineto
+fill
+0.20000 0.02500 moveto
+0.30000 0.02500 lineto
+0.30000 0.04670 lineto
+0.29975 0.04645 lineto
+0.29846 0.04554 lineto
+0.29704 0.04487 lineto
+0.29172 0.04296 lineto
+0.28623 0.04163 lineto
+0.28064 0.04083 lineto
+0.27500 0.04056 lineto
+0.26936 0.04083 lineto
+0.26377 0.04163 lineto
+0.25828 0.04296 lineto
+0.25294 0.04481 lineto
+0.25152 0.04550 lineto
+0.25023 0.04642 lineto
+0.24909 0.04752 lineto
+0.24815 0.04879 lineto
+0.24741 0.05019 lineto
+0.24691 0.05168 lineto
+0.24664 0.05324 lineto
+0.24662 0.05482 lineto
+0.24685 0.05639 lineto
+0.24732 0.05790 lineto
+0.24802 0.05931 lineto
+0.24893 0.06061 lineto
+0.25004 0.06174 lineto
+0.25130 0.06268 lineto
+0.25270 0.06342 lineto
+0.25420 0.06392 lineto
+0.25576 0.06419 lineto
+0.25734 0.06421 lineto
+0.25890 0.06398 lineto
+0.26040 0.06348 lineto
+0.26392 0.06222 lineto
+0.26756 0.06134 lineto
+0.27126 0.06081 lineto
+0.27500 0.06063 lineto
+0.27874 0.06081 lineto
+0.28244 0.06134 lineto
+0.28608 0.06222 lineto
+0.28961 0.06344 lineto
+0.29111 0.06394 lineto
+0.29266 0.06417 lineto
+0.29424 0.06415 lineto
+0.29579 0.06388 lineto
+0.29728 0.06338 lineto
+0.29867 0.06264 lineto
+0.29993 0.06170 lineto
+0.30000 0.06164 lineto
+0.30000 0.12500 lineto
+0.23670 0.12500 lineto
+0.23674 0.12496 lineto
+0.23768 0.12370 lineto
+0.23842 0.12230 lineto
+0.23892 0.12080 lineto
+0.23919 0.11924 lineto
+0.23921 0.11766 lineto
+0.23898 0.11610 lineto
+0.23848 0.11460 lineto
+0.23722 0.11108 lineto
+0.23634 0.10744 lineto
+0.23581 0.10374 lineto
+0.23563 0.10000 lineto
+0.23581 0.09626 lineto
+0.23634 0.09256 lineto
+0.23722 0.08892 lineto
+0.23844 0.08539 lineto
+0.23894 0.08389 lineto
+0.23917 0.08234 lineto
+0.23915 0.08076 lineto
+0.23888 0.07921 lineto
+0.23838 0.07772 lineto
+0.23764 0.07633 lineto
+0.23670 0.07507 lineto
+0.23558 0.07397 lineto
+0.23429 0.07306 lineto
+0.23288 0.07236 lineto
+0.23138 0.07189 lineto
+0.22982 0.07167 lineto
+0.22825 0.07168 lineto
+0.22669 0.07195 lineto
+0.22520 0.07246 lineto
+0.22381 0.07319 lineto
+0.22255 0.07413 lineto
+0.22145 0.07525 lineto
+0.22054 0.07654 lineto
+0.21987 0.07796 lineto
+0.21796 0.08328 lineto
+0.21663 0.08877 lineto
+0.21583 0.09436 lineto
+0.21556 0.10000 lineto
+0.21583 0.10564 lineto
+0.21663 0.11123 lineto
+0.21796 0.11672 lineto
+0.21981 0.12206 lineto
+0.22050 0.12348 lineto
+0.22142 0.12477 lineto
+0.22164 0.12500 lineto
+0.20000 0.12500 lineto
+fill
+0.02500 0.20000 moveto
+0.12500 0.20000 lineto
+0.12500 0.22109 lineto
+0.11840 0.21836 lineto
+0.10932 0.21618 lineto
+0.10000 0.21545 lineto
+0.09068 0.21618 lineto
+0.08160 0.21836 lineto
+0.07296 0.22194 lineto
+0.06500 0.22682 lineto
+0.05789 0.23289 lineto
+0.05182 0.24000 lineto
+0.04694 0.24796 lineto
+0.04336 0.25660 lineto
+0.04118 0.26568 lineto
+0.04045 0.27500 lineto
+0.04118 0.28432 lineto
+0.04336 0.29340 lineto
+0.04609 0.30000 lineto
+0.02500 0.30000 lineto
+fill
+0.20000 0.20000 moveto
+0.30000 0.20000 lineto
+0.30000 0.22109 lineto
+0.29340 0.21836 lineto
+0.28432 0.21618 lineto
+0.27500 0.21545 lineto
+0.26568 0.21618 lineto
+0.25660 0.21836 lineto
+0.24796 0.22194 lineto
+0.24000 0.22682 lineto
+0.23289 0.23289 lineto
+0.22682 0.24000 lineto
+0.22194 0.24796 lineto
+0.21836 0.25660 lineto
+0.21618 0.26568 lineto
+0.21545 0.27500 lineto
+0.21618 0.28432 lineto
+0.21836 0.29340 lineto
+0.22109 0.30000 lineto
+0.20000 0.30000 lineto
+fill
+0.498039 0.498039 0.498039 setrgbcolor
+0.10000 0.10000 0.03937 c
+0.27500 0.10000 0.03937 c
+0.10000 0.27500 0.03937 c
+0.27500 0.27500 0.03937 c
+1 1 1 setrgbcolor
+0.10000 0.10000 0.01575 c
+0.27500 0.10000 0.01575 c
+0.10000 0.27500 0.01575 c
+0.27500 0.27500 0.01575 c
+% Layer plated-drill group -1 drill 1 mask 0
+0.10000 0.10000 0.01575 c
+0.27500 0.10000 0.01575 c
+0.10000 0.27500 0.01575 c
+0.27500 0.27500 0.01575 c
+% Layer topsilk group 1 drill 0 mask 0
+% Layer bottomsilk group 12 drill 0 mask 0
+showpage
+%%EndDocument
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/tests/RTT/ref/thermal_layer.gbr/thermal_layer.bottom.gbr b/tests/RTT/ref/thermal_layer.gbr/thermal_layer.bottom.gbr
index 440f7e3..6ee4596 100644
--- a/tests/RTT/ref/thermal_layer.gbr/thermal_layer.bottom.gbr
+++ b/tests/RTT/ref/thermal_layer.gbr/thermal_layer.bottom.gbr
@@ -1,5 +1,5 @@
-G04 start of page 3 for group 1 layer_idx 1 *
-G04 Title: thermals vs. multiple layer polygons, TODO:group_name *
+G04 start of page 3 for group 10 layer_idx 1 *
+G04 Title: thermals vs. multiple layer polygons, bottom copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/thermal_layer.gbr/thermal_layer.fab.gbr b/tests/RTT/ref/thermal_layer.gbr/thermal_layer.fab.gbr
index 8220add..5959452 100644
--- a/tests/RTT/ref/thermal_layer.gbr/thermal_layer.fab.gbr
+++ b/tests/RTT/ref/thermal_layer.gbr/thermal_layer.fab.gbr
@@ -1,5 +1,5 @@
-G04 start of page 5 for group -1 layer_idx -1 *
-G04 Title: thermals vs. multiple layer polygons, TODO:group_name *
+G04 start of page 5 for group -1 layer_idx 16777221 *
+G04 Title: thermals vs. multiple layer polygons, <virtual group> *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/thermal_layer.gbr/thermal_layer.top.gbr b/tests/RTT/ref/thermal_layer.gbr/thermal_layer.top.gbr
index 7dad94e..8381571 100644
--- a/tests/RTT/ref/thermal_layer.gbr/thermal_layer.top.gbr
+++ b/tests/RTT/ref/thermal_layer.gbr/thermal_layer.top.gbr
@@ -1,5 +1,5 @@
-G04 start of page 2 for group 0 layer_idx 0 *
-G04 Title: thermals vs. multiple layer polygons, TODO:group_name *
+G04 start of page 2 for group 3 layer_idx 0 *
+G04 Title: thermals vs. multiple layer polygons, top copper *
 G04 Creator: <version>
 G04 CreationDate: <date>
 G04 For:  *
diff --git a/tests/RTT/ref/thermal_layer.nelma.em b/tests/RTT/ref/thermal_layer.nelma.em
new file mode 100644
index 0000000..40f7fea
--- /dev/null
+++ b/tests/RTT/ref/thermal_layer.nelma.em
@@ -0,0 +1,75 @@
+/* banner */
+ */
+/* **** Nets **** */
+
+
+/* **** Objects **** */
+
+
+/* **** Layers **** */
+
+layer air-top {
+	height = 40
+	z-order = 1
+	material = "air"
+}
+layer air-bottom {
+	height = 40
+	z-order = 1000
+	material = "air"
+}
+layer top {
+	height = 1
+	z-order = 10
+	material = "air"
+	objects = {
+
+	}
+}
+layer substrate-11 {
+	height = 20
+	z-order = 11
+	material = "composite"
+}
+layer bottom {
+	height = 1
+	z-order = 12
+	material = "air"
+	objects = {
+
+	}
+}
+
+/* **** Materials **** */
+
+material copper {
+	type = "metal"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material air {
+	type = "dielectric"
+	permittivity = 8.850000e-12
+	conductivity = 0.0
+	permeability = 0.0
+}
+material composite {
+	type = "dielectric"
+	permittivity = 3.540000e-11
+	conductivity = 0.0
+	permeability = 0.0
+}
+
+/* **** Space **** */
+
+space pcb {
+	step = { 2.540000e-04, 2.540000e-04, 1.000000e-04 }
+	layers = {
+		"air-top",
+		"air-bottom",
+		"top",
+		"substrate-11",
+		"bottom"
+	}
+}
diff --git a/tests/RTT/ref/thermal_layer.png b/tests/RTT/ref/thermal_layer.png
index 90a3e0d..125c1b6 100644
Binary files a/tests/RTT/ref/thermal_layer.png and b/tests/RTT/ref/thermal_layer.png differ
diff --git a/tests/RTT/ref/thermal_layer.png.text b/tests/RTT/ref/thermal_layer.png.text
new file mode 100644
index 0000000..9e2f458
--- /dev/null
+++ b/tests/RTT/ref/thermal_layer.png.text
@@ -0,0 +1,10 @@
+r6731
+
+each red polygon is 121x121 pixels (100.833 x 100.833)
+each blue polygon is 121x121 pixels (100.833 x 100.833)
+
+clearance 23 pixels (19.167)
+copper width 95 pixels (79.166)
+drill width 39 pixels (32.5)
+
+lower two vias are cleared with only 23 pixels (19.166)
diff --git a/tests/RTT/ref/thermal_layer.ps.gz b/tests/RTT/ref/thermal_layer.ps.gz
index 29f9479..9ff609c 100644
Binary files a/tests/RTT/ref/thermal_layer.ps.gz and b/tests/RTT/ref/thermal_layer.ps.gz differ
diff --git a/tests/RTT/ref/thermal_layer.remote.gz b/tests/RTT/ref/thermal_layer.remote.gz
index 7016a25..0052c06 100644
Binary files a/tests/RTT/ref/thermal_layer.remote.gz and b/tests/RTT/ref/thermal_layer.remote.gz differ
diff --git a/tests/RTT/ref/thermal_layer.scad b/tests/RTT/ref/thermal_layer.scad
new file mode 100644
index 0000000..55cc190
--- /dev/null
+++ b/tests/RTT/ref/thermal_layer.scad
@@ -0,0 +1,90 @@
+//SCAD
+
+module line_segment_r(length, width, thickness, x, y, a, bd, c1, c2) {
+	translate([x,y,0]) rotate ([0,0,a]) union() {
+		if (bd) {cube ([length, width,thickness],true);}
+		if (c2) {translate([length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+		if (c1) { translate([-length/2.,0,0]) cylinder(h=thickness, r=width/2,center=true,$fn=30);}
+	}
+}
+
+module line_segment(length, width, thickness, x, y, a) {
+	translate([x,y,0]) rotate ([0,0,a]) {
+		cube ([length, width,thickness],true);
+	}
+}
+
+// START_OF_LAYER: plated-drill
+layer_pdrill_list=[
+];
+
+
+// END_OF_LAYER layer_pdrill
+
+// START_OF_LAYER: topsilk
+module layer_topsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_topsilk
+
+// START_OF_LAYER: bottomsilk
+module layer_bottomsilk_body (offset) {
+translate ([0, 0, offset]) union () {
+}
+}
+
+
+// END_OF_LAYER layer_bottomsilk
+
+module board_outline () {
+	polygon([[0,0],[0,-12.700000],[12.700000,-12.700000],[12.700000,0]],
+[[0,1,2,3]]);
+}
+
+module all_holes() {
+	plating=0.017500;
+	union () {
+		for (i = layer_pdrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0]+2*plating, h=1.770000, center=true, $fn=30);
+		}
+		for (i = layer_udrill_list) {
+			translate([i[1][0],i[1][1],0]) cylinder(r=i[0], h=1.770000, center=true, $fn=30);
+		}
+	}
+}
+
+module board_body() {
+	translate ([0, 0, -0.800000]) linear_extrude(height=1.600000) board_outline();}
+
+/***************************************************/
+/*                                                 */
+/* Components                                      */
+/*                                                 */
+/***************************************************/
+module all_components() {
+}
+
+/***************************************************/
+/*                                                 */
+/* Final board assembly                            */
+/* Here is the complete board built from           */
+/* pre-generated modules                           */
+/*                                                 */
+/***************************************************/
+		color ([1, 1, 1])
+			layer_topsilk_body(0.818750);
+
+		color ([1, 1, 1])
+			layer_bottomsilk_body(-0.818750);
+
+		color ([0.44, 0.44, 0])
+			difference() {
+				board_body();
+				all_holes();
+			}
+
+		all_components();
+// END_OF_BOARD
diff --git a/tests/RTT/ref/thermal_layer.svg b/tests/RTT/ref/thermal_layer.svg
index 39b0792..455793f 100644
--- a/tests/RTT/ref/thermal_layer.svg
+++ b/tests/RTT/ref/thermal_layer.svg
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="1625.6000" height="1625.6000" viewBox="-2.0000 -2.0000 17.7000 17.7000">
-<g id="layer_4_copper">
+<g id="layer_9_outline">
 <!--normal-->
  <rect x="0.0000" y="0.0000" width="12.7000" height="12.7000" stroke-width="0.2540" stroke="#00868b" stroke-linecap="round" fill="none"/>
 </g>
-<g id="layer_3_copper">
+<g id="layer_7_group7">
 <!--normal-->
  <circle cx="2.5400" cy="2.5400" r="1.0000" stroke-width="0.2540" fill="#7f7f7f" stroke="none"/>
  <circle cx="6.9850" cy="2.5400" r="1.0000" stroke-width="0.2540" fill="#7f7f7f" stroke="none"/>
@@ -15,7 +15,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="6.9850" cy="6.9850" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_2_copper">
+<g id="layer_5_group5">
 <!--normal-->
  <circle cx="2.5400" cy="2.5400" r="1.0000" stroke-width="0.2540" fill="#7f7f7f" stroke="none"/>
  <circle cx="6.9850" cy="2.5400" r="1.0000" stroke-width="0.2540" fill="#7f7f7f" stroke="none"/>
@@ -26,7 +26,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="6.9850" cy="6.9850" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_1_copper">
+<g id="layer_10_bottom">
 <!--normal-->
  <polygon points="1.9050,1.9050 3.5342,1.9050 3.4037,2.0355 3.4338,2.0846 3.4940,2.2300 3.5307,2.3831 3.5400,2.5400 3.5307,2.6969 3.4940,2.8500 3.4338,2.9954 3.4037,3.0445 3.7731,3.4139 3.8878,3.2267 3.9786,3.0074 4.0340,2.7766 4.0480,2.5400 4.0340,2.3034 3.9786,2.0726 3.9092,1.9050 4.4450,1.9050 4.4450,4.4450 1.9050,4.4450 1.9050,3.9092 2.0726,3.9786 2.3034,4.0340 2.5400,4.0526 2.7766,4.0340 3.0074,3.9786 3.2267,3.8878 3.4139,3.7731 3.0445,3.4037 2.9954,3.4338 2.8500,3.4940 2.6969,3.530 [...]
  <polygon points="1.9050,6.3500 4.4450,6.3500 4.4450,8.8900 1.9050,8.8900 " stroke-width="0.075" stroke="#3a5fcd" fill="#3a5fcd"/>
@@ -39,7 +39,7 @@
  <circle cx="2.5400" cy="6.9850" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="6.9850" cy="6.9850" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_0_copper">
+<g id="layer_3_top">
 <!--normal-->
  <polygon points="6.3500,1.9050 7.9792,1.9050 7.8487,2.0355 7.8788,2.0846 7.9390,2.2300 7.9757,2.3831 7.9850,2.5400 7.9757,2.6969 7.9390,2.8500 7.8788,2.9954 7.8487,3.0445 8.2181,3.4139 8.3328,3.2267 8.4236,3.0074 8.4790,2.7766 8.4930,2.5400 8.4790,2.3034 8.4236,2.0726 8.3542,1.9050 8.8900,1.9050 8.8900,4.4450 6.3500,4.4450 6.3500,3.9092 6.5176,3.9786 6.7484,4.0340 6.9850,4.0526 7.2216,4.0340 7.4524,3.9786 7.6717,3.8878 7.8589,3.7731 7.4895,3.4037 7.4404,3.4338 7.2950,3.4940 7.1419,3.530 [...]
  <polygon points="6.3500,6.3500 8.8900,6.3500 8.8900,8.8900 6.3500,8.8900 " stroke-width="0.075" stroke="#104e8b" fill="#104e8b"/>
@@ -56,9 +56,9 @@
  <circle cx="2.5400" cy="6.9850" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="6.9850" cy="6.9850" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
 </g>
-<g id="layer_-4079_topsilk">
+<g id="layer_1_topsilk">
 </g>
-<g id="layer_-4048_plated-drill">
+<g id="layer_-1_plated-drill">
 <!--normal-->
  <circle cx="2.5400" cy="2.5400" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
  <circle cx="6.9850" cy="2.5400" r="0.4001" stroke-width="0.0000" fill="#ffffff" stroke="none"/>
diff --git a/tests/RTT/text_rot.pcb.text b/tests/RTT/text_rot.pcb.text
new file mode 100644
index 0000000..ba73322
--- /dev/null
+++ b/tests/RTT/text_rot.pcb.text
@@ -0,0 +1,14 @@
+layout is 500mils by 500mils
+
+A's are all 7mils thick
+1 7 mils thick
+2 7 mils thick
+3 7 mils thick
+4 7 mils thick
+
+All text is spaced @ 5 mils
+
+113 mils from under A2 to under A4
+113 mils from under A1 to under A3
+
+
diff --git a/tests/RTT/text_scale.pcb.text b/tests/RTT/text_scale.pcb.text
new file mode 100644
index 0000000..afbd9d0
--- /dev/null
+++ b/tests/RTT/text_scale.pcb.text
@@ -0,0 +1,26 @@
+top text A1
+A line width 7 mils
+A width 32
+A height 47
+1 line width 7
+1 width 22
+1 height 47
+
+gap from A to 1 is 5 mils
+
+dot thing in the page
+ tall 11
+ wide 13.2
+
+bottom text A3 
+A line width 12.8
+A width 92.8
+A height 140.8
+3 line width 12.8
+3 width 76.8
+3 height 140.8
+A to 3 is 25.6
+
+all measurements in mils
+
+
diff --git a/tests/RTT/text_sides.pcb.text b/tests/RTT/text_sides.pcb.text
new file mode 100644
index 0000000..6937a0f
--- /dev/null
+++ b/tests/RTT/text_sides.pcb.text
@@ -0,0 +1,5 @@
+layout 500 x 500 mils
+
+38 mils between the bottom of A1 and bottom of A2
+
+all text is 7 mils thick
diff --git a/tests/RTT/thermal_last.pcb.text b/tests/RTT/thermal_last.pcb.text
new file mode 100644
index 0000000..08f1a7f
--- /dev/null
+++ b/tests/RTT/thermal_last.pcb.text
@@ -0,0 +1,8 @@
+500 x 500 mil outline
+
+100 mil x 100 mil for both polygons
+
+via copper width 78.74 mils
+Via drill width 31.50 mils
+annulus 23.62 mils
+clearance 20 mils
diff --git a/tests/RTT/thermal_layer.pcb.text b/tests/RTT/thermal_layer.pcb.text
new file mode 100644
index 0000000..84a00c9
--- /dev/null
+++ b/tests/RTT/thermal_layer.pcb.text
@@ -0,0 +1,8 @@
+500 x 500 mil outline
+
+each red polygon is 100x100 mils
+each blue polygon is 100x100 mils
+
+clearance should be exactly 20.00mils
+copper width 78.74 mils
+drill width 31.50 mils
diff --git a/util/Makefile b/util/Makefile
index 2378775..0dc39a9 100644
--- a/util/Makefile
+++ b/util/Makefile
@@ -1,32 +1,34 @@
 # plain old hand crafted Makefile
+ROOT=..
 
 all:
 	cd gsch2pcb-rnd && $(MAKE) all
 
-include ../Makefile.conf
+include $(ROOT)/Makefile.conf
 
 clean:
 	cd gsch2pcb-rnd && $(MAKE) clean
 
-install_:
-	$(MKDIR) "$(BINDIR)" "$(LIBDIR)"
-	$(CPC) "`pwd`/fp2anim" "$(BINDIR)/fp2anim"
-	$(CPC) "`pwd`/pcb-strip" "$(BINDIR)/pcb-strip"
-	$(CPC) "`pwd`/pcb-prj2lht" "$(BINDIR)/pcb-prj2lht"
-	$(CPC) "`pwd`/gnet-pcbrndfwd.scm" "$(LIBDIR)/gnet-pcbrndfwd.scm"
-	$(CPC) "`pwd`/gnet-pcbrndfwd_elem.scm" "$(LIBDIR)/gnet-pcbrndfwd_elem.scm"
-	cd gsch2pcb-rnd && $(MAKE) install_ CPC="$(CPC)"
+distclean:
+	cd gsch2pcb-rnd && $(MAKE) distclean
+
+install_all:
+	$(SCCBOX) mkdir -p  "$(BINDIR)" "$(LIBDIR)"
+	$(SCCBOX) $(HOW) "fp2anim" "$(BINDIR)/fp2anim"
+	$(SCCBOX) $(HOW) "pcb-strip" "$(BINDIR)/pcb-strip"
+	$(SCCBOX) $(HOW) "pcb-prj2lht" "$(BINDIR)/pcb-prj2lht"
+	$(SCCBOX) $(HOW) "gnet-pcbrndfwd.scm" "$(LIBDIR)/gnet-pcbrndfwd.scm"
+	$(SCCBOX) $(HOW) "gnet-pcbrndfwd_elem.scm" "$(LIBDIR)/gnet-pcbrndfwd_elem.scm"
 
 install:
-	$(MAKE) install_ CPC="$(CP)"
+	$(MAKE) install_all HOW="install -f"
+	cd gsch2pcb-rnd && $(MAKE) install
 
 linstall:
-	$(MAKE) install_ CPC="$(LN)"
+	$(MAKE) install_all HOW="linstall -f"
+	cd gsch2pcb-rnd && $(MAKE) linstall
 
 uninstall:
-	$(RM) "$(BINDIR)/fp2anim"
-	$(RM) "$(BINDIR)/pcb-strip"
-	$(RM) "$(BINDIR)/pcb-prj2lht"
-	$(RM) "$(LIBDIR)/gnet-pcbrndfwd.scm"
-	$(RM) "$(LIBDIR)/gnet-pcbrndfwd_elem.scm"
+	$(MAKE) install_all HOW="uninstall"
 	cd gsch2pcb-rnd && $(MAKE) uninstall
+
diff --git a/util/devhelpers/chgstat.sh b/util/devhelpers/chgstat.sh
index 628ee0e..fd4d4a0 100755
--- a/util/devhelpers/chgstat.sh
+++ b/util/devhelpers/chgstat.sh
@@ -59,10 +59,14 @@ done| awk -v import=$import '
 # old plugins and export plugin import
 				old++
 			}
-			else if ((rev == 4550) || ((rev <= 4548) && (rev >= 4536)) || ((rev <= 4534) && (rev >= 4530)) || ((rev <= 4528) && (rev >= 4524)) || ((rev <= 4522) && (rev >= 4502)) || ((rev <= 4500) && (rev >= 4493)) || ((rev <= 4491) && (rev >= 4486)) || ((rev <= 4633) && (rev >= 4562)) || (rev == 4776) || (rev == 4847) || (rev == 4850) || (rev == 4856) || (rev == 4863) || (rev == 4866) || (rev == 4878) || (rev == 4914) || (rev == 4916) || (rev == 5002) || (rev == 5014)) {
+			else if ((rev == 4550) || ((rev <= 4548) && (rev >= 4536)) || ((rev <= 4534) && (rev >= 4530)) || ((rev <= 4528) && (rev >= 4524)) || ((rev <= 4522) && (rev >= 4502)) || ((rev <= 4500) && (rev >= 4493)) || ((rev <= 4491) && (rev >= 4486)) || ((rev <= 4633) && (rev >= 4562)) || (rev == 4776) || (rev == 4847) || (rev == 4850) || (rev == 4856) || (rev == 4863) || (rev == 4866) || (rev == 4878) || (rev == 4914) || (rev == 4916) || (rev == 5002) || (rev == 5014) || (rev == 5253) || (rev == [...]
 # unravel
 				old++
 			}
+			else if ((rev == 6046) || (rev == 6063) || (rev == 6066) || (rev == 6072) || (rev == 6077) || (rev == 6079) || (rev == 6083) || (rev == 6084)) {
+# gtk splitup
+				old++
+			}
 			else if ((rev <= import) || (rev == 1022) || (rev == 3539) || (rev == 4187))
 				old++
 			else
diff --git a/util/devhelpers/font2c.sh b/util/devhelpers/font2c.sh
new file mode 100755
index 0000000..71f2fc9
--- /dev/null
+++ b/util/devhelpers/font2c.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+#   font2c - convert a pcb font to simplified embedded font structs for pcb-rnd
+#   Copyright (C) 2016 Tibor 'Igor2' Palinkas
+#
+#   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 General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program; if not, write to the Free Software Foundation, Inc.,
+#   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+#   http://repo.hu/projects/pcb-rnd
+
+awk '
+
+BEGIN {
+	minx = 100000
+	miny = 100000
+	maxx = 0
+	maxy = 0
+	print "/* This file is autogenerated by font2c.sh - DO NOT EDIT */"
+	print ""
+	print "/* Internal copy of the default font; used when no font file is found */"
+	print ""
+}
+
+function bump(x, y)
+{
+	if (x < minx) minx = x
+	if (y < miny) miny = y
+	if (x > maxx) maxx = x
+	if (y > maxy) maxy = y
+}
+
+/Symbol[(]/ {
+	sym=substr($0, 9, 1)
+	ADV[sym]=int(substr($0, 11, length($0)))
+	NLINE[sym] = 0
+}
+
+/SymbolLine[(]/ {
+	sub("[ \t]*SymbolLine[(]", "", $0)
+	X1[sym, NLINE[sym]] = int($1)
+	Y1[sym, NLINE[sym]] = int($2)
+	X2[sym, NLINE[sym]] = int($3)
+	Y2[sym, NLINE[sym]] = int($4)
+	TH[sym, NLINE[sym]] = int($5)
+	bump(int($1), int($2))
+	bump(int($3), int($4))
+	NLINE[sym]++
+}
+
+END {
+	for(n = 0; n < 128; n++) {
+		c = sprintf("%c", n)
+		if (c in ADV) {
+			if ((n > 32) && !(c ~ "[{}()]"))
+				annot = " /* " c " */"
+			else
+				annot = ""
+			print "static embf_line_t embf_line_" n "[] = {" annot
+			for(l = 0; l < NLINE[c]; l++)
+				print "	{" X1[c, l] ", " Y1[c, l] ",\t\t" X2[c, l] ", " Y2[c, l] ",\t\t" TH[c, l] "}" ((l < NLINE[c]-1) ? "," : "")
+			if (NLINE[c] == 0)
+				print "	{0,0,0,0}"
+			print "};"
+		};
+	}
+
+	print "/***************************************************************/"
+	print "static int embf_minx = " minx ";"
+	print "static int embf_miny = " miny ";"
+	print "static int embf_maxx = " maxx ";"
+	print "static int embf_maxy = " maxy ";"
+
+	print "static embf_font_t embf_font[] = {"
+	for(n = 0; n < 128; n++) {
+		c = sprintf("%c", n)
+		comma = ((n < 127) ? "," : "")
+		if (c in ADV) {
+			print "	{" ADV[c] ", embf_line_" n ", " NLINE[c] "}" comma
+		}
+		else {
+			print "	{0, NULL, 0}" comma
+		}
+	}
+	print "};"
+}
+'
diff --git a/util/gsch2pcb-rnd/Makefile.in b/util/gsch2pcb-rnd/Makefile.in
index 90afa4c..3b4c5d7 100644
--- a/util/gsch2pcb-rnd/Makefile.in
+++ b/util/gsch2pcb-rnd/Makefile.in
@@ -4,6 +4,7 @@ append /local/pcb/LDFLAGS cc/ldflags
 include {../scconfig/template/debug.tmpasm}
 
 print [@
+ROOT=../..
 PLUGDIR=../../src_plugins
 CFLAGS=@/local/pcb/c89flags@ @/local/pcb/CFLAGS@
 LDFLAGS=-lm @/local/pcb/LDFLAGS@
@@ -12,7 +13,6 @@ CC=@cc/cc@
 HASHOBJ=../../src_3rd/liblihata/genht/hash.o ../../src_3rd/liblihata/genht/htsp.o ../../src_3rd/liblihata/genht/htpp.o
 VECTOBJ=../../src_3rd/genvector/gds_char.o ../../src_3rd/genvector/vtp0.o ../../src_3rd/genvector/vts0.o
 LISTOBJ=../../src_3rd/genlist/genadlist.o ../../src_3rd/genlist/genlistalloc.o
-SCCFOBJ=../../scconfig/src/default/str.o
 QPARSE=../../src_3rd/qparse/qparse.o
 LHTOBJ= \
 	../../src_3rd/liblihata/parser.o \
@@ -65,36 +65,19 @@ all:
 revcheck:
 	cd ../../scconfig && ./revtest Rev.stamp < Rev.tab
 
-gsch2pcb-rnd$(EXE): $(OBJS)  $(CONF_OBJS) $(HASHOBJ) $(VECTOBJ) $(LISTOBJ) $(SCCFOBJ) $(QPARSE) $(FP_OBJS) $(LHTOBJ)
-	$(CC) $(OBJS) $(CONF_OBJS)  $(FP_OBJS) $(HASHOBJ) $(VECTOBJ) $(LISTOBJ) $(SCCFOBJ) $(QPARSE) $(LHTOBJ) -o gsch2pcb-rnd$(EXE) $(LDFLAGS) $(FP_LDFLAGS)
+gsch2pcb-rnd$(EXE): $(OBJS)  $(CONF_OBJS) $(HASHOBJ) $(VECTOBJ) $(LISTOBJ) $(QPARSE) $(FP_OBJS) $(LHTOBJ)
+	$(CC) $(OBJS) $(CONF_OBJS)  $(FP_OBJS) $(HASHOBJ) $(VECTOBJ) $(LISTOBJ) $(QPARSE) $(LHTOBJ) -o gsch2pcb-rnd$(EXE) $(LDFLAGS) $(FP_LDFLAGS)
 
 gsch2pcb.o: gsch2pcb.c ../../config.h
 	$(CC) -c $(CFLAGS) $(FP_CFLAGS) gsch2pcb.c -o gsch2pcb.o
 
-../../src/pcb-rnd:
-	cd ../../src && make
-
-$(HASHOBJ): ../../src/pcb-rnd
-
-$(QPARSE): ../../src/pcb-rnd
-
-../../src_3rd/genvector/gds_char.o:
-	$(CC) -c $(CFLAGS) ../../src_3rd/genvector/gds_char.c -o ../../src_3rd/genvector/gds_char.o
-
-../../src_3rd/genvector/vtp0.o:
-	$(CC) -c $(CFLAGS) ../../src_3rd/genvector/vtp0.c -o ../../src_3rd/genvector/vtp0.o
-
-../../src_3rd/genvector/vts0.o:
-	$(CC) -c $(CFLAGS) ../../src_3rd/genvector/vts0.c -o ../../src_3rd/genvector/vts0.o
-
-../../src_3rd/genadlist/genadlist.o:
-	$(CC) -c $(CFLAGS) ../../src_3rd/genlist/genadlist.c -o ../../src_3rd/genlist/genadlist.o
-
+# TODO: this should be the base lib only
+# run the Makefile in src for the common objects:
+$(HASHOBJ) $(QPARSE) $(LHTOBJ) \
+../../src_3rd/genvector/gds_char.o ../../src_3rd/genvector/vtp0.o \
+../../src_3rd/genvector/vts0.o ../../src_3rd/genadlist/genadlist.o \
 ../../src_3rd/genadlist/genlistalloc.o:
-	$(CC) -c $(CFLAGS) ../../src_3rd/genlist/genlistalloc.c -o ../../src_3rd/genlist/genlistalloc.o
-
-
-
+	cd ../../src && $(MAKE) util_deps
 
 ##### module rules begin #####
 @/local/pcb/RULES@
@@ -112,29 +95,27 @@ gsch2pcb.o: gsch2pcb_rnd_conf_fields.h
 gsch2pcb_rnd_conf_fields.h: gsch2pcb_rnd_conf.h
 	AWK=@/host/fstools/awk@ ../../scconfig/gen_conf.sh < gsch2pcb_rnd_conf.h > gsch2pcb_rnd_conf_fields.h
 
-install_:
-	$(MKDIR) "$(BINDIR)" "$(LIBDIR)"
-	$(CPC) "`pwd`/gsch2pcb-rnd$(EXE)" "$(BINDIR)/gsch2pcb-rnd$(EXE)"
-	$(CPC) "`pwd`/gnet-gsch2pcb-rnd.scm" "$(LIBDIR)/gnet-gsch2pcb-rnd.scm"
+install_all:
+	$(SCCBOX) mkdir -p "$(BINDIR)" "$(LIBDIR)"
+	$(SCCBOX) $(HOW) "gsch2pcb-rnd$(EXE)" "$(BINDIR)/gsch2pcb-rnd$(EXE)"
+	$(SCCBOX) $(HOW) "gnet-gsch2pcb-rnd.scm" "$(LIBDIR)/gnet-gsch2pcb-rnd.scm"
 
 install:
-	$(MAKE) install_ CPC="$(CP)"
+	$(MAKE) install_all HOW="install"
 
 linstall:
-	$(MAKE) install_ CPC="$(LN)"
+	$(MAKE) install_all HOW="linstall -f"
 
 uninstall:
-	$(RM) "$(BINDIR)/gsch2pcb-rnd$(EXE)"
-	$(RM) "$(LIBDIR)/gnet-gsch2pcb-rnd.scm"
-
+	$(MAKE) install_all HOW="uninstall"
 
 clean:
-	-$(RM) gsch2pcb-rnd$(EXE) $(OBJS) gsch2pcb_rnd_conf_fields.h
+	$(SCCBOX) rm -f -q gsch2pcb-rnd$(EXE) $(OBJS) gsch2pcb_rnd_conf_fields.h
 
 distclean: clean
-	-$(RM) fp_init.c fp_init.h
+	$(SCCBOX) rm -f -q fp_init.c fp_init.h
 
-include ../../Makefile.conf
+include $(ROOT)/Makefile.conf
 
 @]
 
diff --git a/util/gsch2pcb-rnd/glue.c b/util/gsch2pcb-rnd/glue.c
index 6462a21..7e17ce6 100644
--- a/util/gsch2pcb-rnd/glue.c
+++ b/util/gsch2pcb-rnd/glue.c
@@ -19,6 +19,8 @@
 #include <stdio.h>
 #include <stdarg.h>
 #include "../src/error.h"
+#include "../src/plugins.h"
+#include "gsch2pcb_rnd_conf.h"
 
 /* glue for pcb-rnd core */
 
@@ -59,3 +61,11 @@ void pcb_trace(const char *Format, ...)
 
 const char *pcb_board_get_filename(void) { return NULL; }
 const char *pcb_board_get_name(void) { return NULL; }
+
+pcb_plugin_info_t *pcb_plugin_register(const char *name, const char *path, void *handle, int dynamic_loaded, void (*uninit)(void))
+{
+	static pcb_plugin_info_t pif;
+	if (conf_g2pr.utils.gsch2pcb_rnd.verbose)
+		printf("Plugin loaded: %s (%s)\n", name, path);
+	return &pif;
+}
diff --git a/util/gsch2pcb-rnd/gsch2pcb.c b/util/gsch2pcb-rnd/gsch2pcb.c
index a554308..b770cd2 100644
--- a/util/gsch2pcb-rnd/gsch2pcb.c
+++ b/util/gsch2pcb-rnd/gsch2pcb.c
@@ -42,6 +42,7 @@
 #include "../src/plugins.h"
 #include "../src/compat_misc.h"
 #include "../src/compat_fs.h"
+#include "../src/misc_util.h"
 #include "method.h"
 #include "help.h"
 #include "gsch2pcb_rnd_conf.h"
@@ -260,7 +261,7 @@ static void load_extra_project_files(void)
 	load_project("/etc/gsch2pcb");
 	load_project("/usr/local/etc/gsch2pcb");
 
-	path = str_concat(PCB_DIR_SEPARATOR_S, conf_core.rc.path.home, ".gEDA", "gsch2pcb", NULL);
+	path = pcb_concat(conf_core.rc.path.home, PCB_DIR_SEPARATOR_S, ".gEDA", PCB_DIR_SEPARATOR_S, "gsch2pcb", NULL);
 	load_project(path);
 	free(path);
 
@@ -350,14 +351,6 @@ static void get_args(int argc, char ** argv)
 	}
 }
 
-pcb_plugin_info_t *pcb_plugin_register(const char *name, const char *path, void *handle, int dynamic_loaded, void (*uninit)(void))
-{
-	static pcb_plugin_info_t pif;
-	if (conf_g2pr.utils.gsch2pcb_rnd.verbose)
-		printf("Plugin loaded: %s (%s)\n", name, path);
-	return &pif;
-}
-
 void free_strlist(gadl_list_t *lst)
 {
 	char **s;
diff --git a/util/gsch2pcb-rnd/gsch2pcb.h b/util/gsch2pcb-rnd/gsch2pcb.h
index f29fd58..da4c0e1 100644
--- a/util/gsch2pcb-rnd/gsch2pcb.h
+++ b/util/gsch2pcb-rnd/gsch2pcb.h
@@ -10,9 +10,6 @@
 
 #define SEP_STRING "--------\n"
 
-/* from scconfig str lib: */
-char *str_concat(const char *sep, ...);
-
 typedef struct {
 	char *refdes, *value, *description, *changed_description, *changed_value;
 	char *flags, *tail;
diff --git a/util/gsch2pcb-rnd/method_import.c b/util/gsch2pcb-rnd/method_import.c
index dbef1b6..3148089 100644
--- a/util/gsch2pcb-rnd/method_import.c
+++ b/util/gsch2pcb-rnd/method_import.c
@@ -31,6 +31,7 @@
 #include "../src/conf_core.h"
 #include "../src/compat_misc.h"
 #include "../src/compat_fs.h"
+#include "../src/misc_util.h"
 
 char *cmd_file_name;
 char *pcb_file_name;
@@ -38,9 +39,9 @@ char *net_file_name;
 
 static void method_import_init(void)
 {
-	pcb_file_name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".pcb", NULL);
-	cmd_file_name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".cmd", NULL);
-	net_file_name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".net", NULL);
+	pcb_file_name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".pcb", NULL);
+	cmd_file_name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".cmd", NULL);
+	net_file_name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".net", NULL);
 	local_project_pcb_name = pcb_file_name;
 }
 
@@ -98,11 +99,11 @@ static int method_import_guess_out_name(void)
 	int res;
 	char *name;
 	
-	name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".lht", NULL);
+	name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".lht", NULL);
 	res = pcb_file_readable(name);
 	free(name);
 	if (!res) {
-		name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".pcb.lht", NULL);
+		name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".pcb.lht", NULL);
 		res = pcb_file_readable(name);
 		free(name);
 	}
diff --git a/util/gsch2pcb-rnd/method_pcb.c b/util/gsch2pcb-rnd/method_pcb.c
index 798b372..9e97ff0 100644
--- a/util/gsch2pcb-rnd/method_pcb.c
+++ b/util/gsch2pcb-rnd/method_pcb.c
@@ -36,6 +36,7 @@
 #include "../src/compat_fs.h"
 #include "../src/plugins.h"
 #include "../src/plug_footprint.h"
+#include "../src/misc_util.h"
 
 static const char *element_search_path = NULL; /* queried once from the config, when the config is already stable */
 
@@ -383,7 +384,7 @@ static void prune_elements(char * pcb_file, char * bak)
 		fprintf(stderr, "error: can not read %s\n", pcb_file);
 		return;
 	}
-	tmp = str_concat(NULL, pcb_file, ".tmp", NULL);
+	tmp = pcb_concat(pcb_file, ".tmp", NULL);
 	if ((f_out = fopen(tmp, "wb")) == NULL) {
 		fprintf(stderr, "error: can not write %s\n", tmp);
 		fclose(f_in);
@@ -452,7 +453,7 @@ static int add_elements(char * pcb_file)
 
 	if ((f_in = fopen(pcb_file, "r")) == NULL)
 		return 0;
-	tmp_file = str_concat(NULL, pcb_file, ".tmp", NULL);
+	tmp_file = pcb_concat(pcb_file, ".tmp", NULL);
 	if ((f_out = fopen(tmp_file, "wb")) == NULL) {
 		fclose(f_in);
 		free(tmp_file);
@@ -559,7 +560,7 @@ static void update_element_descriptions(char * pcb_file, char * bak)
 	}
 	if ((f_in = fopen(pcb_file, "r")) == NULL)
 		return;
-	tmp = str_concat(NULL, pcb_file, ".tmp", NULL);
+	tmp = pcb_concat(pcb_file, ".tmp", NULL);
 	if ((f_out = fopen(tmp, "wb")) == NULL) {
 		fclose(f_in);
 		return;
@@ -644,9 +645,9 @@ static char *pcb_file_name, *pcb_new_file_name, *bak_file_name, *pins_file_name,
 static void method_pcb_init(void)
 {
 	pcb_fp_init();
-	pins_file_name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".cmd", NULL);
-	net_file_name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".net", NULL);
-	pcb_file_name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".pcb", NULL);
+	pins_file_name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".cmd", NULL);
+	net_file_name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".net", NULL);
+	pcb_file_name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".pcb", NULL);
 	local_project_pcb_name = pcb_file_name;
 }
 
@@ -704,7 +705,7 @@ static void method_pcb_go()
 
 	if (pcb_file_readable(pcb_file_name)) {
 		initial_pcb = FALSE;
-		pcb_new_file_name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".new.pcb", NULL);
+		pcb_new_file_name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".new.pcb", NULL);
 		get_pcb_element_list(pcb_file_name);
 	}
 	else
@@ -790,7 +791,7 @@ static void method_pcb_go()
 static int method_pcb_guess_out_name(void)
 {
 	int res;
-	char *name = str_concat(NULL, conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".pcb", NULL);
+	char *name = pcb_concat(conf_g2pr.utils.gsch2pcb_rnd.sch_basename, ".pcb", NULL);
 	res = pcb_file_readable(name);
 	free(name);
 	return res;
diff --git a/util/gsch2pcb-rnd/netlister.c b/util/gsch2pcb-rnd/netlister.c
index e9eaa80..c1667c6 100644
--- a/util/gsch2pcb-rnd/netlister.c
+++ b/util/gsch2pcb-rnd/netlister.c
@@ -40,6 +40,7 @@
 #include "../src/compat_misc.h"
 #include "gsch2pcb_rnd_conf.h"
 #include "gsch2pcb.h"
+#include "../src/misc_util.h"
 #include "run.h"
 
 const char *gnetlist_name(void)
@@ -95,7 +96,7 @@ int run_gnetlist(const char *pins_file, const char *net_file, const char *pcb_fi
 		char *out_file;
 		char *backend;
 		if (!s2) {
-			out_file = str_concat(NULL, basename, ".", s, NULL);
+			out_file = pcb_concat(basename, ".", s, NULL);
 			backend = pcb_strdup(s);
 		}
 		else {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-electronics/pcb-rnd.git



More information about the Pkg-electronics-commits mailing list