summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2018-03-19 19:55:58 +0100
committerJörg Frings-Fürst <debian@jff-webhosting.net>2018-03-19 19:55:58 +0100
commitd1a8285f818eb7e5c3d6a05709ea21a808490b8c (patch)
tree326578f0505cbed07cfe60de530022822dc237ac
parent16e9630b79f0a7a90c6cedb6781175bb8b337dc1 (diff)
New upstream version 5.1.0upstream/5.1.0
-rw-r--r--CMake/FindCMocka.cmake4
-rw-r--r--CMake/FindGTKUnixPrint.cmake (renamed from app/wlib/gtklib/FindGTKUnixPrint.cmake)0
-rw-r--r--CMake/FindPandoc.cmake18
-rw-r--r--CMakeLists.txt78
-rw-r--r--app/CMakeLists.txt2
-rw-r--r--app/FindPkgConfig.cmake360
-rw-r--r--app/bin/CMakeLists.txt30
-rw-r--r--app/bin/ChangeLog495
-rw-r--r--app/bin/acclkeys.h3
-rw-r--r--app/bin/appdefaults.c435
-rw-r--r--app/bin/bdf2xtp.c10
-rw-r--r--app/bin/bitmaps/bezier.xpm23
-rw-r--r--app/bin/bitmaps/dbezier.xpm22
-rw-r--r--app/bin/bitmaps/ecornu.xpm23
-rw-r--r--app/bin/bitmaps/eltsharp.xpm21
-rw-r--r--app/bin/bitmaps/helix.xpm21
-rw-r--r--app/bin/bitmaps/map.xpm22
-rw-r--r--app/bin/bitmaps/pan.xpm22
-rw-r--r--app/bin/cbezier.c1153
-rw-r--r--app/bin/cbezier.h53
-rw-r--r--app/bin/cblock.c31
-rw-r--r--app/bin/ccontrol.c25
-rw-r--r--app/bin/ccornu.c1240
-rw-r--r--app/bin/ccornu.h23
-rw-r--r--app/bin/ccurve.c241
-rw-r--r--app/bin/ccurve.h18
-rw-r--r--app/bin/cdraw.c204
-rw-r--r--app/bin/celev.c18
-rw-r--r--app/bin/cgroup.c52
-rw-r--r--app/bin/chndldto.c18
-rw-r--r--app/bin/chotbar.c47
-rw-r--r--app/bin/cjoin.c105
-rw-r--r--app/bin/cjoin.h15
-rw-r--r--app/bin/cmisc.c774
-rw-r--r--app/bin/cmodify.c153
-rw-r--r--app/bin/cnote.c638
-rw-r--r--app/bin/common.h23
-rw-r--r--app/bin/compound.c253
-rw-r--r--app/bin/compound.h10
-rw-r--r--app/bin/cparalle.c15
-rw-r--r--app/bin/cprint.c101
-rw-r--r--app/bin/cprofile.c18
-rw-r--r--app/bin/cpull.c102
-rw-r--r--app/bin/cruler.c7
-rw-r--r--app/bin/cselect.c261
-rw-r--r--app/bin/cselect.h12
-rw-r--r--app/bin/csensor.c27
-rw-r--r--app/bin/csignal.c38
-rw-r--r--app/bin/csnap.c16
-rw-r--r--app/bin/csplit.c22
-rw-r--r--app/bin/cstraigh.c80
-rw-r--r--app/bin/cstraigh.h12
-rw-r--r--app/bin/cstruct.c28
-rw-r--r--app/bin/cswitchmotor.c23
-rw-r--r--app/bin/ctext.c94
-rw-r--r--app/bin/ctodesgn.c20
-rw-r--r--app/bin/ctrain.c4680
-rw-r--r--app/bin/ctrain.h10
-rw-r--r--app/bin/cturnout.c168
-rw-r--r--app/bin/cturntbl.c64
-rw-r--r--app/bin/cundo.c17
-rw-r--r--app/bin/cundo.h12
-rw-r--r--app/bin/custom.c16
-rw-r--r--app/bin/custom.h18
-rw-r--r--app/bin/dbench.c9
-rw-r--r--app/bin/dbitmap.c29
-rw-r--r--app/bin/dcar.c45
-rw-r--r--app/bin/dcmpnd.c14
-rw-r--r--app/bin/dcontmgm.c13
-rw-r--r--app/bin/dcustmgm.c25
-rw-r--r--app/bin/dease.c110
-rw-r--r--app/bin/denum.c31
-rw-r--r--app/bin/dlayer.c1538
-rw-r--r--app/bin/doption.c221
-rw-r--r--app/bin/dpricels.c21
-rw-r--r--app/bin/dprmfile.c65
-rw-r--r--app/bin/draw.c684
-rw-r--r--app/bin/draw.h14
-rw-r--r--app/bin/drawgeom.c306
-rw-r--r--app/bin/drawgeom.h20
-rw-r--r--app/bin/dxfformat.c2
-rw-r--r--app/bin/dxfformat.h24
-rw-r--r--app/bin/dxfoutput.c16
-rw-r--r--app/bin/elev.c15
-rw-r--r--app/bin/fileio.c229
-rw-r--r--app/bin/fileio.h19
-rw-r--r--app/bin/i18n.c7
-rw-r--r--app/bin/layout.c375
-rw-r--r--app/bin/layout.h56
-rw-r--r--app/bin/lprintf.c16
-rw-r--r--app/bin/macro.c123
-rw-r--r--app/bin/misc.c375
-rw-r--r--app/bin/misc.h30
-rw-r--r--app/bin/misc2.c98
-rw-r--r--app/bin/misc2.h30
-rw-r--r--app/bin/param.c391
-rw-r--r--app/bin/param.h13
-rw-r--r--app/bin/paths.c220
-rw-r--r--app/bin/paths.h (renamed from app/help/pageorder.c)40
-rw-r--r--app/bin/shrtpath.c4
-rw-r--r--app/bin/shrtpath.h10
-rw-r--r--app/bin/smalldlg.c32
-rw-r--r--app/bin/smalldlg.h4
-rw-r--r--app/bin/tbezier.c1629
-rw-r--r--app/bin/tbezier.h57
-rw-r--r--app/bin/tcornu.c1321
-rw-r--r--app/bin/tcornu.h66
-rw-r--r--app/bin/tcurve.c170
-rw-r--r--app/bin/tease.c36
-rw-r--r--app/bin/track.c270
-rw-r--r--app/bin/track.h161
-rw-r--r--app/bin/trackx.h9
-rw-r--r--app/bin/trkseg.c599
-rw-r--r--app/bin/tstraigh.c55
-rw-r--r--app/bin/unittest/CMakeLists.txt21
-rw-r--r--app/bin/unittest/defaultstest.c110
-rw-r--r--app/bin/unittest/pathstest.c121
-rw-r--r--app/bin/uthash.h960
-rw-r--r--app/bin/utility.c16
-rw-r--r--app/bin/utility.h8
-rw-r--r--app/bin/version.h7
-rw-r--r--app/cornu/CMakeLists.txt27
-rw-r--r--app/cornu/bezctx.c48
-rw-r--r--app/cornu/bezctx.h13
-rw-r--r--app/cornu/bezctx_intf.h23
-rw-r--r--app/cornu/bezctx_xtrkcad.c217
-rw-r--r--app/cornu/bezctx_xtrkcad.h4
-rw-r--r--app/cornu/ppedit_gtk1.c930
-rw-r--r--app/cornu/spiro.c1099
-rw-r--r--app/cornu/spiro.h22
-rw-r--r--app/cornu/spiroentrypoints.c60
-rw-r--r--app/cornu/spiroentrypoints.h31
-rw-r--r--app/cornu/zmisc.h12
-rw-r--r--app/doc/CMakeLists.txt2
-rw-r--r--app/doc/ChangeLog24
-rw-r--r--app/doc/addm.but31
-rw-r--r--app/doc/changem.but293
-rw-r--r--app/doc/doc.vcproj154
-rw-r--r--app/doc/drawm.but36
-rw-r--r--app/doc/filem.but6
-rw-r--r--app/doc/intro.but.in8
-rw-r--r--app/doc/managem.but4
-rw-r--r--app/doc/navigation.but6
-rw-r--r--app/doc/optionm.but24
-rw-r--r--app/doc/osxconf.but4
-rw-r--r--app/doc/png.d/bezier.pngbin0 -> 3866 bytes
-rw-r--r--app/doc/png.d/bmap.pngbin0 -> 353 bytes
-rw-r--r--app/doc/png.d/cmdopt.pngbin8213 -> 19624 bytes
-rw-r--r--app/doc/png.d/dbezier.pngbin0 -> 3776 bytes
-rw-r--r--app/doc/png.d/displayopt.pngbin37583 -> 68298 bytes
-rw-r--r--app/doc/png.d/dproperties.pngbin9213 -> 43970 bytes
-rw-r--r--app/doc/png.d/easew.pngbin5361 -> 12509 bytes
-rw-r--r--app/doc/png.d/joincornu1.pngbin0 -> 4784 bytes
-rw-r--r--app/doc/png.d/joincornu2.pngbin0 -> 5997 bytes
-rw-r--r--app/doc/png.d/joincornu3.pngbin0 -> 7406 bytes
-rw-r--r--app/doc/png.d/joincornu4.pngbin0 -> 11409 bytes
-rw-r--r--app/doc/png.d/joincornu5.pngbin0 -> 7154 bytes
-rw-r--r--app/doc/png.d/layout.pngbin7843 -> 13213 bytes
-rw-r--r--app/doc/png.d/mchange.pngbin6461 -> 23214 bytes
-rw-r--r--app/doc/png.d/mdraw.pngbin2585 -> 10174 bytes
-rw-r--r--app/doc/png.d/mrotatealign.pngbin2552 -> 12893 bytes
-rw-r--r--app/doc/png.d/mrotatefixed.pngbin2727 -> 12910 bytes
-rw-r--r--app/doc/png.d/mrotatemove.pngbin2590 -> 12872 bytes
-rw-r--r--app/doc/png.d/mview.pngbin6712 -> 15591 bytes
-rw-r--r--app/doc/png.d/pan.pngbin0 -> 3929 bytes
-rw-r--r--app/doc/png.d/toolbar.pngbin12627 -> 13676 bytes
-rw-r--r--app/doc/view_winm.but2
-rw-r--r--app/doxfileversionfilter.sh12
-rw-r--r--app/dynstring/dynstring.c10
-rw-r--r--app/dynstring/dynstring.h26
-rw-r--r--app/help/ChangeLog63
-rw-r--r--app/help/fixbmp.c227
-rw-r--r--app/help/genhelp.in32
-rw-r--r--app/help/genmessages.c559
-rw-r--r--app/help/messages.in40
-rwxr-xr-xapp/help/mkpngbutt21
-rwxr-xr-xapp/help/mkpngs88
-rw-r--r--app/help/mkshg.c455
-rwxr-xr-xapp/help/mkshgs348
-rw-r--r--app/help/mkxpmbutt.c303
-rw-r--r--app/help/prochelp.c2178
-rw-r--r--app/help/readpng.c275
-rw-r--r--app/help/readpng.h64
-rw-r--r--app/help/xtrkcad.info10
-rw-r--r--app/help/xtrkcad.tip3
-rw-r--r--app/help/xvfontsel.hlpsrc25
-rw-r--r--app/help/xvprintsel.hlpsrc73
-rw-r--r--app/i18n/ChangeLog22
-rw-r--r--app/i18n/de_DE.po25391
-rw-r--r--app/i18n/fi.po18286
-rw-r--r--app/i18n/pt_BR.po9253
-rw-r--r--app/lib/CHANGELOG.md199
-rw-r--r--app/lib/CMakeLists.txt54
-rw-r--r--app/lib/Readme.md269
-rw-r--r--app/lib/Readme.txt559
-rw-r--r--app/lib/examples/DVRR v3.0 E Stroudsburg - Pt Jervis.xtc34
-rw-r--r--app/lib/mdtotxt.bat3
-rw-r--r--app/lib/params/Any-CTC_panel.xtp88
-rw-r--r--app/lib/params/AtlasTrueTrk.xtp12
-rw-r--r--app/lib/params/BachmannEZ-HO.xtp42
-rw-r--r--app/lib/params/BachmannEZ-N.xtp56
-rw-r--r--app/lib/params/ChangeLog87
-rw-r--r--app/lib/params/F-NMRA-RP12-21.xtp592
-rw-r--r--app/lib/params/G-NMRA-RP12-23.xtp592
-rw-r--r--app/lib/params/HO-Frateschi.xtp390
-rw-r--r--app/lib/params/HO-LifeLike-Power-Loc.xtp8
-rw-r--r--app/lib/params/HO-MicroEngineering.xtp160
-rw-r--r--app/lib/params/HO-Peco-Code100Setrack.xtp (renamed from app/lib/params/pecohost.xtp)14
-rw-r--r--app/lib/params/HO-Peco-Code100Streamline.xtp (renamed from app/lib/params/pecoho.xtp)145
-rw-r--r--app/lib/params/HO-Peco-Code75Finescale.xtp288
-rw-r--r--app/lib/params/HO-Peco-Code83.xtp (renamed from app/lib/params/pecoho83.xtp)381
-rw-r--r--app/lib/params/HO-WalthCornerstone 1.xtp4385
-rw-r--r--app/lib/params/HO-atl100ho.xtp970
-rw-r--r--app/lib/params/HOn3-BlackStoneProTraxx.xtp42
-rw-r--r--app/lib/params/HOn30_Minitrains.xtp148
-rw-r--r--app/lib/params/LifeLike-N.xtp4
-rw-r--r--app/lib/params/Lionel-O-O27.xtp38
-rw-r--r--app/lib/params/Lionel-O.xtp25
-rw-r--r--app/lib/params/Lionel27.xtp22
-rw-r--r--app/lib/params/LionelFasttrack.xtp40
-rw-r--r--app/lib/params/N-AtlasTrueTrack.xtp14
-rw-r--r--app/lib/params/N-LifeLike Power-Loc.xtp4
-rw-r--r--app/lib/params/N-NScaleArchitect.xtp2
-rw-r--r--app/lib/params/N-PecoCode55Finescale.xtp (renamed from app/lib/params/pecon55.xtp)146
-rw-r--r--app/lib/params/N-PecoCode80Setrack.xtp (renamed from app/lib/params/peconst.xtp)347
-rw-r--r--app/lib/params/N-PecoCode80Streamline.xtp (renamed from app/lib/params/pecon80.xtp)149
-rw-r--r--app/lib/params/N-fl.xtp (renamed from app/lib/params/rocon.xtp)156
-rw-r--r--app/lib/params/N-kato-n-gl-trk.xtp38
-rw-r--r--app/lib/params/N-kato-turntable.xtp38
-rw-r--r--app/lib/params/N-kato.xtp3395
-rw-r--r--app/lib/params/N-walth-n.xtp3050
-rw-r--r--app/lib/params/O-ETS TramTrack.xtp194
-rw-r--r--app/lib/params/O-ETS.xtp466
-rw-r--r--app/lib/params/O-Lehnhardt Tramrails.xtp360
-rw-r--r--app/lib/params/O-Lenz.xtp366
-rw-r--r--app/lib/params/O-RealTrax.xtp8
-rw-r--r--app/lib/params/O-Ross.xtp262
-rw-r--r--app/lib/params/On14mm KBScale.xtp31
-rw-r--r--app/lib/params/On30-FastTrack.xtp2
-rw-r--r--app/lib/params/On30.xtp100
-rw-r--r--app/lib/params/Piko-A.xtp32
-rw-r--r--app/lib/params/Piko-g.xtp12
-rw-r--r--app/lib/params/ProZ-Track.xtp4
-rw-r--r--app/lib/params/RocoGeoLineHO.xtp12
-rw-r--r--app/lib/params/S-SHelper S-Trax.xtp2
-rw-r--r--app/lib/params/S-Trax.xtp3
-rw-r--r--app/lib/params/T-Eishindo.xtp658
-rw-r--r--app/lib/params/TT-Roco-Turntable.xtp24
-rw-r--r--app/lib/params/TT-TilligAdvBeddingTrack.xtp514
-rw-r--r--app/lib/params/TTi-AuhagenNG.xtp80
-rw-r--r--app/lib/params/TilligAdvTT.xtp647
-rw-r--r--app/lib/params/TilligH0EliteCode83.xtp1586
-rw-r--r--app/lib/params/TilligH0e.xtp148
-rw-r--r--app/lib/params/TilligH0m.xtp148
-rw-r--r--app/lib/params/TilligTTModellGS.xtp1662
-rw-r--r--app/lib/params/Z-Atlas55.xtp39
-rw-r--r--app/lib/params/Z-Rokuhan.xtp2207
-rw-r--r--app/lib/params/arnold.xtp34
-rw-r--r--app/lib/params/atl83ho.xtp145
-rw-r--r--app/lib/params/atlascho.cars20
-rw-r--r--app/lib/params/atlascn.xtp16
-rw-r--r--app/lib/params/atlaseho.cars12
-rw-r--r--app/lib/params/atlasen.xtp60
-rw-r--r--app/lib/params/atlaso2rail.xtp25
-rw-r--r--app/lib/params/ctlpanel.xtp16
-rw-r--r--app/lib/params/fl-model.xtp24
-rw-r--r--app/lib/params/fl-profi.xtp28
-rw-r--r--app/lib/params/flnpicco.xtp104
-rw-r--r--app/lib/params/gargrv-o.xtp22
-rw-r--r--app/lib/params/ho-amb.xtp2
-rw-r--r--app/lib/params/hubner1.xtp44
-rw-r--r--app/lib/params/kato-ho.xtp1039
-rw-r--r--app/lib/params/kato-n-DblTrk.xtp28
-rw-r--r--app/lib/params/kato-n.xtp3278
-rw-r--r--app/lib/params/lgb.xtp82
-rw-r--r--app/lib/params/minitrix.xtp4
-rw-r--r--app/lib/params/mkcarpart.c26
-rw-r--r--app/lib/params/mrkholde.xtp52
-rw-r--r--app/lib/params/mrkhomde.xtp108
-rw-r--r--app/lib/params/mrklnhom.xtp66
-rw-r--r--app/lib/params/mrklnz.xtp112
-rw-r--r--app/lib/params/mtl-z.xtp506
-rw-r--r--app/lib/params/peco turntable wo routes.xtp36
-rw-r--r--app/lib/params/pecohom.xtp2
-rw-r--r--app/lib/params/rocho83.xtp38
-rw-r--r--app/lib/params/tomix-n.xtp3376
-rwxr-xr-xapp/lib/xdg-open972
-rw-r--r--app/lib/xtrkcad.xtq16
-rw-r--r--app/tools/CMakeLists.txt19
-rw-r--r--app/tools/addcrlf.c242
-rw-r--r--app/tools/bin2c.c126
-rw-r--r--app/tools/halibut/bk_html.c2
-rw-r--r--app/tools/listxtp.c7
-rw-r--r--app/tools/oldscripts/README4
-rw-r--r--app/tools/oldscripts/checkall10
-rw-r--r--app/tools/oldscripts/diffall37
-rw-r--r--app/tools/oldscripts/fetchall46
-rw-r--r--app/tools/oldscripts/makeall23
-rw-r--r--app/tools/oldscripts/markall17
-rw-r--r--app/tools/oldscripts/mkwinrlse34
-rw-r--r--app/tools/oldscripts/roall22
-rw-r--r--app/wlib/gtklib/CMakeLists.txt68
-rw-r--r--app/wlib/gtklib/ChangeLog250
-rw-r--r--app/wlib/gtklib/bitmap.c1
-rw-r--r--app/wlib/gtklib/boxes.c1
-rw-r--r--app/wlib/gtklib/browserhelp.c137
-rw-r--r--app/wlib/gtklib/button.c4
-rw-r--r--app/wlib/gtklib/control.c22
-rw-r--r--app/wlib/gtklib/droplist.c2
-rw-r--r--app/wlib/gtklib/font.c11
-rw-r--r--app/wlib/gtklib/gtkdraw-cairo.c47
-rw-r--r--app/wlib/gtklib/gtkint.h8
-rw-r--r--app/wlib/gtklib/ixhelp.c14
-rw-r--r--app/wlib/gtklib/list.c2
-rw-r--r--app/wlib/gtklib/liststore.c20
-rw-r--r--app/wlib/gtklib/main.c1
-rw-r--r--app/wlib/gtklib/menu.c21
-rw-r--r--app/wlib/gtklib/message.c76
-rw-r--r--app/wlib/gtklib/notice.c3
-rw-r--r--app/wlib/gtklib/png.c1
-rw-r--r--app/wlib/gtklib/print.c65
-rw-r--r--app/wlib/gtklib/statusbar.c211
-rw-r--r--app/wlib/gtklib/text.c4
-rw-r--r--app/wlib/gtklib/tooltip.c31
-rw-r--r--app/wlib/gtklib/treeview.c1
-rw-r--r--app/wlib/gtklib/util.c235
-rw-r--r--app/wlib/gtklib/window.c268
-rw-r--r--app/wlib/gtklib/wpref.c10
-rw-r--r--app/wlib/include/wcolors.h80
-rw-r--r--app/wlib/include/wlib.h57
-rw-r--r--app/wlib/mswlib/CMakeLists.txt1
-rw-r--r--app/wlib/mswlib/ChangeLog146
-rw-r--r--app/wlib/mswlib/mswbitmap.c26
-rw-r--r--app/wlib/mswlib/mswbutt.c22
-rw-r--r--app/wlib/mswlib/mswdraw.c8
-rw-r--r--app/wlib/mswlib/mswedit.c2
-rw-r--r--app/wlib/mswlib/mswlist.c6
-rw-r--r--app/wlib/mswlib/mswmenu.c8
-rw-r--r--app/wlib/mswlib/mswmisc.c4811
-rw-r--r--app/wlib/mswlib/mswmsg.c4
-rw-r--r--app/wlib/mswlib/mswpref.c10
-rw-r--r--app/wlib/mswlib/mswsplash.c9
-rw-r--r--app/wlib/mswlib/mswstatus.c110
-rw-r--r--app/wlib/mswlib/mswtext.c636
-rw-r--r--distribution/CMakeLists.txt2
-rw-r--r--distribution/downloadpage.wiki.in46
-rw-r--r--distribution/osx/gtk-bundle/CMakeLists.txt2
-rw-r--r--distribution/osx/gtk-bundle/gtk-bundle.README21
-rw-r--r--distribution/posix/CMakeLists.txt45
-rw-r--r--distribution/posix/xtrkcad.spec5
-rw-r--r--distribution/win32/nsis/install.nsh6
351 files changed, 75963 insertions, 53327 deletions
diff --git a/CMake/FindCMocka.cmake b/CMake/FindCMocka.cmake
index e8a4e92..bec2905 100644
--- a/CMake/FindCMocka.cmake
+++ b/CMake/FindCMocka.cmake
@@ -21,6 +21,10 @@
#=============================================================================
#
+
+set (CMOCKA_ROOT_DIR
+ "C:/Users/Martin/Documents/CMocka")
+
find_path(CMOCKA_INCLUDE_DIR
NAMES
cmocka.h
diff --git a/app/wlib/gtklib/FindGTKUnixPrint.cmake b/CMake/FindGTKUnixPrint.cmake
index 06bc548..06bc548 100644
--- a/app/wlib/gtklib/FindGTKUnixPrint.cmake
+++ b/CMake/FindGTKUnixPrint.cmake
diff --git a/CMake/FindPandoc.cmake b/CMake/FindPandoc.cmake
new file mode 100644
index 0000000..1a076ff
--- /dev/null
+++ b/CMake/FindPandoc.cmake
@@ -0,0 +1,18 @@
+# This module looks for Pandoc, and sets PANDOC_EXECUTABLE to the
+# location of its binary.
+#
+# It respects the variable Pandoc_FIND_QUIETLY
+
+include(FindPackageHandleStandardArgs)
+
+if(DEFINED PANDOC_EXECUTABLE)
+ set(Pandoc_FIND_QUIETLY TRUE)
+endif()
+
+find_program(PANDOC_EXECUTABLE
+ NAMES pandoc
+ DOC "Pandoc - a universal document converter")
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Pandoc REQUIRED_VARS PANDOC_EXECUTABLE)
+
+mark_as_advanced(PANDOC_EXECUTABLE) \ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f0a9a9..0ec8908 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,27 +1,33 @@
PROJECT(XTrkCAD)
enable_testing()
+cmake_minimum_required(VERSION 3.0)
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
-SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/app)
+
# additional CMake modules can be found here
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/")
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
# Setup high-level build options ...
-IF(UNIX AND NOT APPLE)
- SET(XTRKCAD_USE_GTK_DEFAULT ON)
- SET(XTRKCAD_USE_GETTEXT_DEFAULT ON)
-ENDIF(UNIX AND NOT APPLE)
-
-IF(APPLE)
- SET(XTRKCAD_USE_GTK_DEFAULT ON)
+if(UNIX)
+ include(FindPkgConfig)
+ set(XTRKCAD_USE_GTK_DEFAULT ON)
+ if(APPLE)
SET(XTRKCAD_USE_GETTEXT_DEFAULT OFF)
-ENDIF(APPLE)
+ else()
+ set(XTRKCAD_USE_GETTEXT_DEFAULT ON)
+ add_compile_options("-std=gnu99")
+ PKG_CHECK_MODULES(GTK_WEBKIT "webkit-1.0")
+ if(GTK_WEBKIT_FOUND)
+ set(XTRKCAD_USE_BROWSER_DEFAULT OFF)
+ else()
+ set(XTRKCAD_USE_BROWSER_DEFAULT ON)
+ endif()
+ endif(APPLE)
+endif(UNIX)
IF(WIN32)
- CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR)
-
SET(XTRKCAD_USE_GTK_DEFAULT OFF)
- SET(XTRKCAD_USE_GETTEXT_DEFAULT OFF)
+ SET(XTRKCAD_USE_GETTEXT_DEFAULT ON)
SET(CMAKE_C_FLAGS_DEBUG "/D_DEBUG /MTd /Zi /Ob0 /Od /RTC1" CACHE STRING "Flags used by the compiler during debug builds" FORCE)
SET(CMAKE_C_FLAGS_MINSIZEREL "/MT /O1 /Ob1 /D NDEBUG" CACHE STRING "Flags used by the compiler during release minumum size builds" FORCE)
@@ -40,9 +46,17 @@ if(COMMAND cmake_policy)
endif(COMMAND cmake_policy)
SET(XTRKCAD_USE_DOXYGEN_DEFAULT OFF)
+
OPTION(XTRKCAD_USE_GTK "Use GTK for the graphical user interface back-end" ${XTRKCAD_USE_GTK_DEFAULT})
OPTION(XTRKCAD_USE_GETTEXT "Use gettext for internationalization" ${XTRKCAD_USE_GETTEXT_DEFAULT})
OPTION(XTRKCAD_USE_DOXYGEN "Generate internals documentation using doxygen" ${XTRKCAD_USE_DOXYGEN_DEFAULT})
+if(UNIX AND NOT APPLE)
+ option(XTRKCAD_USE_BROWSER "Show help in default browser" ${XTRKCAD_USE_BROWSER_DEFAULT})
+endif()
+
+IF(UNIX)
+ PKG_CHECK_MODULES(GTK REQUIRED "gtk+-2.0")
+ENDIF()
IF(APPLE)
OPTION(XTRKCAD_USE_PACKAGEMAKER "Generate an OSX PackageMaker package for distribution." OFF)
@@ -62,12 +76,6 @@ IF(WIN32 AND NOT XTRKCAD_USE_GTK)
FIND_PACKAGE(HTMLHelp REQUIRED)
ENDIF(WIN32 AND NOT XTRKCAD_USE_GTK)
-IF(XTRKCAD_USE_GTK)
- INCLUDE(FindPkgConfig)
- PKG_CHECK_MODULES(GTK REQUIRED "gtk+-2.0")
- PKG_CHECK_MODULES(GTK_WEBKIT REQUIRED "webkit-1.0")
-ENDIF(XTRKCAD_USE_GTK)
-
IF(XTRKCAD_USE_PACKAGEMAKER)
IF(NOT CMAKE_INSTALL_PREFIX STREQUAL "/usr")
MESSAGE(SEND_ERROR "XTRKCAD_USE_PACKAGEMAKER requires CMAKE_INSTALL_PREFIX set to /usr.")
@@ -76,20 +84,23 @@ ENDIF(XTRKCAD_USE_PACKAGEMAKER)
# Find unit testing framework
find_package(CMocka)
-if( CMOCKA_FOUND)
+if(CMOCKA_FOUND)
include_directories(${CMOCKA_INCLUDE_DIR})
set(LIBS ${LIBS} ${CMOCKA_LIBRARIES})
option( XTRKCAD_TESTING "Build unittests" ON)
endif()
+# Find document conversion tool
+find_package(Pandoc)
+
# Test for headers and libraries for portability ...
INCLUDE (CheckIncludeFiles)
CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
# Setup some global options for installation ...
-SET(XTRKCAD_MAJOR_VERSION "4")
-SET(XTRKCAD_MINOR_VERSION "3")
+SET(XTRKCAD_MAJOR_VERSION "5")
+SET(XTRKCAD_MINOR_VERSION "1")
SET(XTRKCAD_RELEASE_VERSION "0")
SET(XTRKCAD_VERSION_MODIFIER "")
SET(XTRKCAD_VERSION "${XTRKCAD_MAJOR_VERSION}.${XTRKCAD_MINOR_VERSION}.${XTRKCAD_RELEASE_VERSION}${XTRKCAD_VERSION_MODIFIER}")
@@ -106,6 +117,29 @@ SET(XTRKCAD_SHARE_INSTALL_DIR "share/xtrkcad")
ADD_DEFINITIONS(-DXTRKCAD_CMAKE_BUILD)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/xtrkcad-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/xtrkcad-config.h)
+IF(XTRKCAD_USE_GETTEXT)
+ SET(GENHELP_OPTS "-bhi")
+ #
+ # Find the GnuWin32 installation directory, the gettext include should be located in subdir include
+ #
+ IF(WIN32)
+ if(MSVC)
+ # use supplied gettext library for Visual Studio
+ message( STATUS "Use simple_gettext module included with XTrackCAD" )
+ ADD_DEFINITIONS(-DUSE_SIMPLE_GETTEXT )
+ else()
+ # for mingw & co. find libintl.h and use it
+ find_path ( INTL_PATH libintl.h )
+ if(INTL_PATH)
+ message( STATUS "Use installed gettext module" )
+ INCLUDE_DIRECTORIES(${INTL_PATH})
+ endif(INTL_PATH)
+ endif()
+ ENDIF(WIN32)
+ELSE(XTRKCAD_USE_GETTEXT)
+ SET(GENHELP_OPTS "-bh")
+ENDIF(XTRKCAD_USE_GETTEXT)
+
# Setup the rest of the build ...
ADD_SUBDIRECTORY(app)
ADD_SUBDIRECTORY(distribution)
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 9a47f95..5791fa2 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -1,6 +1,7 @@
# "bin/i18n.h" is widely used
INCLUDE_DIRECTORIES(bin)
include_directories(dynstring)
+include_directories(cornu)
# Setup the rest of the build ...
add_subdirectory(dynstring)
@@ -10,6 +11,7 @@ ADD_SUBDIRECTORY(help)
ADD_SUBDIRECTORY(doc)
ADD_SUBDIRECTORY(bin)
ADD_SUBDIRECTORY(lib)
+ADD_SUBDIRECTORY(cornu)
IF(XTRKCAD_USE_GETTEXT)
ADD_SUBDIRECTORY(i18n)
diff --git a/app/FindPkgConfig.cmake b/app/FindPkgConfig.cmake
deleted file mode 100644
index 4a894cb..0000000
--- a/app/FindPkgConfig.cmake
+++ /dev/null
@@ -1,360 +0,0 @@
-# - a pkg-config module for CMake
-#
-# Usage:
-# pkg_check_modules(<PREFIX> [REQUIRED] <MODULE> [<MODULE>]*)
-# checks for all the given modules
-#
-# pkg_search_module(<PREFIX> [REQUIRED] <MODULE> [<MODULE>]*)
-# checks for given modules and uses the first working one
-#
-# When the 'REQUIRED' argument was set, macros will fail with an error
-# when module(s) could not be found
-#
-# It sets the following variables:
-# PKG_CONFIG_FOUND ... true iff pkg-config works on the system
-# PKG_CONFIG_EXECUTABLE ... pathname of the pkg-config program
-# <PREFIX>_FOUND ... set to 1 iff module(s) exist
-#
-# For the following variables two sets of values exist; first one is the
-# common one and has the given PREFIX. The second set contains flags
-# which are given out when pkgconfig was called with the '--static'
-# option.
-# <XPREFIX>_LIBRARIES ... only the libraries (w/o the '-l')
-# <XPREFIX>_LIBRARY_DIRS ... the paths of the libraries (w/o the '-L')
-# <XPREFIX>_LDFLAGS ... all required linker flags
-# <XPREFIX>_LDFLAGS_OTHERS ... all other linker flags
-# <XPREFIX>_INCLUDE_DIRS ... the '-I' preprocessor flags (w/o the '-I')
-# <XPREFIX>_CFLAGS ... all required cflags
-# <XPREFIX>_CFLAGS_OTHERS ... the other compiler flags
-#
-# <XPREFIX> = <PREFIX> for common case
-# <XPREFIX> = <PREFIX>_STATIC for static linking
-#
-# There are some special variables whose prefix depends on the count
-# of given modules. When there is only one module, <PREFIX> stays
-# unchanged. When there are multiple modules, the prefix will be
-# changed to <PREFIX>_<MODNAME>:
-# <XPREFIX>_VERSION ... version of the module
-# <XPREFIX>_PREFIX ... prefix-directory of the module
-# <XPREFIX>_INCLUDEDIR ... include-dir of the module
-# <XPREFIX>_LIBDIR ... lib-dir of the module
-#
-# <XPREFIX> = <PREFIX> when |MODULES| == 1, else
-# <XPREFIX> = <PREFIX>_<MODNAME>
-#
-# A <MODULE> parameter can have the following formats:
-# {MODNAME} ... matches any version
-# {MODNAME}>={VERSION} ... at least version <VERSION> is required
-# {MODNAME}={VERSION} ... exactly version <VERSION> is required
-# {MODNAME}<={VERSION} ... modules must not be newer than <VERSION>
-#
-# Examples
-# pkg_check_modules (GLIB2 glib-2.0)
-#
-# pkg_check_modules (GLIB2 glib-2.0>=2.10)
-# requires at least version 2.10 of glib2 and defines e.g.
-# GLIB2_VERSION=2.10.3
-#
-# pkg_check_modules (FOO glib-2.0>=2.10 gtk+-2.0)
-# requires both glib2 and gtk2, and defines e.g.
-# FOO_glib-2.0_VERSION=2.10.3
-# FOO_gtk+-2.0_VERSION=2.8.20
-#
-# pkg_check_modules (XRENDER REQUIRED xrender)
-# defines e.g.:
-# XRENDER_LIBRARIES=Xrender;X11
-# XRENDER_STATIC_LIBRARIES=Xrender;X11;pthread;Xau;Xdmcp
-#
-# pkg_search_module (BAR libxml-2.0 libxml2 libxml>=2)
-
-
-# Copyright (C) 2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
-#
-# Redistribution and use, with or without modification, are permitted
-# provided that the following conditions are met:
-#
-# 1. Redistributions must retain the above copyright notice, this
-# list of conditions and the following disclaimer.
-# 2. The name of the author may not be used to endorse or promote
-# products derived from this software without specific prior
-# written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-### Common stuff ####
-set(PKG_CONFIG_VERSION 1)
-set(PKG_CONFIG_FOUND 0)
-
-find_program(PKG_CONFIG_EXECUTABLE NAMES pkg-config DOC "pkg-config executable")
-mark_as_advanced(PKG_CONFIG_EXECUTABLE)
-
-if(PKG_CONFIG_EXECUTABLE)
- set(PKG_CONFIG_FOUND 1)
-endif(PKG_CONFIG_EXECUTABLE)
-
-
-# Unsets the given variables
-macro(_pkgconfig_unset var)
- set(${var} "" CACHE INTERNAL "")
-endmacro(_pkgconfig_unset)
-
-macro(_pkgconfig_set var value)
- set(${var} ${value} CACHE INTERNAL "")
-endmacro(_pkgconfig_set)
-
-# Invokes pkgconfig, cleans up the result and sets variables
-macro(_pkgconfig_invoke _pkglist _prefix _varname _regexp)
- set(_pkgconfig_invoke_result)
-
- execute_process(
- COMMAND ${PKG_CONFIG_EXECUTABLE} ${ARGN} ${_pkglist}
- OUTPUT_VARIABLE _pkgconfig_invoke_result
- RESULT_VARIABLE _pkgconfig_failed)
-
- if (_pkgconfig_failed)
- set(_pkgconfig_${_varname} "")
- _pkgconfig_unset(${_prefix}_${_varname})
- else(_pkgconfig_failed)
- string(REGEX REPLACE "[\r\n]" " " _pkgconfig_invoke_result "${_pkgconfig_invoke_result}")
- string(REGEX REPLACE " +$" "" _pkgconfig_invoke_result "${_pkgconfig_invoke_result}")
-
- if (NOT ${_regexp} STREQUAL "")
- string(REGEX REPLACE "${_regexp}" " " _pkgconfig_invoke_result "${_pkgconfig_invoke_result}")
- endif(NOT ${_regexp} STREQUAL "")
-
- separate_arguments(_pkgconfig_invoke_result)
-
- #message(STATUS " ${_varname} ... ${_pkgconfig_invoke_result}")
- set(_pkgconfig_${_varname} ${_pkgconfig_invoke_result})
- _pkgconfig_set(${_prefix}_${_varname} "${_pkgconfig_invoke_result}")
- endif(_pkgconfig_failed)
-endmacro(_pkgconfig_invoke)
-
-# Invokes pkgconfig two times; once without '--static' and once with
-# '--static'
-macro(_pkgconfig_invoke_dyn _pkglist _prefix _varname cleanup_regexp)
- _pkgconfig_invoke("${_pkglist}" ${_prefix} ${_varname} "${cleanup_regexp}" ${ARGN})
- _pkgconfig_invoke("${_pkglist}" ${_prefix} STATIC_${_varname} "${cleanup_regexp}" --static ${ARGN})
-endmacro(_pkgconfig_invoke_dyn)
-
-# Splits given arguments into options and a package list
-macro(_pkgconfig_parse_options _result _is_req)
- set(${_is_req} 0)
-
- foreach(_pkg ${ARGN})
- if (_pkg STREQUAL "REQUIRED")
- set(${_is_req} 1)
- endif (_pkg STREQUAL "REQUIRED")
- endforeach(_pkg ${ARGN})
-
- set(${_result} ${ARGN})
- list(REMOVE_ITEM ${_result} "REQUIRED")
-endmacro(_pkgconfig_parse_options)
-
-###
-macro(_pkg_check_modules_internal _is_required _is_silent _prefix)
- _pkgconfig_unset(${_prefix}_FOUND)
- _pkgconfig_unset(${_prefix}_VERSION)
- _pkgconfig_unset(${_prefix}_PREFIX)
- _pkgconfig_unset(${_prefix}_INCLUDEDIR)
- _pkgconfig_unset(${_prefix}_LIBDIR)
- _pkgconfig_unset(${_prefix}_LIBS)
- _pkgconfig_unset(${_prefix}_LIBS_L)
- _pkgconfig_unset(${_prefix}_LIBS_PATHS)
- _pkgconfig_unset(${_prefix}_LIBS_OTHER)
- _pkgconfig_unset(${_prefix}_CFLAGS)
- _pkgconfig_unset(${_prefix}_CFLAGS_I)
- _pkgconfig_unset(${_prefix}_CFLAGS_OTHER)
- _pkgconfig_unset(${_prefix}_STATIC_LIBDIR)
- _pkgconfig_unset(${_prefix}_STATIC_LIBS)
- _pkgconfig_unset(${_prefix}_STATIC_LIBS_L)
- _pkgconfig_unset(${_prefix}_STATIC_LIBS_PATHS)
- _pkgconfig_unset(${_prefix}_STATIC_LIBS_OTHER)
- _pkgconfig_unset(${_prefix}_STATIC_CFLAGS)
- _pkgconfig_unset(${_prefix}_STATIC_CFLAGS_I)
- _pkgconfig_unset(${_prefix}_STATIC_CFLAGS_OTHER)
-
- # create a better addressable variable of the modules and calculate its size
- set(_pkg_check_modules_list ${ARGN})
- list(LENGTH _pkg_check_modules_list _pkg_check_modules_cnt)
-
- if(PKG_CONFIG_EXECUTABLE)
- # give out status message telling checked module
- if (NOT ${_is_silent})
- if (_pkg_check_modules_cnt EQUAL 1)
- message(STATUS "checking for module '${_pkg_check_modules_list}'")
- else(_pkg_check_modules_cnt EQUAL 1)
- message(STATUS "checking for modules '${_pkg_check_modules_list}'")
- endif(_pkg_check_modules_cnt EQUAL 1)
- endif(NOT ${_is_silent})
-
- set(_pkg_check_modules_packages)
- set(_pkg_check_modules_failed)
-
- # iterate through module list and check whether they exist and match the required version
- foreach (_pkg_check_modules_pkg ${_pkg_check_modules_list})
- set(_pkg_check_modules_exist_query)
-
- # check whether version is given
- if (_pkg_check_modules_pkg MATCHES ".*(>=|=|<=).*")
- string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\1" _pkg_check_modules_pkg_name "${_pkg_check_modules_pkg}")
- string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\2" _pkg_check_modules_pkg_op "${_pkg_check_modules_pkg}")
- string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\3" _pkg_check_modules_pkg_ver "${_pkg_check_modules_pkg}")
- else(_pkg_check_modules_pkg MATCHES ".*(>=|=|<=).*")
- set(_pkg_check_modules_pkg_name "${_pkg_check_modules_pkg}")
- set(_pkg_check_modules_pkg_op)
- set(_pkg_check_modules_pkg_ver)
- endif(_pkg_check_modules_pkg MATCHES ".*(>=|=|<=).*")
-
- # handle the operands
- if (_pkg_check_modules_pkg_op STREQUAL ">=")
- list(APPEND _pkg_check_modules_exist_query --atleast-version)
- endif(_pkg_check_modules_pkg_op STREQUAL ">=")
-
- if (_pkg_check_modules_pkg_op STREQUAL "=")
- list(APPEND _pkg_check_modules_exist_query --exact-version)
- endif(_pkg_check_modules_pkg_op STREQUAL "=")
-
- if (_pkg_check_modules_pkg_op STREQUAL "<=")
- list(APPEND _pkg_check_modules_exist_query --max-version)
- endif(_pkg_check_modules_pkg_op STREQUAL "<=")
-
- # create the final query which is of the format:
- # * --atleast-version <version> <pkg-name>
- # * --exact-version <version> <pkg-name>
- # * --max-version <version> <pkg-name>
- # * --exists <pkg-name>
- if (_pkg_check_modules_pkg_op)
- list(APPEND _pkg_check_modules_exist_query "${_pkg_check_modules_pkg_ver}")
- else(_pkg_check_modules_pkg_op)
- list(APPEND _pkg_check_modules_exist_query --exists)
- endif(_pkg_check_modules_pkg_op)
-
- _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_VERSION)
- _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_PREFIX)
- _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_INCLUDEDIR)
- _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_LIBDIR)
-
- list(APPEND _pkg_check_modules_exist_query "${_pkg_check_modules_pkg_name}")
- list(APPEND _pkg_check_modules_packages "${_pkg_check_modules_pkg_name}")
-
- # execute the query
- execute_process(
- COMMAND ${PKG_CONFIG_EXECUTABLE} ${_pkg_check_modules_exist_query}
- RESULT_VARIABLE _pkgconfig_retval)
-
- # evaluate result and tell failures
- if (_pkgconfig_retval)
- if(NOT ${_is_silent})
- message(STATUS " package '${_pkg_check_modules_pkg}' not found")
- endif(NOT ${_is_silent})
-
- set(_pkg_check_modules_failed 1)
- endif(_pkgconfig_retval)
- endforeach(_pkg_check_modules_pkg)
-
- if(_pkg_check_modules_failed)
- # fail when requested
- if (${_is_required})
- message(SEND_ERROR "A required package was not found")
- endif (${_is_required})
- else(_pkg_check_modules_failed)
- # when we are here, we checked whether requested modules
- # exist. Now, go through them and set variables
-
- _pkgconfig_set(${_prefix}_FOUND 1)
- list(LENGTH _pkg_check_modules_packages pkg_count)
-
- # iterate through all modules again and set individual variables
- foreach (_pkg_check_modules_pkg ${_pkg_check_modules_packages})
- # handle case when there is only one package required
- if (pkg_count EQUAL 1)
- set(_pkg_check_prefix "${_prefix}")
- else(pkg_count EQUAL 1)
- set(_pkg_check_prefix "${_prefix}_${_pkg_check_modules_pkg}")
- endif(pkg_count EQUAL 1)
-
- _pkgconfig_invoke(${_pkg_check_modules_pkg} "${_pkg_check_prefix}" VERSION "" --modversion )
- _pkgconfig_invoke(${_pkg_check_modules_pkg} "${_pkg_check_prefix}" PREFIX "" --variable=prefix )
- _pkgconfig_invoke(${_pkg_check_modules_pkg} "${_pkg_check_prefix}" INCLUDEDIR "" --variable=includedir )
- _pkgconfig_invoke(${_pkg_check_modules_pkg} "${_pkg_check_prefix}" LIBDIR "" --variable=libdir )
-
- message(STATUS " found ${_pkg_check_modules_pkg}, version ${_pkgconfig_VERSION}")
- endforeach(_pkg_check_modules_pkg)
-
- # set variables which are combined for multiple modules
- _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LIBRARIES "(^| )-l" --libs-only-l )
- _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LIBRARY_DIRS "(^| )-L" --libs-only-L )
- _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LDFLAGS "" --libs )
- _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LDFLAGS_OTHER "" --libs-only-other )
-
- _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" INCLUDE_DIRS "(^| )-I" --cflags-only-I )
- _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" CFLAGS "" --cflags )
- _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" CFLAGS_OTHER "" --cflags-only-other )
- endif(_pkg_check_modules_failed)
- else(PKG_CONFIG_EXECUTABLE)
- if (${_is_required})
- message(SEND_ERROR "pkg-config tool not found")
- endif (${_is_required})
- endif(PKG_CONFIG_EXECUTABLE)
-endmacro(_pkg_check_modules_internal)
-
-###
-### User visible macros start here
-###
-
-###
-macro(pkg_check_modules _prefix _module0)
- # check cached value
-# if (NOT DEFINED __pkg_config_checked_${_prefix} OR __pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION})
- _pkgconfig_parse_options (_pkg_modules _pkg_is_required "${_module0}" ${ARGN})
- _pkg_check_modules_internal("${_pkg_is_required}" 0 "${_prefix}" ${_pkg_modules})
-
-# _pkgconfig_set(__pkg_config_checked_${_prefix} ${PKG_CONFIG_VERSION})
-# endif(NOT DEFINED __pkg_config_checked_${_prefix} OR __pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION})
-endmacro(pkg_check_modules)
-
-###
-macro(pkg_search_module _prefix _module0)
- # check cached value
-# if (NOT DEFINED __pkg_config_checked_${_prefix} OR __pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION})
- set(_pkg_modules_found 0)
- _pkgconfig_parse_options(_pkg_modules_alt _pkg_is_required "${_module0}" ${ARGN})
-
- message(STATUS "checking for one of the modules '${_pkg_modules_alt}'")
-
- # iterate through all modules and stop at the first working one.
- foreach(_pkg_alt ${_pkg_modules_alt})
- if(NOT _pkg_modules_found)
- _pkg_check_modules_internal(0 1 "${_prefix}" "${_pkg_alt}")
- endif(NOT _pkg_modules_found)
-
- if (${_prefix}_FOUND)
- set(_pkg_modules_found 1)
- endif(${_prefix}_FOUND)
- endforeach(_pkg_alt)
-
- if (NOT ${_prefix}_FOUND)
- if(${_pkg_is_required})
- message(SEND_ERROR "None of the required '${_pkg_modules_alt}' found")
- endif(${_pkg_is_required})
- endif(NOT ${_prefix}_FOUND)
-
-# _pkgconfig_set(__pkg_config_checked_${_prefix} ${PKG_CONFIG_VERSION})
-# endif(NOT DEFINED __pkg_config_checked_${_prefix} OR __pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION})
-endmacro(pkg_search_module)
-
-### Local Variables:
-### mode: cmake
-### End:
diff --git a/app/bin/CMakeLists.txt b/app/bin/CMakeLists.txt
index ee0886d..74b1bc8 100644
--- a/app/bin/CMakeLists.txt
+++ b/app/bin/CMakeLists.txt
@@ -42,18 +42,6 @@ SET(LIN_SOURCES
GET_TARGET_PROPERTY(genhelp_EXE genhelp LOCATION)
-IF(XTRKCAD_USE_GETTEXT)
- SET(GENHELP_OPTS "-bhi")
- #
- # Find the GnuWin32 installation directory, the gettext include should be located in subdir include
- #
- IF(WIN32)
- ADD_DEFINITIONS(-DUSE_SIMPLE_GETTEXT )
- ENDIF(WIN32)
-ELSE(XTRKCAD_USE_GETTEXT)
- SET(GENHELP_OPTS "-bh")
-ENDIF(XTRKCAD_USE_GETTEXT)
-
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bllnhlp.c
DEPENDS genhelp ${help_SOURCE_DIR}/genhelp.in
@@ -62,8 +50,11 @@ ADD_CUSTOM_COMMAND(
SET(SOURCES
${LIN_SOURCES}
+ appdefaults.c
bllnhlp.c
+ cbezier.c
cblock.c
+ ccornu.c
ccurve.c
ccontrol.c
cdraw.c
@@ -115,12 +106,16 @@ SET(SOURCES
elev.c
fileio.c
i18n.c
+ layout.c
lprintf.c
macro.c
misc2.c
param.c
+ paths.c
shrtpath.c
smalldlg.c
+ tbezier.c
+ tcornu.c
tcurve.c
tease.c
track.c
@@ -134,12 +129,6 @@ INCLUDE_DIRECTORIES(${XTrkCAD_BINARY_DIR})
INCLUDE_DIRECTORIES(${help_BINARY_DIR})
INCLUDE_DIRECTORIES(${wlib_SOURCE_DIR}/include)
-# find libintl.h and use it
-find_path ( INTL_PATH libintl.h )
-if(INTL_PATH)
- INCLUDE_DIRECTORIES(${INTL_PATH})
-endif(INTL_PATH)
-
LINK_DIRECTORIES(${GTK_LIBRARY_DIRS})
LINK_DIRECTORIES(${GTK_WEBKIT_LIBRARY_DIRS})
@@ -149,12 +138,13 @@ ADD_LIBRARY(xtrkcad-lib ${SOURCES})
ADD_DEPENDENCIES(xtrkcad-lib Help)
ADD_EXECUTABLE(xtrkcad WIN32
- misc.c
+ misc.c
xtrkcad.rc
)
TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-lib)
TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-wlib)
-target_link_libraries(xtrkcad dynstring)
+TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-cornu)
+TARGET_LINK_LIBRARIES(xtrkcad dynstring)
ADD_EXECUTABLE(mkturnout
${LIN_SOURCES}
diff --git a/app/bin/ChangeLog b/app/bin/ChangeLog
deleted file mode 100644
index 034812e..0000000
--- a/app/bin/ChangeLog
+++ /dev/null
@@ -1,495 +0,0 @@
-Apr 28, 2010
- FIX: Daniel Spagnol
- i18n.c, misc.c: replaced hard-coded XTRKCAD_LOCALE_DIR path with
- 'locale' based on application library directory (XTRKCAD_LOCALE_DIR is
- defined at makefiles generation time and does not reflect the place
- where the application is actually installed)
-
-Jan 01, 2010
- FIX: Martin Fischer
- custom.c, custom.h: fix compile warnings
-
-Dec 30, 2009
- FIX: Martin Fischer
- misc.c: make load last layout option work
-
-Dec 29, 2009
- FIX: Martin Fischer
- denum.c: remove signed / unsigned mismatch
-
-Dec 19, 2009
- FIX: Robert Heller
- cswitchmotor.c: Patch to fix Visual C++ compile error
-
-Dec 12, 2009
- FIX: Martin Fischer
- draw.c, custom.c: refactoring, move some functionality from the lowlevel
- library to the more appropriate core application modules
-
-Oct 14, 2009
- ENH: Daniel Spagnol
- chotbar.c: undone Oct 03, 2009 changes due to gtk+-2.18 fixed it for us.
- Actually gtk+-2.18 fixed all surface drawing performance issues for
- quartz.
-
-Oct 09, 2009
- FIX: Daniel Spagnol
- denum.c: application crash due to a double value used as a "%*" sprintf
- argument. scenario is "Manage" -> "Parts List..." -> "Price" (checkbox).
- denum.c: added a character counter function for utf-8 strings
-
-Oct 04, 2009
- FIX: Martin Fischer
- misc2.c: minimum radius is correctly changed
-
-Oct 03, 2009
- FIX: Daniel Spagnol
- chotbar.c: hotbar redraw too slow under gtk-quartz
-
-Sep 21, 2009
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- custom.c, misc.c, param.c, param.h, smalldlg.c smalldlg.h:
- New 'About' dialog
-
-Sep 16, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- cblock.c, cswitchmotor.c: remove some unused locals
-
-Aug 16, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- CMakeLists.txt cprint.c denum.c i18n.c i18n.h misc.c
- Improve internationalization support, use simple gettext on Win32
-
-Aug 16, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- custom.c cturnout.c: Code cleanup
-
-Jul 30, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- dcustmgm.c: set locale when exporting to parameter
-
-Jul 24, 2009
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c: add command line option for configuration
- file selection
-
-Jul 10, 2009
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c: use getopt() for access to command line arguments
-
-Jul 09, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- custom.c, misc.c, denum.c, doption.c: remove some
- obsolete flags
-
-Jul 08, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- cblock.c, cswitchmotor.c: make compile under MSVC
-
-Jul 08, 2009
- ENH: Robert Heller
- cblock.c, cswitchmotor.c: new functionality for layout
- control: blocks and switchmotors
-
-Version 4.0.3a
-==============
-
-Jul 05, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- track.c: Bug fix #2816663: Block gaps are not printed
-
-Jul 01, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- CMakeList.txt: remove dependency from unneeded cmisc2.c
-
-Jun 26, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- custom.c: correct handling of export file extensions
-
-Jun 20, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- ctodesgn.c: convert roadbed width as necessary
- (Robert Myers)
-
-Jun 15, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- tcurve.c, drawgeom.c: fix variable initialization
- problems.
-
-Jun 14, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- macro.c: make demos work again with new dialogs
-
-Jun 13, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- dlayer.c: "changed" state of layout is updated with
- layer changes. (DonDASA)
-
-Version 4.0.3
-=============
-
-Jun 10, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- ctodesgn.c: remove unneeded local variables
-
-Jun 08, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- draw.c: no tooltip for the main drawing area
-
-Jun 06, 2009
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- draw.c: fix compiler warning
-
-May 26, 2009
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- ctrain.c: update icons
-
-May 25, 2009
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- ctrain.c: change default for train running to 'Go'
- beautify throttle slider
-
-May 25, 2009
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- cturnout.c, track.c, track.h,utility.c, cparalle.c
- parallel command also works for straight pieces of
- sectional track
-
-May 15, 2009
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- macro.c, misc.c: more message boxes with icon
-
-May 08, 2009
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- fileio.c, misc.c: use new message box with icon
-
-
-Oct 11, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- draw.h: fixed prototype for DoZoom as suggested by
- Stefan Gruenendahl
-
-Sep 05, 2008
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, cselect.c, track.c: create full partlist
- when no track is selected
-
-Sep 01, 2008
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, common.h: add new toolbar icons for file ops
-
-Aug 29, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- draw.c: fixed bug #1821257: no zoom larger than 1:1
-
-Jul 11, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c: update map on loading initial layout
-
-Jul 10, 2008
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, misc.h, draw.c: allow user to cancel close request
-
-Jun 04, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- cselect.c: Rescale dialog wasn't updated correctly
- misc2.c: fixed bug when rescale same piece several times
-
-Jun 03. 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- CMakeLists.txt: find getext on Win32
-
-Jun 03, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- cselect.c: fixed bug when rescale same piece several times
- csnap.c: initialize grid spacing value
-
-Apr 13, 2008
- ENH: Bob Blackwell
- ctrain.c: updated label text
-
-Mar 27, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- csnap.c: working default value for grid spacing
-
-Mar 21, 2008
- FIX: Bob Blackwell
- doption.c: uppdated labels in option dialogs
-
-Mar 18, 2008
- FIX: Bob Blackwell
- doption.c: rearrange option settings in display / command / preferences
- dialog
-
-Feb 04, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- CMakeLists.txt: Fix missing icon problem for Windows exe
-
-Feb 04, 2008
- FIX: Mikko Nissinen <mni77@users.sourceforge.net>
- misc.c: Fixed an internationalization bug in MenuPlayback.
-
-Feb 04, 2008
- FIX: Mikko Nissinen <mni77@users.sourceforge.net>
- cnote.c: Minor fix to internationalization.
-
-Feb 03, 2008
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- cprint.c: printout of date is correctly localized now.
-
-Feb 03, 2008
- ENH: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, misc.h doption.c: on startup last file can now be loaded automatically.
- This behavior is controled by an option in the preferences dialog.
-
-Jan 28, 2008
- FIX: Mikko Nissinen <mni77@users.sourceforge.net>
- misc.c: Product name changed in font selection dialog.
-
-Jan 28, 2008
- FIX: Mikko Nissinen <mni77@users.sourceforge.net>
- common.c: Dynamically allocate and form some global translatable
- strings.
-
-Jan 27, 2008
- FIX: Mikko Nissinen <mni77@users.sourceforge.net>
- macro.c: String XTrkCad changed to XTrackCAD.
-
-Jan 27, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, fileio.c: fixed product name
-
-Jan 27, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- dcar.c: corrected problem in CarPartWrite()
-
-Jan 25, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- custom.c, version.h: Changed product name to XTrackCAD and version
- to 4.1.0b1
-
-Jan 23, 2008
- FIX: Mikko Nissinen <mni77@users.sourceforge.net>
- ctodesgn.c: Removed '_()' around turnout label from InitNewTurn()
- and ShowTurnoutDesigner().
- dcustmgm.c: Saving custom stuff in demo mode changed the locale
- to "C" without restoring it back to original.
-
-Jan 23, 2008
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- fileio.c: increase precision for roomsize to 6 digits .
-
-Jan 23, 2008
- FIX: Mikko Nissinen <mni77@users.sourceforge.net>
- param.c: ParamPlayback(): If parameter type is PD_FLOAT, then use the
- locale "C" during atof().
-
-Jan 22, 2008
- ENH: Mikko Nissinen <mni77@users.sourceforge.net>
- misc.c: Save user locale when program initializes.
- macro.c: Gettext support added.
-
-Jan 21, 2008
- ENH: Mikko Nissinen <mni77@users.sourceforge.net>
- Gettext support added. The following 48 files were modified:
- ccurve.c, cdraw.c, celev.c, cgroup.c, chndldto.c, cjoin.c, cmisc.c,
- cmisc2.c, cmodify.c, cnote.c, compound.c, cparalle.c, cpull.c,
- cruler.c, cselect.c, csnap.c, csplit.c, cstraigh.c, cstruct.c,
- ctext.c, ctodesgn.c, ctrain.c, cturnout.c, cturntbl.c, cundo.c,
- custom.c, dbench.c, dbitmap.c, dcar.c, dcmpnd.c, dcustmgm.c, dease.c,
- denum.c, dlayer.c, doption.c, dpricels.c, dprmfile.c, draw.c,
- drawgeom.c, misc2.c, param.c, smalldlg.c, tcurve.c, tease.c, track.c,
- tstraigh.c
-
-Jan 18, 2008
- FIX: Mikko Nissinen <mni77@users.sourceforge.net>
- dcar.c: CarInvSaveText() Car list text file is now created to
- selected path instead of current working directory.
-
-Jan 15, 2008
- IMPROVEMENT: Mikko Nissinen <mni77@users.sourceforge.net>
- Basic gettext support added. Gettext is initialized in misc.c:wMain().
- The initialization routine is defined in i18n.[ch] along with all
- other gettext definitions.
- CMakeLists.txt
- fileio.[ch]
- i18n.[ch]
- misc.c
- Also the following CMakeLists were modified for gettext:
- xtrkcad/CMakeLists.txt
- xtrkcad/app/CMakeLists.txt
- xtrkcad/app/help/CMakeLists.txt
- xtrkcad/app/i18n/CMakeLists.txt (Initial import)
- xtrkcad/app/wlib/gtklib/CMakeLists.txt
-
-Dec 13, 2007
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- fileio.c: fixed segfault when locale is saved
-
-Dec. 12. 2007
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- dlayer.c: layers lists are updated properly after file is loaded
- fileio.c: fixed segfault when locale is saved
- Makefile: updated dependencies for dlayer.c
-
-Dec 08, 2007
- FIX: Martin Fischer <m_fischer@users.sourceforge.net>
- xtrkcad.ico: create a new color icon
-
-Dec. 01, 2007
- BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
- acclkeys.h: removed non-working accelerator key for deselect all
-
-Nov. 30, 2007
- FIX: Timothy M. Shead
- misc.c: make sure that font initialization is run first
-
-Oct 29, 2007
- BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
- dlayer.c: Shortened button text to 'Defaults'
-
-Oct 10, 2007
- BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
- csnap.c cprint.c, misc.c: Accelerator keys for Print and
- Snap Grid Dialog work again.
-
-Oct 10, 2007
- BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
- acclkeys.h: Revert and Redo used the same accelerator key.
- Fixed, Revert doesn't have an acclerator now.
-
-Sep 28, 2007
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, smalldlg.c: Use large message for tip of the day
- teaser line. Changed to a more generous spacing in dialogs.
-
-Sep 23, 2007
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, smalldlg.c: separated tip window code into new
- source file. Slightly improved the "tip of the day" dialog
- (jump to next and prev tip).
-
-Sep 15, 2007
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c: XTrkCad now has a real splash window during startup
-
-Jul 22, 2007
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- draw.c: the mouse wheel can be used for zooming in and out
-
-Jun 27, 2007
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- dlayer.c: some cleanup and modified layer buttons. Also all
- layer buttons where moved to the bitmaps directory.
-
-Jun 16, 2007
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- fileio.c: default directory for storing files is the user's
- home directory now.
-
-Jun 15, 2007
- BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
- dlayer.c: fixed function prototype for Windows compile
-
-Jun 15, 2007
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- dlayer.c: layer buttons now are push buttons that are in
- 'pressed' state when layer is visible.
-
-Jun 15, 2007
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- dlayer.c, fileio.c, misc.c: settings for the layers can now
- be saved in the preferences. On opening a new layout or upon
- startup of XTrkCad these settings are automatically loaded.
-
-May 18, 2007
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- draw.c misc.c: disable zoom up and zoom down buttons when
- end of list is reached
-
-Apr 30, 2007
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- draw.c, misc.c, draw.h: use radio buttons for selecting zoom factor
- zoom in and out goes through all available zoom factors step by step
- setting zoom is available from the pulldown menu as well
-
-Apr 11, 2007
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- draw.c: changed layout of status bar to include labels.
- Part count is no longer shown.
-
-Feb 23, 2007
- BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
- cmisc.c, cselect.c rescale / resize works again. UI change to
- allow changing scale and gauge independently
-
-Feb 16, 2007
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- Recently used files list is only updated after successful load
-
-
-Version 4.0.1
-=============
-
-May 26th, 2006
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- Visual Studio C++ 2005 Express is now supported under Windows
-
-Mar 26th, 2006
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, fileio,c, draw.c If the application crashed the user can decide
- to resume work at the last state saved in a checkpoint file
- checkpoint files (ckp and ck1) are removed on normal exit
-
-Mar 25th, 2006
-
- BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
- misc2.c prevent warning in DoSetScaleDesc
-
-Mar 02nd, 2006
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- cturnout.c Improvements to the select turnout dialog, new turnout is drawn
- blue
-
-Feb. 26th, 2006
-
- NEW FEATURE: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, cselect.c, 'Select orphaned track' command added to set all
- unconnected track pieces.
-
-Feb, 22nd, 2006
-
- NEW FEATURE: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, misc2.c, doption.c Scale and gauge are two independant seetings
- now.
-
- NEW FEATURE: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c, cselect.c Add new function 'Invert Selection' which inverts
- the selection state of all visible objects on the layout
-
- NEW FEATURE: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c Add new function 'Revert' to main menu, implemented in ChkRevert
- acclkeys.h Added Ctrl-r as accelerator for 'Revert'
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- cselect.c Optimized performance for 'Select Connected' operation
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- bllnhelp.c: removed inconsistencies in usage of 'track' and 'object'
-
- IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
- misc.c: moved 'Join' command to 'Change' menu
-
- BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
- fileio.c Setting locale to portable 'C' before reading/writing parameters
- and trackplans to prevent problems with locales that use comma as decimal
- separator ( eg. Germany )
-
- BUGFIX:
diff --git a/app/bin/acclkeys.h b/app/bin/acclkeys.h
index 09bd9bb..1cbdf00 100644
--- a/app/bin/acclkeys.h
+++ b/app/bin/acclkeys.h
@@ -30,6 +30,7 @@
/* commands */
#define ACCL_DESCRIBE (WCTL+'?')
#define ACCL_SELECT (WCTL+'e')
+#define ACCL_PAN (WCTL+'/')
#define ACCL_STRAIGHT (WCTL+'g')
#define ACCL_CURVE1 (WCTL+'4')
#define ACCL_CURVE2 (WCTL+'5')
@@ -38,6 +39,7 @@
#define ACCL_CIRCLE1 (WCTL+'8')
#define ACCL_CIRCLE2 (WCTL+'9')
#define ACCL_CIRCLE3 (WCTL+'0')
+#define ACCL_BEZIER (0)
#define ACCL_TURNOUT (WCTL+'t')
#define ACCL_TURNTABLE (WCTL+WSHIFT+'n')
#define ACCL_PARALLEL (WCTL+WSHIFT+'p')
@@ -70,6 +72,7 @@
#define ACCL_DRAWFILLCIRCLE1 (WALT+WCTL+'8')
#define ACCL_DRAWFILLCIRCLE2 (WALT+WCTL+'9')
#define ACCL_DRAWFILLCIRCLE3 (WALT+WCTL+'0')
+#define ACCL_DRAWBEZLINE (0)
#define ACCL_DRAWBOX (WCTL+WSHIFT+'[')
#define ACCL_DRAWFILLBOX (WALT+WCTL+'[')
#define ACCL_DRAWPOLYLINE (WCTL+WSHIFT+'2')
diff --git a/app/bin/appdefaults.c b/app/bin/appdefaults.c
new file mode 100644
index 0000000..a2dd885
--- /dev/null
+++ b/app/bin/appdefaults.c
@@ -0,0 +1,435 @@
+/** \file appdefaults.c
+* Provide defaults, mostly for first run of the program.
+*/
+
+/* XTrkCad - Model Railroad CAD
+* Copyright (C) 2017 Martin Fischer
+*
+* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#ifdef WINDOWS
+#include <Windows.h>
+#include <malloc.h>
+#endif
+
+#include "common.h"
+#include "custom.h"
+#include "fileio.h"
+#include "paths.h"
+#include "wlib.h"
+
+enum defaultTypes {
+ INTEGERCONSTANT,
+ FLOATCONSTANT,
+ STRINGCONSTANT,
+ INTEGERFUNCTION,
+ FLOATFUNCTION,
+ STRINGFUNCTION
+};
+
+struct appDefault {
+ char *defaultKey; /**< the key used to access the value */
+ bool wasUsed; /**< value has already been used on this run */
+ enum defaultTypes
+ valueType; /**< type of default, constant or pointer to a function */
+ union {
+ int intValue;
+ double floatValue;
+ char *stringValue;
+ int (*intFunction)(struct appDefault *, void *);
+ double (*floatFunction)(struct appDefault *, void *);
+ char *(*stringFunction)(struct appDefault *, void *);
+ } defaultValue;
+ void *additionalData;
+};
+
+static int GetLocalMeasureSystem(struct appDefault *ptrDefault,
+ void *additionalData);
+static int GetLocalDistanceFormat(struct appDefault *ptrDefault,
+ void *additionalData);
+static char *GetLocalPopularScale(struct appDefault *ptrDefault,
+ void *additionalData);
+static double GetLocalRoomSize(struct appDefault *ptrDefault,
+ void *additionalData);
+static char *GetParamFullPath(struct appDefault *ptrDefault,
+ void *additionalData);
+static char *GetParamPrototype(struct appDefault *ptrDefault,
+ void *additionalData);
+
+/**
+ * List of application default settings. As this is searched by binary search, the list has to be kept sorted
+ * alphabetically for the key, the first element
+ * Also the search is case sensitive on this field.
+ */
+
+struct appDefault xtcDefaults[] = {
+ { "DialogItem.cmdopt-preselect", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< default command is select */
+ { "DialogItem.grid-horzenable", 0, INTEGERCONSTANT, { .intValue = 0 }},
+ { "DialogItem.grid-vertenable", 0, INTEGERCONSTANT,{ .intValue = 0 } },
+ { "DialogItem.pref-dstfmt", 0, INTEGERFUNCTION,{ .intFunction = GetLocalDistanceFormat } }, /**< number format for distances */
+ { "DialogItem.pref-units", 0, INTEGERFUNCTION,{ .intFunction = GetLocalMeasureSystem } }, /**< default unit depends on region */
+ { "DialogItem.rgbcolor-exception", 0, INTEGERCONSTANT, { .intValue = 15923462 }}, /**< rich yellow as exception color */
+ { "Parameter File Map.British stock", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "br.xtp" },
+ { "Parameter File Map.European stock", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "eu.xtp" },
+ { "Parameter File Map.NMRA RP12-25 Feb 2015 O scale Turnouts", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "nmra-o.xtp" },
+ { "Parameter File Map.NMRA RP12-27 Feb 2015 S Scale Turnouts", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "nmra-s.xtp" },
+ { "Parameter File Map.NMRA RP12-31 Feb 2015 HO Scale Turnouts", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "nmra-ho.xtp" },
+ { "Parameter File Map.NMRA RP12-33 Feb 2015 TT Scale Turnouts", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "nmra-tt.xtp" },
+ { "Parameter File Map.NMRA RP12-35 Feb 2015 N Scale Turnouts", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "nmra-n.xtp" },
+ { "Parameter File Map.NMRA RP12-37 Feb 2015 Z scale Turnouts", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "nmra-z.xtp" },
+ { "Parameter File Map.North American Prototypes", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath }, "protoam.xtp" },
+ { "Parameter File Map.Trees", 0, STRINGFUNCTION,{ .stringFunction = GetParamFullPath } , "trees.xtp" },
+ { "Parameter File Names.File1", 0, STRINGFUNCTION,{ .stringFunction = GetParamPrototype }},
+ { "Parameter File Names.File2", 0, STRINGCONSTANT,{ .stringValue = "Trees" } },
+ { "Parameter File Names.File3", 0, STRINGCONSTANT,{ .stringValue = "NMRA RP12-37 Feb 2015 Z scale Turnouts" } },
+ { "Parameter File Names.File4", 0, STRINGCONSTANT,{ .stringValue = "NMRA RP12-35 Feb 2015 N Scale Turnouts" } },
+ { "Parameter File Names.File5", 0, STRINGCONSTANT,{ .stringValue = "NMRA RP12-33 Feb 2015 TT Scale Turnouts" } },
+ { "Parameter File Names.File6", 0, STRINGCONSTANT,{ .stringValue = "NMRA RP12-31 Feb 2015 HO Scale Turnouts" } },
+ { "Parameter File Names.File7", 0, STRINGCONSTANT,{ .stringValue = "NMRA RP12-27 Feb 2015 S Scale Turnouts" } },
+ { "Parameter File Names.File8", 0, STRINGCONSTANT,{ .stringValue = "NMRA RP12-25 Feb 2015 O scale Turnouts" } },
+ { "draw.roomsizeX", 0, FLOATFUNCTION, {.floatFunction = GetLocalRoomSize }}, /**< layout width */
+ { "draw.roomsizeY", 0, FLOATFUNCTION,{ .floatFunction = GetLocalRoomSize } }, /**< layout depth */
+ { "misc.scale", 0, STRINGFUNCTION, { .stringFunction = GetLocalPopularScale}}, /**< the (probably) most popular scale for a region */
+};
+
+#define DEFAULTCOUNT (sizeof(xtcDefaults)/sizeof(xtcDefaults[0]))
+
+
+static long bFirstRun; /**< TRUE if appl is run the first time */
+static char regionCode[3]; /**< will be initialized to the locale's region code */
+
+static wBool_t(*GetIntegerPref)(const char *, const char *, long *, long) = wPrefGetIntegerExt; /**< pointer to active integer pref getter */
+static wBool_t(*GetFloatPref)(const char *, const char *, double *, double) = wPrefGetFloatExt; /**< pointer to active float pref getter */
+static char *(*GetStringPref)(const char *, const char *) = wPrefGetStringExt; /**< pointer to active string pref getter */
+
+/**
+ * A recursive binary search function. It returns location of x in
+ * given array arr[l..r] is present, otherwise -1
+ * Taken from http://www.geeksforgeeks.org/binary-search/ and modified
+ *
+ * \param arr IN array to search
+ * \param l IN starting index
+ * \param r IN highest index in array
+ * \param key IN key to search
+ * \return index if found, -1 otherwise
+ */
+
+static int binarySearch(struct appDefault arr[], int l, int r, char *key)
+{
+ if (r >= l) {
+ int mid = l + (r - l) / 2;
+ int res = strcmp(key, arr[mid].defaultKey);
+
+ // If the element is present at the middle itself
+ if (!res) {
+ return mid;
+ }
+
+ // If the array size is 1
+ if (r == 0) {
+ return -1;
+ }
+
+ // If element is smaller than mid, then it can only be present
+ // in left subarray
+ if (res < 0) {
+ return binarySearch(arr, l, mid - 1, key);
+ }
+
+ // Else the element can only be present in right subarray
+ return binarySearch(arr, mid + 1, r, key);
+ }
+
+ // We reach here when element is not present in array
+ return -1;
+}
+
+/**
+ * Lookup default for a value
+ *
+ * \param defaultValues IN array of all default values
+ * \param section IN default's section
+ * \param name IN default's name
+ * \return pointer to default if found, NULL otherwise
+ */
+struct appDefault *
+FindDefault(struct appDefault *defaultValues, const char *section,
+ const char *name)
+{
+ char *searchString = malloc(strlen(section) + strlen(name) +
+ 2); //includes separator and terminating \0
+ int res;
+ sprintf(searchString, "%s.%s", section, name);
+
+ res = binarySearch(defaultValues, 0, DEFAULTCOUNT-1, searchString);
+ free(searchString);
+
+ if (res != -1 && defaultValues[res].wasUsed == FALSE) {
+ defaultValues[res].wasUsed = TRUE;
+ return (defaultValues + res);
+ } else {
+ return (NULL);
+ }
+}
+/**
+ * Get the application's default region code. On Windows, the system's API is used.
+ * On *ix the environment variable LANG is supposed to contain a value in the
+ * format ll_RR* where rr is the two character region code.
+ */
+static void
+InitializeRegionCode(void)
+{
+ strcpy(regionCode, "US");
+
+#ifdef WINDOWS
+ {
+ LCID lcid;
+ char iso3166[10];
+
+ lcid = GetThreadLocale();
+ GetLocaleInfo(lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof(iso3166));
+ strncpy(regionCode, iso3166, 2);
+ }
+#else
+ {
+ char *pLang;
+ pLang = getenv("LANG");
+
+ if (pLang) {
+ char *ptr;
+ ptr = strpbrk(pLang, "_-");
+
+ if (ptr) {
+ strncpy(regionCode, ptr + 1, 2);
+ }
+ }
+ }
+#endif
+}
+
+/**
+ * For the US the classical 4x8 sheet is used as default size. in the metric world 1,25x2,0m is used.
+ */
+
+static double
+GetLocalRoomSize(struct appDefault *ptrDefault, void *data)
+{
+ if (!strcmp(ptrDefault->defaultKey, "draw.roomsizeY")) {
+ return (strcmp(regionCode, "US") ? 125.0/2.54 : 48);
+ }
+
+ if (!strcmp(ptrDefault->defaultKey, "draw.roomsizeX")) {
+ return (strcmp(regionCode, "US") ? 200.0 / 2.54 : 96);
+ }
+
+ return (0.0); // should never get here
+}
+
+/**
+ * The most popular scale is supposed to be HO except for UK where OO is assumed.
+ */
+
+static char *
+GetLocalPopularScale(struct appDefault *ptrDefault, void *data)
+{
+ return (strcmp(regionCode, "GB") ? "HO" : "OO");
+}
+
+/**
+ * The measurement system is english for the US and metric elsewhere
+ */
+static int
+GetLocalMeasureSystem(struct appDefault *ptrDefault, void *data)
+{
+ return (strcmp(regionCode, "US") ? 1 : 0);
+}
+
+/**
+* The distance format is 999.9 cm for metric and ?? for english
+*/
+static int
+GetLocalDistanceFormat(struct appDefault *ptrDefault, void *data)
+{
+ return (strcmp(regionCode, "US") ? 8 : 5);
+}
+
+/**
+* Prototype definitions currently only exist for US and British. So US
+* is assumed to be the default.
+*/
+
+static char*
+GetParamPrototype(struct appDefault *ptrDefault, void *additionalData)
+{
+ return (strcmp(regionCode, "GB") ? "North American Prototypes" : "British stock");
+}
+
+/**
+ * The full path to the applications parameter directory
+ */
+static char *
+GetParamFullPath(struct appDefault *ptrDefault, void *additionalData)
+{
+ char *str;
+ MakeFullpath(&str, libDir, PARAM_SUBDIR, (char*)additionalData, (void *)0);
+ return str;
+}
+
+
+/**
+ * The following are three jump points for the correct implementation. Changing the funtion pointer
+ * allows to switch from the extended default version to the basic implementation.
+ */
+
+wBool_t
+wPrefGetInteger(const char *section, const char *name, long *result, long defaultValue)
+{
+ return GetIntegerPref(section, name, result, defaultValue);
+}
+
+wBool_t
+wPrefGetFloat(const char *section, const char *name, double *result, double defaultValue)
+{
+ return GetFloatPref(section, name, result, defaultValue);
+}
+
+char *
+wPrefGetString(const char *section, const char *name)
+{
+ return GetStringPref(section, name);
+}
+
+/**
+ * Get an integer value from the configuration file. The is a wrapper for the real
+ * file access and adds a region specific default value.
+ *
+ * \param section IN section in config file
+ * \param name IN name in config file
+ * \param result OUT pointer to result
+ * \param defaultValue IN the default value to use if config is not found
+ * \return returncode of wPrefGetIntegerBasic()
+ */
+wBool_t
+wPrefGetIntegerExt(const char *section, const char *name, long *result,
+ long defaultValue)
+{
+ struct appDefault *thisDefault;
+
+ thisDefault = FindDefault(xtcDefaults, section, name);
+
+ if (thisDefault) {
+ if (thisDefault->valueType == INTEGERCONSTANT) {
+ defaultValue = thisDefault->defaultValue.intValue;
+ } else {
+ defaultValue = (thisDefault->defaultValue.intFunction)(thisDefault,
+ thisDefault->additionalData);
+ }
+ }
+
+ return (wPrefGetIntegerBasic(section, name, result, defaultValue));
+}
+
+/**
+ * Get a float value from the configuration file. The is a wrapper for the real
+ * file access and adds a region specific default value.
+ *
+ * \param section IN section in config file
+ * \param name IN name in config file
+ * \param result OUT pointer to result
+ * \param defaultValue IN the default value to use if config is not found
+ * \return returncode of wPrefGetFloatBasic()
+ */
+
+wBool_t
+wPrefGetFloatExt(const char *section, const char *name, double *result,
+ double defaultValue)
+{
+ struct appDefault *thisDefault;
+
+ thisDefault = FindDefault(xtcDefaults, section, name);
+
+ if (thisDefault) {
+ if (thisDefault->valueType == FLOATCONSTANT) {
+ defaultValue = thisDefault->defaultValue.floatValue;
+ } else {
+ defaultValue = (thisDefault->defaultValue.floatFunction)(thisDefault,
+ thisDefault->additionalData);
+ }
+ }
+
+ return (wPrefGetFloatBasic(section, name, result, defaultValue));
+}
+
+/**
+ * Get a string from the configuration file. The is a wrapper for the real
+ * file access and adds a region specific default value.
+ *
+ * \param section IN section in config file
+ * \param name IN name in config file
+ * \return returncode of wPrefGetStringBasic()
+ */
+char *
+wPrefGetStringExt(const char *section, const char *name)
+{
+ struct appDefault *thisDefault;
+
+ thisDefault = FindDefault(xtcDefaults, section, name);
+
+ if (thisDefault) {
+ char *prefString;
+ char *defaultValue;
+
+ if (thisDefault->valueType == STRINGCONSTANT) {
+ defaultValue = thisDefault->defaultValue.stringValue;
+ } else {
+ defaultValue = (thisDefault->defaultValue.stringFunction)(thisDefault,
+ thisDefault->additionalData);
+ }
+
+ prefString = (char *)wPrefGetStringBasic(section, name);
+ return (prefString ? prefString : defaultValue);
+ } else {
+ return ((char *)wPrefGetStringBasic(section, name));
+ }
+}
+
+/**
+ * Initialize the application default system. The flag firstrun is used to find
+ * out whether the application was run before. This is accomplished by trying
+ * to read it from the configuration file. As it is only written after this
+ * test, it can never be found on the first run of the application ie. when the
+ * configuration file does not exist yet.
+ */
+
+void
+InitAppDefaults(void)
+{
+ wPrefGetIntegerBasic( "misc", "firstrun", &bFirstRun, TRUE);
+ if (bFirstRun) {
+ wPrefSetInteger("misc", "firstrun", FALSE);
+ InitializeRegionCode();
+ } else {
+ GetIntegerPref = wPrefGetIntegerBasic;
+ GetFloatPref = wPrefGetFloatBasic;
+ GetStringPref = wPrefGetStringBasic;
+ }
+}
diff --git a/app/bin/bdf2xtp.c b/app/bin/bdf2xtp.c
index adc2b04..76fb31a 100644
--- a/app/bin/bdf2xtp.c
+++ b/app/bin/bdf2xtp.c
@@ -134,21 +134,17 @@ double findDistance( coOrd p0, coOrd p1 )
int small(double v )
/* is <v> close to 0.0 */
{
- return (fabs(v) < 0.0001);
+ return (fabs(v) < 0.000000000001);
}
double findAngle( coOrd p0, coOrd p1 )
/* find angle between two points */
{
double dx = p1.x-p0.x, dy = p1.y-p0.y;
- if (small(dx)) {
- if (dy >=0) return 0.0;
+ if (small(dx) && small(dy)) {
+ if (dy >=0.0) return 0.0;
else return 180.0;
}
- if (small(dy)) {
- if (dx >=0) return 90.0;
- else return 270.0;
- }
return R2D(atan2( dx,dy ));
}
diff --git a/app/bin/bitmaps/bezier.xpm b/app/bin/bitmaps/bezier.xpm
new file mode 100644
index 0000000..6c592ed
--- /dev/null
+++ b/app/bin/bitmaps/bezier.xpm
@@ -0,0 +1,23 @@
+/* XPM */
+static char * bezier_xpm[] = {
+"16 16 4 1",
+" c None",
+"! c #000000000000",
+"# c #FFFF00000000",
+"$ c #808080000000",
+" ### !!!!",
+" # #########",
+" ### !! !",
+" $!! $!!!",
+" !!$$ !! !",
+" !! $!$ !",
+" $$ !! !! $ ",
+" !!!!!!! ",
+" !! ! $$ ",
+" $!! !! ",
+"! !$$!! ",
+"! ! $! ",
+"!!!$ !!$ ",
+"! !! ### ",
+"######### # ",
+"!!!! ### "}; \ No newline at end of file
diff --git a/app/bin/bitmaps/dbezier.xpm b/app/bin/bitmaps/dbezier.xpm
new file mode 100644
index 0000000..1bf366f
--- /dev/null
+++ b/app/bin/bitmaps/dbezier.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static char * dbezier_xpm[] = {
+"16 16 3 1",
+" c None",
+"! c #000000000000",
+"# c #FFFF00000000",
+" ### ",
+" # ########",
+" ### !!!!",
+" !!!! ",
+" !!!! ",
+" !!! ",
+" !!! ",
+" !! ",
+" !!! ",
+" !! ",
+" !!! ",
+" !!! ",
+" !!! ",
+"!!!! ### ",
+"######## # ",
+" ### "}; \ No newline at end of file
diff --git a/app/bin/bitmaps/ecornu.xpm b/app/bin/bitmaps/ecornu.xpm
new file mode 100644
index 0000000..e32e56a
--- /dev/null
+++ b/app/bin/bitmaps/ecornu.xpm
@@ -0,0 +1,23 @@
+/* XPM */
+static char * ecornu_xpm[] = {
+"41 16 4 1",
+". c None",
+" c #000000000000",
+"# c #FFFF00000000",
+"$ c #808080000000",
+" .................................. .",
+" ..................................... ",
+" ...... ... .. .. . ... .. .. .",
+" .. .. . .... .. . .. .. . .. . .. . .",
+" ..... .. .. .. . .. .. . . .. . .",
+" ..... .. .... . .... .. .. . .... .. . .",
+" .. . ... . .. .. .. . .. .. ",
+".........................................",
+"...$$$...###.....................$$$$$...",
+"..$...$.#...#................$$$$.....$..",
+".$..$..$#......##..###..###$$#..#.$$$..$.",
+"$..$.$..#.....#..#.#$$#$#..#.#..#$...$..$",
+"$..$...$#.....#$$#$#....#..#.#..#..$.$..$",
+".$..$$$.#..$#$#..#.#....#..#.#..#$..$..$.",
+"..$.....$###...##..#....#..#..##..$...$..",
+"...$$$$$...........................$$$..."};
diff --git a/app/bin/bitmaps/eltsharp.xpm b/app/bin/bitmaps/eltsharp.xpm
new file mode 100644
index 0000000..70985c1
--- /dev/null
+++ b/app/bin/bitmaps/eltsharp.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+static char * eltsharp_xpm[] = {
+"41 16 2 1",
+". c None",
+" c #000000000000",
+" .................................. .",
+" ..................................... ",
+" ...... ... .. .. . ... .. .. .",
+" .. .. . .... .. . .. .. . .. . .. . .",
+" ..... .. .. .. . .. .. . . .. . .",
+" ..... . .... . .... .. .. . .... .. . .",
+" .. . . ... . .. .. .. . .. .. ",
+".........................................",
+"..... ...... . ......................",
+".... ...... ...... ......................",
+"... ....... ...... ... .. .. .....",
+".. ......... . .. . .. . .. . .. ....",
+"... ............ . .. . .. . .... .. ....",
+".... ........... . .. . . . .... .....",
+"..... ..... .. .. .. . . .... .......",
+"................................. ......."};
diff --git a/app/bin/bitmaps/helix.xpm b/app/bin/bitmaps/helix.xpm
deleted file mode 100644
index ba0551e..0000000
--- a/app/bin/bitmaps/helix.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static char * helix_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #000000000000",
-" ",
-" ........... ",
-" . ",
-" . . ",
-" . . ",
-" .......... ",
-" . . ",
-" . . ",
-" .......... ",
-" . . ",
-" . . ",
-" ......... ",
-" . ",
-" . ",
-" ............ ",
-" "};
diff --git a/app/bin/bitmaps/map.xpm b/app/bin/bitmaps/map.xpm
new file mode 100644
index 0000000..a1f427a
--- /dev/null
+++ b/app/bin/bitmaps/map.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static char * map_xpm[] = {
+"16 16 3 1",
+"o c None",
+" c #000000000000",
+". c #FFFFFFFFFFFF",
+"ooo ooo",
+"ooo ooo",
+"oo ........ oo",
+"oo ........ oo",
+"o .......... o",
+"o .......... o",
+" ...... .... ",
+" .... .. ... ",
+" .. .. .... .. ",
+" ... ...... . ",
+" .............. ",
+" ",
+" ",
+"oooooooooooooooo",
+"oooooooooooooooo",
+"oooooooooooooooo"};
diff --git a/app/bin/bitmaps/pan.xpm b/app/bin/bitmaps/pan.xpm
new file mode 100644
index 0000000..8782714
--- /dev/null
+++ b/app/bin/bitmaps/pan.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static char * pan_xpm[] = {
+"16 16 3 1",
+" c None",
+". c #000000000000",
+"X c #FFFF00000000",
+" ",
+" XX ",
+" XXXX ",
+" XXXXXX. ",
+" XX XX XX ",
+" XX ",
+" XX XX XX ",
+" XXXXXXXXXXXXXX ",
+" XXXXXXXXXXXXXX ",
+" XX XX XX ",
+" XX ",
+" XX XX XX ",
+" XXXXXX ",
+" XXXX ",
+" XX ",
+" "};
diff --git a/app/bin/cbezier.c b/app/bin/cbezier.c
new file mode 100644
index 0000000..92855c1
--- /dev/null
+++ b/app/bin/cbezier.c
@@ -0,0 +1,1153 @@
+/** \file cbezier.c
+ * Bezier Command. Draw or modify a Bezier (Track or Line).
+ */
+ /* XTrkCad - Model Railroad CAD
+ *
+ * Cubic Bezier curves have a definitional representation as an a set of four points.
+ * The first and fourth are the end points, while the middle two are control points.
+ * The control points positions define the angle at the ends and by their relative positions the overall
+ * curvature. This representation is a familiar approach for those who know drawing programs such as Adobe
+ * Illustrator or CorelDraw.
+ *
+ * In XTrackCAD, the Bezier form is also represented and drawn as a set of
+ * joined circular arcs that approximate the Bezier form within a small tolerance. This is because
+ * many of the operations we need to do are either computationally difficult or
+ * impossible using the Bezier equations. For example, creating a parallel Bezier
+ * which is necessary to draw a track with two lines or sleepers has no easy, stable solution.
+ * But the program is already able to do these tasks for straight lines and curves.
+ *
+ * Note that every time we change the Bezier points we have to recalculate the arc approximation,
+ * but that means that the majority of the time we are using the simpler approximation.
+ *
+ * We do not allow Bezier curves that have loops or cusps as they make no sense for tracks and
+ * can easily be approximated for lines with multiple unaligned Bezier curves.
+ *
+ * This program borrows from particular ideas about converting Bezier curves that Pomax placed into
+ * open source. The originals in Javascript can be found at github.com/Pomax.
+ * The web pages that explain many other techniques are located at https://pomax.github.io/bezierinfo
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include "track.h"
+#include "draw.h"
+#include "ccurve.h"
+#include "cbezier.h"
+#include "tbezier.h"
+#include "cstraigh.h"
+#include "drawgeom.h"
+#include "cjoin.h"
+#include "i18n.h"
+#include "common.h"
+#include "wcolors.h"
+#include "math.h"
+#include "utility.h"
+#include "param.h"
+#include "fileio.h"
+#include "layout.h"
+#include "cundo.h"
+
+extern drawCmd_t tempD;
+
+
+/*
+ * STATE INFO
+ */
+enum Bezier_States { NONE,
+ POS_1,
+ CONTROL_ARM_1,
+ POS_2,
+ CONTROL_ARM_2,
+ PICK_POINT,
+ POINT_PICKED,
+ TRACK_SELECTED };
+
+typedef struct {
+ curveData_t curveData;
+ double start;
+ double end;
+ coOrd pos0;
+ coOrd pos1;
+ } bCurveData_t;
+
+static struct {
+ enum Bezier_States state;
+ coOrd pos[4];
+ int selectPoint;
+ wDrawColor color;
+ DIST_T width;
+ track_p trk[2];
+ EPINX_T ep[2];
+ dynArr_t crvSegs_da;
+ int crvSegs_da_cnt;
+ trkSeg_t cp1Segs_da[4];
+ int cp1Segs_da_cnt;
+ trkSeg_t cp2Segs_da[4];
+ int cp2Segs_da_cnt;
+ BOOL_T unlocked;
+ track_p selectTrack;
+ BOOL_T track;
+ DIST_T minRadius;
+ } Da;
+
+
+
+/**
+ * Draw a ControlArm.
+ * A control arm has two filled or unfilled circles for endpoints and a straight line between them.
+ * If the end or control point is not selectable we don't mark it with a circle.
+ * If a selectable end or control point is unlocked place a filled circle on it, otherwise an empty circle.
+ * A red color indicates that this arm, end or control point is "active" as it was selected.
+ */
+int createControlArm(
+ trkSeg_t sp[], //seg pointer for up to 3 trkSegs (ends and line)
+ coOrd pos0, //end on curve
+ coOrd pos1, // control point at other end of line
+ BOOL_T track, // isTrack()? (otherwise Line)
+ BOOL_T selectable, // can this arm be selected?
+ BOOL_T cp_direction_locked, //isFixed to track
+ int point_selected, //number of point 0, 1 or -1
+ wDrawColor color //drawColorBlack or drawColorWhite
+ )
+{
+ DIST_T d, w;
+ d = tempD.scale*0.25;
+ w = tempD.scale/tempD.dpi; /*double width*/
+ sp[0].u.l.pos[0] = pos0;
+ sp[0].u.l.pos[1] = pos1;
+ sp[0].type = SEG_STRLIN;
+ sp[0].width = w;
+ sp[0].color = (point_selected>=0)?drawColorRed:drawColorBlack;
+ int n = 0;
+ if (selectable) {
+ for (int j=0;j<2;j++) {
+ if (j==0 && cp_direction_locked) continue; //Don't show select circle if end locked
+ n++;
+ sp[n].u.c.center = j==0?pos0:pos1;
+ sp[n].u.c.radius = d/4;
+ sp[n].width = w;
+ sp[n].color = (j==point_selected)?drawColorRed:drawColorBlack;
+ if (j==point_selected && cp_direction_locked) {
+ sp[n].type = SEG_FILCRCL;
+ } else {
+ sp[n].type = SEG_CRVLIN;
+ sp[n].u.c.a0 = 0.0;
+ sp[n].u.c.a1 = 360.0;
+ }
+ }
+ }
+ return n+1;
+}
+
+coOrd getPoint(coOrd pos[4], double s) {
+ double mt = 1-s;
+ double a = mt*mt*mt;
+ double b = mt*mt*s*3;
+ double c = mt*s*s*3;
+ double d = s*s*s;
+ coOrd ret;
+ ret.x = a*pos[0].x + b*pos[1].x + c*pos[2].x + d*pos[3].x;
+ ret.y = a*pos[0].y + b*pos[1].y + c*pos[2].y + d*pos[3].y;
+ return ret;
+}
+/*
+ * Get Error between a Bezier and an arc centered at pc that goes from start to end
+ *
+ * Because the curve is defined to pass through the start and the end and the middle, the test is
+ * to see how much of an error there is between those points. If the sum of the errors is off by more \
+ * than 0.5 pixels - that will mean it is not a good fit.
+ *
+ */
+double BezError(coOrd pos[4], coOrd center, coOrd start_point, double start, double end) {
+ double quarter = (end - start) / 4; // take point at 1/4 and 3/4 and check
+ coOrd c1 = getPoint(pos, start + quarter);
+ coOrd c2 = getPoint(pos, end - quarter);
+ double ref = FindDistance(center, start_point); //radius
+ double d1 = FindDistance(center, c1); // distance to quarter
+ double d2 = FindDistance(center, c2); // distance to three quarters
+ return fabs(d1-ref) + fabs(d2-ref); //total error at quarter points
+};
+
+/*
+ * Get distance between a point and a line segment
+ */
+
+double DistanceToLineSegment(coOrd p, coOrd l1, coOrd l2) {
+ double A = p.x - l1.x;
+ double B = p.y - l1.y;
+ double C = l2.x - l1.x;
+ double D = l2.y - l1.y;
+
+ double dot = A * C + B * D;
+ double len_sq = C * C + D * D;
+ double param = -1;
+ if (len_sq != 0) //non 0 length line
+ param = dot / len_sq;
+
+ double xx, yy;
+
+ if (param < 0) { // zero length line or beyond end use point 1
+ xx = l1.x;
+ yy = l1.y;
+ } else if (param > 1) { // beyond point 2 end of line segment
+ xx = l2.x;
+ yy = l2.y;
+ } else { // In the middle
+ xx = l1.x + param * C;
+ yy = l1.y + param * D;
+ }
+
+ double dx = p.x - xx; //distance to perpendicular (or end point)
+ double dy = p.y - yy;
+ return sqrt(dx * dx + dy * dy);
+}
+
+/*
+ * Get Error between a straight line segment and the Bezier curve.
+ * Sum distance to straight line of quarter points.
+ */
+
+double BezErrorLine(coOrd pos[4], coOrd start_point, coOrd end_point, double start, double end) {
+ double quarter = (end - start) / 4; // take point at 1/4 and 3/4 and check
+ coOrd c1 = getPoint(pos, start + quarter);
+ coOrd c2 = getPoint(pos, end - quarter);
+ double d1 = DistanceToLineSegment(c1, start_point, end_point);
+ double d2 = DistanceToLineSegment(c2, start_point, end_point);
+ return fabs(d1)+fabs(d2);
+}
+
+/*
+ * Add element to DYNARR pointed to by caller from segment handed in
+ */
+void addSegBezier(dynArr_t * const array_p, trkSeg_p seg) {
+ trkSeg_p s;
+
+
+ DYNARR_APPEND(trkSeg_t, * array_p, 1); //Adds 1 to cnt
+ s = &DYNARR_N(trkSeg_t,* array_p,array_p->cnt-1);
+ s->type = seg->type;
+ s->color = seg->color;
+ s->width = seg->width;
+ s->bezSegs.cnt = 0;
+ if (s->bezSegs.ptr) MyFree(s->bezSegs.ptr);
+ s->bezSegs.ptr=NULL;
+ s->bezSegs.max = 0;
+ if ((s->type == SEG_BEZLIN || s->type == SEG_BEZTRK) && seg->bezSegs.cnt) {
+ s->u.b.angle0 = seg->u.b.angle0; //Copy all the rest
+ s->u.b.angle3 = seg->u.b.angle3;
+ s->u.b.length = seg->u.b.length;
+ s->u.b.minRadius = seg->u.b.minRadius;
+ for (int i=0;i<4;i++) s->u.b.pos[i] = seg->u.b.pos[i];
+ s->u.b.radius0 = seg->u.b.radius3;
+ s->bezSegs.cnt = 0;
+ if (s->bezSegs.ptr) MyFree(s->bezSegs.ptr);
+ s->bezSegs.max = 0;
+ s->bezSegs.ptr = NULL; //Make sure new space as addr copied in earlier from seg
+ for (int i = 0; i<seg->bezSegs.cnt; i++) {
+ addSegBezier(&s->bezSegs,(((trkSeg_p)seg->bezSegs.ptr)+i)); //recurse for copying embedded Beziers as in Cornu joint
+ }
+ } else {
+ s->u = seg->u;
+ }
+}
+
+enum BezierType {PLAIN, LOOP, CUSP, INFLECTION, DOUBLEINFLECTION, LINE, ENDS, COINCIDENT } bType;
+
+/*
+ * Analyse Bezier.
+ *
+ * Using results from Maureen C. Stone of XeroxParc and Tony deRose of U of Washington
+ * characterise the curve type and find out what features it has.
+ * We will eliminate cusps and loops as not useful forms. Line, Plain, Inflection and DoubleInflection are ok.
+ *
+ */
+EXPORT enum BezierType AnalyseCurve(coOrd inpos[4], double *Rfx, double *Rfy, double *cusp) {
+
+ *Rfx = *Rfy = 0;
+ if (Da.track && inpos[0].x == inpos[3].x && inpos[0].y == inpos[3].y ) {
+ return ENDS;
+ }
+
+ DIST_T d01 = FindDistance(inpos[0],inpos[1]);
+ DIST_T d12 = FindDistance(inpos[1],inpos[2]);
+ DIST_T d02 = FindDistance(inpos[0],inpos[2]);
+ if (d01+d12 == d02) { //straight
+ DIST_T d23 = FindDistance(inpos[2],inpos[3]);
+ DIST_T d03 = FindDistance(inpos[0],inpos[3]);
+ if (d02+d23 == d03) return LINE;
+ }
+ int common_points = 0;
+ for (int i=0;i<3;i++) {
+ if (inpos[i].x == inpos[i+1].x && inpos[i].y == inpos[i+1].y) common_points++;
+ }
+ for (int i=0;i<2;i++) {
+ if (inpos[i].x == inpos[i+2].x && inpos[i].y == inpos[i+2].y) common_points++;
+ }
+
+ if (common_points>2) {
+ return COINCIDENT;
+ }
+
+ coOrd pos[4];
+ coOrd offset2, offset = inpos[0];
+
+ for (int i=0;i<4;i++) { //move to zero origin
+ pos[i].x = inpos[i].x-offset.x;
+ pos[i].y = inpos[i].y-offset.y;
+ }
+
+ offset2.x = -offset.x + pos[3].x;
+ offset2.y = -offset.y + pos[3].y;
+ if (pos[1].y == 0.0) { //flip order of points
+ for (int i=0;i<4;i++) {
+ coOrd temp_pos = pos[i];
+ pos[i].x = pos[3-i].x - offset2.x;
+ pos[i].y = pos[3-i].y - offset2.y;
+ pos[3-i] = temp_pos;
+ }
+ if (pos[1].y == 0.0) { //Both ways round the second point has no y left after translation
+ return PLAIN;
+ }
+ }
+ double f21 = (pos[2].y)/(pos[1].y);
+ double f31 = (pos[3].y)/(pos[1].y);
+ if (fabs(pos[2].x-(pos[1].x*f21)) <0.0001) return PLAIN; //defend against divide by zero
+ double fx = (pos[3].x-(pos[1].x*f31))/(pos[2].x-(pos[1].x*f21));
+ double fy = f31+(1-f21)*fx;
+ *Rfx = fx;
+ *Rfy = fy;
+ *cusp = fabs(fy - (-(fx*fx)+2*fx+3)/4);
+
+ if (fy > 1.0) return INFLECTION;
+ if (fx >= 1.0) return PLAIN;
+ if (fabs(fy - (-(fx*fx)+2*fx+3)/4) <0.100) return CUSP;
+ if (fy < (-(fx*fx)+2*fx+3)/4) {
+ if (fx <= 0.0 && fy >= (3*fx-(fx*fx))/3) return LOOP;
+ if (fx > 0.0 && fy >= (sqrt(3*(4*fx-fx*fx))-fx)/2) return LOOP;
+ return PLAIN;
+ }
+
+ return DOUBLEINFLECTION;
+}
+
+/*
+ * ConvertToArcs
+ * Take a Bezier curve and turn it into a set of circular arcs, such that the error between the arc and the
+ * Bezier is under 0.5 pixels at maxiumum zoom.
+ *
+ * This enables us to use normal methods (operating over the array of arcs)
+ * to perform actions on the Bezier and also to export it to DXF.
+ *
+ */
+EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawColor color, DIST_T width) {
+ double t_s = 0.0, t_e = 1.0;
+ double errorThreshold = 0.05;
+ bCurveData_t prev_arc;
+ prev_arc.end = 0.0;
+ bCurveData_t arc;
+ segs->cnt = 0; //wipe out
+ BOOL_T safety;
+ int col = 0;
+
+ double prev_e = 0.0;
+ // we do a binary search to find the "good `t` closest to no-longer-good"
+ do {
+ safety=FALSE;
+ // step 1: start with the maximum possible arc length
+ t_e = 1.0;
+ // points:
+ coOrd start_point, mid_point, end_point;
+ // booleans:
+ BOOL_T curr_good = FALSE, prev_good = FALSE, done = FALSE;
+ // numbers:
+ double t_m, step = 0;
+ // step 2: find the best possible arc
+ do { // !done
+ prev_good = curr_good; //remember last time
+ t_m = (t_s + t_e)/2;
+ step++;
+ start_point = getPoint(pos, t_s); //Start of arc
+ mid_point = getPoint(pos, t_m); //Middle of trial arc
+ end_point = getPoint(pos, t_e); //End of trial Arc
+
+ PlotCurve( crvCmdFromChord, start_point, end_point, mid_point,
+ &(arc.curveData), TRUE ); //Find Arc through three points
+
+ arc.start = t_s; //remember start
+ arc.end = t_e; //remember end
+ arc.pos0 = start_point; //remember start point (used for Straight)
+ arc.pos1 = end_point; // Remember end point (used for Straight)
+
+ if (arc.curveData.type == curveTypeStraight) {
+ double error = BezErrorLine(pos,start_point,end_point, t_s, t_e);
+ curr_good = (error <= errorThreshold/2);
+ arc.curveData.a0 = FindAngle(start_point,end_point);
+ arc.curveData.a1 = FindAngle(end_point,start_point);
+
+ } else if (arc.curveData.type == curveTypeNone) {
+ return FALSE; //Something wrong
+ } else {
+ double error = BezError(pos, arc.curveData.curvePos, start_point, t_s, t_e);
+ curr_good = (error <= errorThreshold/2);
+ };
+
+ done = prev_good && !curr_good; //Was better than this last time?
+ if(!done) {
+ // this arc is fine: we can move 'e' up to see if we can find a wider arc
+ if(curr_good) {
+ prev_e = t_e; //remember good end only
+ prev_arc = arc;
+ // if e is already at max, then we're done for this arc.
+ if (t_e >= 1.0) {
+ // make sure we cap at t=1
+ arc.end = prev_e = 1.0;
+ // if we capped the arc segment to t=1 we also need to make sure that
+ // the arc's end angle is correct with respect to the bezier end point.
+ if (t_e > 1.0) {
+ if (arc.curveData.type != curveTypeStraight) {
+ coOrd d;
+ d.x = arc.curveData.curvePos.x + fabs(arc.curveData.curveRadius) * cos(D2R(arc.curveData.a1));
+ d.y = arc.curveData.curvePos.y + fabs(arc.curveData.curveRadius) * sin(D2R(arc.curveData.a1));
+
+ arc.curveData.a1 += FindAngle(d, getPoint(pos,1.0));
+ t_e = 1.0;
+ }
+ }
+ prev_arc = arc;
+ done = TRUE;
+ break;
+ }
+ // if not, move it up by half the iteration distance or to end
+ t_e = t_e + (t_e-t_s)/2;
+ if (t_e > 1.0) t_e = 1.0;
+ }
+ // this is a bad arc: we need to move 'e' down to find a good arc
+ else {
+ t_e = t_m;
+ }
+ } // If !Done end
+ } while(!done && safety++<100);
+ if(safety>=100) {
+ return FALSE; //Failed to make into arcs
+ }
+ prev_arc = prev_arc.end==0.0?arc:prev_arc;
+ trkSeg_t curveSeg; //Now set up tempSeg to copy into array
+ curveSeg.width = track?0:width;
+ if ( prev_arc.curveData.type == curveTypeCurve ) {
+ if (track)
+ curveSeg.color = (fabs(prev_arc.curveData.curveRadius)<(GetLayoutMinTrackRadius()-EPSILON))?wDrawColorRed:wDrawColorBlack;
+ else
+ curveSeg.color = color;
+ curveSeg.type = track?SEG_CRVTRK:SEG_CRVLIN;
+ curveSeg.u.c.a0 = prev_arc.curveData.a0;
+ curveSeg.u.c.a1 = prev_arc.curveData.a1;
+ curveSeg.u.c.center = prev_arc.curveData.curvePos;
+ if (prev_arc.curveData.negative)
+ curveSeg.u.c.radius = -prev_arc.curveData.curveRadius;
+ else
+ curveSeg.u.c.radius = prev_arc.curveData.curveRadius;
+ } else { //Straight Line because all points co-linear
+ curveSeg.type = track?SEG_STRTRK:SEG_STRLIN;
+ if (track)
+ curveSeg.color = wDrawColorBlack;
+ else
+ curveSeg.color = color;
+ curveSeg.u.l.angle = prev_arc.curveData.a1;
+ curveSeg.u.l.pos[0] = prev_arc.pos0;
+ curveSeg.u.l.pos[1] = prev_arc.pos1;
+ curveSeg.u.l.option = 0;
+ }
+ addSegBezier(segs, &curveSeg); //Add to array of segs used
+ t_s = prev_e;
+ col++;
+ } while(prev_e < 1.0);
+
+ return TRUE;
+};
+/*
+ * Draw Bezier while editing it. It consists of three elements - the curve and one or two control arms.
+ *
+ */
+
+EXPORT void DrawBezCurve(trkSeg_p control_arm1,
+ int cp1Segs_cnt,
+ trkSeg_p control_arm2,
+ int cp2Segs_cnt,
+ trkSeg_p curveSegs,
+ int crvSegs_cnt,
+ wDrawColor color
+ ) {
+ long oldDrawOptions = tempD.funcs->options;
+ tempD.funcs->options = wDrawOptTemp;
+ long oldOptions = tempD.options;
+ tempD.options = DC_TICKS;
+ tempD.orig = mainD.orig;
+ tempD.angle = mainD.angle;
+ if (crvSegs_cnt && curveSegs)
+ DrawSegs( &tempD, zero, 0.0, curveSegs, crvSegs_cnt, trackGauge, color );
+ if (cp1Segs_cnt && control_arm1)
+ DrawSegs( &tempD, zero, 0.0, control_arm1, cp1Segs_cnt, trackGauge, drawColorBlack );
+ if (cp2Segs_cnt && control_arm2)
+ DrawSegs( &tempD, zero, 0.0, control_arm2, cp2Segs_cnt, trackGauge, drawColorBlack );
+ tempD.funcs->options = oldDrawOptions;
+ tempD.options = oldOptions;
+
+}
+
+/*
+ * If Track, make it red if the radius is below minimum
+ */
+void DrawTempBezier(BOOL_T track) {
+ if (track) DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt, (trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da_cnt,Da.minRadius<(GetLayoutMinTrackRadius()-EPSILON)?drawColorRed:drawColorBlack);
+ else
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt, (trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da_cnt,drawColorBlack); //Add Second Arm
+}
+
+void CreateBothControlArms(int selectPoint, BOOL_T track) {
+ if (selectPoint == -1) {
+ Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0],
+ Da.pos[1], track, TRUE, Da.trk[0]!=NULL, -1,
+ drawColorBlack);
+ Da.cp2Segs_da_cnt = createControlArm(Da.cp2Segs_da, Da.pos[3],
+ Da.pos[2], track, TRUE, Da.trk[1]!=NULL, -1,
+ drawColorBlack);
+ } else if (selectPoint == 0 || selectPoint == 1) {
+ Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0],
+ Da.pos[1], track, TRUE, Da.trk[0]!=NULL, selectPoint,
+ drawColorBlack);
+ Da.cp2Segs_da_cnt = createControlArm(Da.cp2Segs_da, Da.pos[3],
+ Da.pos[2], track, FALSE, Da.trk[1]!=NULL, -1,
+ drawColorBlack);
+ } else {
+ Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0],
+ Da.pos[1], track, FALSE, Da.trk[0]!=NULL, -1,
+ drawColorBlack);
+ Da.cp2Segs_da_cnt = createControlArm(Da.cp2Segs_da, Da.pos[3],
+ Da.pos[2], track, TRUE, Da.trk[1]!=NULL,
+ 3-selectPoint, drawColorBlack);
+ }
+}
+
+/*
+ * AdjustBezCurve
+ *
+ * Called to adjust the curve either when creating it or modifying it
+ * States are "PICK_POINT" and "POINT_PICKED" and "TRACK_SELECTED".
+ *
+ * In PICK_POINT, the user can select an end-point to drag and release in POINT_PICKED. They can also
+ * hit Enter (which saves the changes) or ESC (which cancels them).
+ *
+ * Only those points which can be picked are shown with circles - locked end-points are not shown.
+ *
+ * SHIFT at release will lock , re-locking any end-points that are aligned with like items at the same position
+ * (Track to unconnected Track, Line to any Line end).
+ *
+ */
+EXPORT STATUS_T AdjustBezCurve(
+ wAction_t action,
+ coOrd pos,
+ BOOL_T track,
+ wDrawColor color,
+ DIST_T width,
+ bezMessageProc message )
+{
+ track_p t;
+ DIST_T d;
+ ANGLE_T angle1, angle2;
+ static coOrd pos0, pos3, p;
+ enum BezierType b;
+ DIST_T dd;
+ EPINX_T ep;
+ double fx, fy, cusp;
+ int controlArm = -1;
+
+
+ if (Da.state != PICK_POINT && Da.state != POINT_PICKED && Da.state != TRACK_SELECTED) return C_CONTINUE;
+
+ switch ( action & 0xFF) {
+
+ case C_START:
+ Da.selectPoint = -1;
+ CreateBothControlArms(Da.selectPoint, track);
+ if (ConvertToArcs(Da.pos,&Da.crvSegs_da,track,color,Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ Da.minRadius = BezierMinRadius(Da.pos,Da.crvSegs_da);
+ Da.unlocked = FALSE;
+ if (track)
+ InfoMessage( _("Select End-Point - Ctrl unlocks end-point") );
+ else
+ InfoMessage( _("Select End-Point") );
+ DrawTempBezier(Da.track);
+ return C_CONTINUE;
+
+ case C_DOWN:
+ if (Da.state != PICK_POINT) return C_CONTINUE;
+ dd = 10000.0;
+ Da.selectPoint = -1;
+ DrawTempBezier(Da.track); //wipe out
+ for (int i=0;i<4;i++) {
+ d = FindDistance(Da.pos[i],pos);
+ if (d < dd) {
+ if (i==0 && Da.trk[0]) continue;
+ if (i==3 && Da.trk[1]) continue; //ignore locked points
+ dd = d;
+ Da.selectPoint = i;
+ }
+
+ }
+ if (!IsClose(dd) ) Da.selectPoint = -1;
+ if (Da.selectPoint == -1) {
+ InfoMessage( _("Not close enough to any valid, selectable point, reselect") );
+ DrawTempBezier(Da.track);
+ return C_CONTINUE;
+ } else {
+ pos = Da.pos[Da.selectPoint];
+ Da.state = POINT_PICKED;
+ InfoMessage( _("Drag point %d to new location and release it"),Da.selectPoint+1 );
+ }
+ CreateBothControlArms(Da.selectPoint, track);
+ if (ConvertToArcs(Da.pos, &Da.crvSegs_da, track, color,Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ Da.minRadius = BezierMinRadius(Da.pos, Da.crvSegs_da);
+ DrawTempBezier(Da.track);
+ return C_CONTINUE;
+
+ case C_MOVE:
+ if (Da.state != POINT_PICKED) {
+ InfoMessage(_("Pick any circle to adjust it - Enter to confirm, ESC to abort"));
+ return C_CONTINUE;
+ }
+ //If locked, reset pos to be on line from other track
+ DrawTempBezier(Da.track); //wipe out
+ if (Da.selectPoint == 1 || Da.selectPoint == 2) { //CPs
+ int controlArm = Da.selectPoint-1; //Snap to direction of track
+ if (Da.trk[controlArm]) {
+ angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk[controlArm], Da.ep[controlArm]));
+ angle2 = NormalizeAngle(FindAngle(pos, Da.pos[Da.selectPoint==1?0:3])-angle1);
+ if (angle2 > 90.0 && angle2 < 270.0)
+ Translate( &pos, Da.pos[Da.selectPoint==1?0:3], angle1, -FindDistance( Da.pos[Da.selectPoint==1?0:3], pos )*cos(D2R(angle2)) );
+ else pos = Da.pos[Da.selectPoint==1?0:3];
+ } // Dont Snap control points
+ } else SnapPos(&pos);
+ Da.pos[Da.selectPoint] = pos;
+ CreateBothControlArms(Da.selectPoint, track);
+ if (ConvertToArcs(Da.pos,&Da.crvSegs_da,track, color, Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ Da.minRadius = BezierMinRadius(Da.pos,Da.crvSegs_da);
+ if (Da.track) {
+ b = AnalyseCurve(Da.pos,&fx,&fy,&cusp);
+ if (b==ENDS) {
+ wBeep();
+ InfoMessage(_("Bezier Curve Invalid has identical end points Change End Point"),b==CUSP?"Cusp":"Loop");
+ } else if ( b == CUSP || b == LOOP) {
+ wBeep();
+ InfoMessage(_("Bezier Curve Invalid has %s Change End Point"),b==CUSP?"Cusp":"Loop");
+ } else if ( b == COINCIDENT ) {
+ wBeep();
+ InfoMessage(_("Bezier Curve Invalid has three co-incident points"),b==CUSP?"Cusp":"Loop");
+ } else if ( b == LINE ) {
+ InfoMessage(_("Bezier is Straight Line"));
+ } else
+ InfoMessage( _("Bezier %s : Min Radius=%s Length=%s fx=%0.3f fy=%0.3f cusp=%0.3f"),track?"Track":"Line",
+ FormatDistance(Da.minRadius>=100000?0:Da.minRadius),
+ FormatDistance(BezierLength(Da.pos,Da.crvSegs_da)),fx,fy,cusp);
+ } else
+ InfoMessage( _("Bezier %s : Min Radius=%s Length=%s"),track?"Track":"Line",
+ FormatDistance(Da.minRadius>=100000?0:Da.minRadius),
+ FormatDistance(BezierLength(Da.pos,Da.crvSegs_da)));
+ DrawTempBezier(Da.track);
+ return C_CONTINUE;
+
+ case C_UP:
+ if (Da.state != POINT_PICKED) return C_CONTINUE;
+ //Take last pos and decide if it should be snapped to a track because SHIFT is held (pos0 and pos3)
+ ep = 0;
+ BOOL_T found = FALSE;
+
+ DrawTempBezier(Da.track); //wipe out
+
+ p = pos;
+
+ if (track && (Da.selectPoint == 0 || Da.selectPoint == 3)) { //EPs
+ if ((MyGetKeyState() & WKEY_SHIFT) != 0) { //Snap Track
+ if ((t = OnTrackIgnore(&p, FALSE, TRUE, Da.selectTrack)) != NULL) { //Snap to endPoint
+ ep = PickUnconnectedEndPointSilent(p, t);
+ if (ep != -1) {
+ Da.trk[Da.selectPoint/3] = t;
+ Da.ep[Da.selectPoint/3] = ep;
+ pos0 = Da.pos[(Da.selectPoint == 0)?1:2];
+ pos = GetTrkEndPos(t, ep);
+ found = TRUE;
+ }
+ } else {
+ wBeep();
+ InfoMessage(_("No unconnected End Point to lock to"));
+ }
+ }
+ }
+ if (found) {
+ angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk[Da.selectPoint/3], Da.ep[Da.selectPoint/3]));
+ angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1);
+ Translate(&Da.pos[Da.selectPoint==0?1:2], Da.pos[Da.selectPoint==0?0:3], angle1, FindDistance(Da.pos[Da.selectPoint==0?1:2],pos)*cos(D2R(angle2)));
+ }
+ Da.selectPoint = -1;
+ CreateBothControlArms(Da.selectPoint,track);
+ if (ConvertToArcs(Da.pos,&Da.crvSegs_da,track,color,Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ Da.minRadius = BezierMinRadius(Da.pos,Da.crvSegs_da);
+ if (Da.track) {
+ b = AnalyseCurve(Da.pos,&fx,&fy,&cusp);
+ if (b==ENDS) {
+ wBeep();
+ InfoMessage(_("Bezier curve invalid has identical end points Change End Point"),b==CUSP?"Cusp":"Loop");
+ } else if ( b == CUSP || b == LOOP) {
+ wBeep();
+ InfoMessage(_("Bezier curve invalid has %s Change End Point"),b==CUSP?"Cusp":"Loop");
+ } else if ( b == COINCIDENT ) {
+ wBeep();
+ InfoMessage(_("Bezier curve invalid has three co-incident points"),b==CUSP?"Cusp":"Loop");
+ } else if ( b == LINE) {
+ InfoMessage(_("Bezier curve is straight line"));
+ }
+ InfoMessage(_("Pick any circle to adjust it - Enter to confirm, ESC to abort"));
+ } else
+ InfoMessage(_("Pick any circle to adjust it - Enter to confirm, ESC to abort"));
+ DrawTempBezier(Da.track);
+ Da.state = PICK_POINT;
+
+ return C_CONTINUE;
+
+ case C_OK: //C_OK is not called by Modify.
+ if ( Da.state == PICK_POINT ) {
+ char c = (unsigned char)(action >> 8);
+ if (Da.track && Da.pos[0].x == Da.pos[3].x && Da.pos[0].y == Da.pos[3].y ) {
+ wBeep();
+ ErrorMessage(_("Invalid Bezier Track - end points are identical"));
+ return C_CONTINUE;
+ }
+ if (Da.track) {
+ b = AnalyseCurve(Da.pos,&fx,&fy,&cusp);
+ if ( b == CUSP || b == LOOP ) {
+ wBeep();
+ ErrorMessage(_("Invalid Bezier Curve has a %s - Adjust"),b==CUSP?"Cusp":"Loop");
+ return C_CONTINUE;
+ } else if (b==COINCIDENT) {
+ wBeep();
+ ErrorMessage(_("Invalid Bezier Curve has three coincident points - Adjust"));
+ return C_CONTINUE;
+ } else if(b==ENDS) {
+ ErrorMessage(_("Invalid Bezier Track - end points are identical"));
+ return C_CONTINUE;
+ }
+ }
+ Da.minRadius = BezierMinRadius(Da.pos,Da.crvSegs_da);
+ DrawTempBezier(Da.track);
+ UndoStart( _("Create Bezier"), "newBezier - CR" );
+ if (Da.track) {
+ t = NewBezierTrack( Da.pos, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt);
+ for (int i=0;i<2;i++)
+ if (Da.trk[i] != NULL) ConnectAbuttingTracks(t,i,Da.trk[i],Da.ep[i]);
+ }
+ else t = NewBezierLine(Da.pos, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt,color,width);
+ UndoEnd();
+ if (Da.crvSegs_da.ptr) MyFree(Da.crvSegs_da.ptr);
+ Da.crvSegs_da.ptr = NULL;
+ Da.crvSegs_da.cnt = 0;
+ Da.crvSegs_da.max = 0;
+ DrawNewTrack(t);
+ Da.state = NONE;
+ MainRedraw();
+ MapRedraw();
+ return C_TERMINATE;
+
+ }
+ return C_CONTINUE;
+
+ case C_REDRAW:
+ DrawTempBezier(Da.track);
+ return C_CONTINUE;
+
+ default:
+ return C_CONTINUE;
+ }
+
+
+}
+
+struct extraData {
+ BezierData_t bezierData;
+ };
+
+/*
+ * CmdBezModify
+ *
+ * Called from Modify Command - this function deals with the real (old) track and calls AdjustBezCurve to tune up the new one
+ * Sequence is this -
+ * - The C_START is called from CmdModify C_DOWN action if a track has being selected. The old track is hidden, the editable one is shown.
+ * - C_MOVES will be ignored until a C_UP ends the track selection and moves the state to PICK_POINT,
+ * - C_DOWN then hides the track and shows the Bezier handles version. Selects a point (if close enough and available) and the state moves to POINT_PICKED
+ * - C_MOVE drags the point around modifying the curve
+ * - C_UP puts the state back to PICK_POINT (pick another)
+ * - C_OK (Enter/Space) creates the new track, deletes the old and shows the changed track.
+ * - C_CANCEL (Esc) sets the state to NONE and reshows the original track unchanged.
+ *
+ * Note: Available points are shown - if a Bezier track is attached to its neighbor, only the control point on that side is selectable.
+ * Any free end-point can be locked to a unconnected end point using SHIFT during drag.
+ */
+STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos) {
+ BOOL_T track = TRUE;
+ track_p t;
+ double width = 1.0;
+ long mode = 0;
+ long cmd;
+
+ struct extraData *xx = GetTrkExtraData(trk);
+ cmd = (long)commandContext;
+
+
+ switch (action&0xFF) {
+ case C_START:
+ Da.state = NONE;
+ DYNARR_RESET(trkSeg_t,Da.crvSegs_da);
+ Da.cp1Segs_da_cnt = 0;
+ Da.cp2Segs_da_cnt = 0;
+ Da.selectPoint = -1;
+ Da.selectTrack = NULL;
+
+ if (IsTrack(trk)) Da.track = TRUE;
+ else Da.track = FALSE;
+
+ Da.selectTrack = trk;
+ Da.trk[0] = GetTrkEndTrk( trk, 0 );
+ if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk);
+ Da.trk[1] = GetTrkEndTrk( trk, 1 );
+ if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk);
+
+ for (int i=0;i<4;i++) Da.pos[i] = xx->bezierData.pos[i]; //Copy parms from old trk
+ InfoMessage(_("%s picked - now select a Point"),track?"Track":"Line");
+ Da.state = TRACK_SELECTED;
+ DrawTrack(Da.selectTrack,&mainD,wDrawColorWhite); //Wipe out real track, draw replacement
+ return AdjustBezCurve(C_START, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage);
+
+ case C_DOWN:
+ if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up
+ return AdjustBezCurve(C_DOWN, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage);
+
+
+ case C_MOVE:
+ if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up and down
+ return AdjustBezCurve(C_MOVE, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage);
+
+ case C_UP:
+ if (Da.state == TRACK_SELECTED) {
+ Da.state = PICK_POINT; //First time up, next time pick a point
+ }
+ return AdjustBezCurve(C_UP, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage); //Run Adjust
+
+ case C_TEXT:
+ if ((action>>8) != 32)
+ return C_CONTINUE;
+ /* no break */
+ case C_OK:
+ if (Da.state != PICK_POINT) { //Too early - abandon
+ InfoMessage(_("No changes made"));
+ Da.state = NONE;
+ return C_CANCEL;
+ }
+ UndoStart( _("Modify Bezier"), "newBezier - CR" );
+ if (Da.track) t = NewBezierTrack( Da.pos, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt);
+ else t = NewBezierLine(Da.pos, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt,xx->bezierData.segsColor,xx->bezierData.segsWidth);
+
+ DeleteTrack(trk, TRUE);
+
+ if (Da.track) {
+ for (int i=0;i<2;i++) { //Attach new track
+ if (Da.trk[i] != NULL && Da.ep[i] != -1) { //Like the old track
+ ConnectAbuttingTracks(t,i,Da.trk[i],Da.ep[i]);
+ }
+ }
+ }
+ UndoEnd();
+ InfoMessage(_("Modify Bezier Complete - select another"));
+ Da.state = NONE;
+ return C_TERMINATE;
+
+ case C_CANCEL:
+ InfoMessage(_("Modify Bezier Cancelled"));
+ Da.state = NONE;
+ MainRedraw();
+ MapRedraw();
+ return C_TERMINATE;
+
+ case C_REDRAW:
+ return AdjustBezCurve(C_REDRAW, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage);
+ }
+
+ return C_CONTINUE;
+
+}
+
+/*
+ * Find length by adding up the underlying segments. The segments can be straights, curves or bezier.
+ */
+DIST_T BezierLength(coOrd pos[4],dynArr_t segs) {
+
+ DIST_T dd = 0.0;
+ if (segs.cnt == 0 ) return dd;
+ for (int i = 0;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ dd += fabs(t.u.c.radius*D2R(t.u.c.a1));
+ } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) {
+ dd +=BezierLength(t.u.b.pos,t.bezSegs);
+ } else if (t.type == SEG_STRLIN || t.type == SEG_STRTRK ) {
+ dd += FindDistance(t.u.l.pos[0],t.u.l.pos[1]);
+ }
+ }
+ return dd;
+}
+
+DIST_T BezierMinRadius(coOrd pos[4],dynArr_t segs) {
+ DIST_T r = 100000.0, rr;
+ if (segs.cnt == 0 ) return r;
+ for (int i = 0;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ rr = fabs(t.u.c.radius);
+ } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) {
+ rr = BezierMinRadius(t.u.b.pos, t.bezSegs);
+ } else rr = 100000.00;
+ if (rr<r) r = rr;
+ }
+ return r;
+}
+
+/*
+ * Create a Bezier Curve (Track or Line)
+ * Sequence is
+ * 1. Place 1st End (snapping if needed)
+ * 2.Drag out 1st Control Arm (in one direction if snapped)
+ * 3.Place 2nd End (again snapping)
+ * 4.Drag out 2nd Control Arm (constrained if snapped)
+ * 5 to n. Select and drag around points until done
+ * n+1. Confirm with enter or Cancel with Esc
+ */
+STATUS_T CmdBezCurve( wAction_t action, coOrd pos )
+{
+ track_p t;
+ static int segCnt;
+ STATUS_T rc = C_CONTINUE;
+ long curveMode = 0;
+ long cmd;
+ if (action>>8) {
+ cmd = action>>8;
+ } else cmd = (long)commandContext;
+
+ Da.color = lineColor;
+ Da.width = (double)lineWidth/mainD.dpi;
+
+ switch (action&0xFF) {
+
+ case C_START:
+
+ Da.track = (cmd == bezCmdModifyTrack || cmd == bezCmdCreateTrack)?TRUE:FALSE;
+
+ Da.state = POS_1;
+ Da. selectPoint = -1;
+ for (int i=0;i<4;i++) {
+ Da.pos[i] = zero;
+ }
+ Da.trk[0] = Da.trk[1] = NULL;
+ //tempD.orig = mainD.orig;
+
+ DYNARR_RESET(trkSeg_t,Da.crvSegs_da);
+ Da.cp1Segs_da_cnt = 0;
+ Da.cp2Segs_da_cnt = 0;
+ InfoMessage( _("Place 1st end point of Bezier + Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" );
+ return C_CONTINUE;
+
+
+ case C_DOWN:
+ if ( Da.state == POS_1 || Da.state == POS_2) { //Set the first or third point
+ coOrd p = pos;
+ BOOL_T found = FALSE;
+ int end = Da.state==POS_1?0:1;
+ EPINX_T ep;
+ if (Da.track) {
+ if ((MyGetKeyState() & WKEY_SHIFT) != 0) { //Snap Track
+ if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
+ ep = PickUnconnectedEndPointSilent(p, t);
+ if (ep != -1) {
+ Da.trk[end] = t;
+ Da.ep[end] = ep;
+ pos = GetTrkEndPos(t, ep);
+ found = TRUE;
+ }
+ }
+ if (!found) {
+ wBeep();
+ InfoMessage(_("Shift used, but no Unconnected Track End there"));
+ return C_CONTINUE;
+ }
+ }
+ } else { //Snap Bez Line to Lines
+ if ((MyGetKeyState() & WKEY_SHIFT) != 0) {
+ if ((t = OnTrack(&p,FALSE, FALSE)) != NULL) {
+ if (GetClosestEndPt(t,&p)) {
+ pos = p;
+ found = TRUE;
+ }
+ } else {
+ wBeep();
+ InfoMessage(_("Shift used, but no Line End there"));
+ return C_CONTINUE;
+ }
+ }
+ }
+ if (!found) SnapPos( &pos );
+ if (Da.state == POS_1) {
+ Da.pos[0] = pos;
+ Da.pos[1] = pos;
+ Da.state = CONTROL_ARM_1; //Draw the first control arm
+ Da.selectPoint = 1;
+ InfoMessage( _("Drag end of first Control Arm") );
+ Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0], Da.pos[1], Da.track,TRUE,Da.trk[1]!=NULL,1,wDrawColorBlack);
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack);
+ } else {
+ Da.pos[3] = pos; //2nd End Point
+ Da.pos[2] = pos; //2nd Ctl Point
+ Da.state = POINT_PICKED; // Drag out the second control arm
+ Da.selectPoint = 2;
+ InfoMessage( _("Drag end of second Control Arm") );
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack); //Wipe out initial Arm
+ Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0], Da.pos[1], Da.track,FALSE,Da.trk[0]!=NULL,-1,wDrawColorBlack);
+ Da.cp2Segs_da_cnt = createControlArm(Da.cp2Segs_da, Da.pos[3], Da.pos[2], Da.track,TRUE,Da.trk[1]!=NULL,1,wDrawColorBlack);
+ if (ConvertToArcs(Da.pos,&Da.crvSegs_da,Da.track,Da.color,Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ DrawTempBezier(Da.track);
+ }
+ return C_CONTINUE;
+ } else {
+ return AdjustBezCurve( action&0xFF, pos, Da.track, Da.color, Da.width, InfoMessage );
+ }
+ return C_CONTINUE;
+
+ case C_MOVE:
+ if (Da.state == POS_1) {
+ InfoMessage( _("Place 1st end point of Bezier + Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" );
+ return C_CONTINUE;
+ }
+ if (Da.state == POS_2) {
+ InfoMessage( _("Select other end of Bezier, +Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" );
+ }
+ if (Da.state == CONTROL_ARM_1 ) {
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack);
+ if (Da.trk[0]) {
+ EPINX_T ep = 0;
+ ANGLE_T angle1,angle2;
+ angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk[0],Da.ep[0]));
+ angle2 = NormalizeAngle(FindAngle(pos, Da.pos[0])-angle1);
+ if (angle2 > 90.0 && angle2 < 270.0)
+ Translate( &pos, Da.pos[0], angle1, -FindDistance( Da.pos[0], pos )*cos(D2R(angle2)));
+ else pos = Da.pos[0];
+ } // Don't Snap control points
+ Da.pos[1] = pos;
+ Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0], Da.pos[1], Da.track, TRUE, Da.trk[0]!=NULL, 1, wDrawColorBlack);
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack);
+ } else {
+ return AdjustBezCurve( action&0xFF, pos, Da.track, Da.color, Da.width, InfoMessage );
+ }
+ return C_CONTINUE;
+
+ case C_UP:
+ if (Da.state == CONTROL_ARM_1) {
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack);
+ if (Da.trk[0]) {
+ EPINX_T ep = Da.ep[0];
+ ANGLE_T angle1,angle2;
+ angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk[0],Da.ep[0]));
+ angle2 = NormalizeAngle(FindAngle(pos, Da.pos[0])-angle1);
+ if (angle2 > 90.0 && angle2 < 270.0)
+ Translate( &pos, Da.pos[0], angle1, -FindDistance( Da.pos[0], pos )*cos(D2R(angle2)));
+ else pos = Da.pos[0];
+ } // Don't Snap control points
+ Da.pos[1] = pos;
+ if (FindDistance(Da.pos[0],Da.pos[1]) <=minLength) {
+ InfoMessage( _("Control Arm 1 is too short, try again") );
+ Da.state = POS_1;
+ return C_CONTINUE;
+ }
+ Da.state = POS_2;
+ InfoMessage( _("Select other end of Bezier, +Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" );
+ Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0], Da.pos[1], Da.track, FALSE, Da.trk[0]!=NULL, -1, wDrawColorBlack);
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack);
+ return C_CONTINUE;
+ } else {
+ return AdjustBezCurve( action&0xFF, pos, Da.track, Da.color, Da.width, InfoMessage );
+ }
+ case C_TEXT:
+ if (Da.state != PICK_POINT || (action>>8) != ' ') //Space is same as Enter.
+ return C_CONTINUE;
+ /* no break */
+ case C_OK:
+ if (Da.state != PICK_POINT) return C_CONTINUE;
+ return AdjustBezCurve( C_OK, pos, Da.track, Da.color, Da.width, InfoMessage);
+
+ case C_REDRAW:
+ if ( Da.state != NONE ) {
+
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, Da.color);
+ }
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ if (Da.state != NONE) {
+ DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, Da.color);
+ Da.cp1Segs_da_cnt = 0;
+ Da.cp2Segs_da_cnt = 0;
+ Da.crvSegs_da_cnt = 0;
+ for (int i=0;i<2;i++) {
+ Da.trk[i] = NULL;
+ Da.ep[i] = -1;
+ }
+ if (Da.crvSegs_da.ptr) MyFree(Da.crvSegs_da.ptr);
+ Da.crvSegs_da.ptr = NULL;
+ Da.crvSegs_da.cnt = 0;
+ Da.crvSegs_da.max = 0;
+ }
+ Da.state = NONE;
+ return C_CONTINUE;
+
+ default:
+
+ return C_CONTINUE;
+ }
+
+}
+
+void UpdateParms(wDrawColor color,long width) {
+ DrawTempBezier(Da.track);
+ Da.color = lineColor;
+ Da.width = (double)lineWidth/mainD.dpi;
+ if (Da.crvSegs_da.cnt) {
+ ConvertToArcs(Da.pos,&Da.crvSegs_da,Da.track,Da.color,Da.width);
+ }
+ DrawTempBezier(Da.track);
+}
+
+
+#include "bitmaps/bezier.xpm"
+#include "bitmaps/dbezier.xpm"
+
+EXPORT void InitCmdBezier( wMenu_p menu )
+{
+
+}
diff --git a/app/bin/cbezier.h b/app/bin/cbezier.h
new file mode 100644
index 0000000..8a8a8b0
--- /dev/null
+++ b/app/bin/cbezier.h
@@ -0,0 +1,53 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cbezier.h,v 1.1 2005-12-07 15:47:36 rc-flyer Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "common.h"
+#include "wlib.h"
+#include "utility.h"
+
+
+dynArr_t tempEndPts_da;
+#define BezSegs(N) DYNARR_N( trkEndPt_t, tempEndPts_da, N )
+
+#define bezCmdNone (0)
+#define bezCmdModifyTrack (1)
+#define bezCmdModifyLine (2)
+#define bezCmdCreateTrack (3)
+#define bezCmdCreateLine (4)
+
+extern wDrawColor lineColor;
+extern long lineWidth;
+
+typedef void (*bezMessageProc)( char *, ... );
+STATUS_T CmdBezCurve( wAction_t, coOrd);
+STATUS_T CmdBezModify(track_p, wAction_t, coOrd);
+
+STATUS_T CreateBezier( wAction_t, coOrd, BOOL_T, wDrawColor, DIST_T, long, bezMessageProc );
+DIST_T BezierDescriptionDistance( coOrd, track_p );
+STATUS_T BezierDescriptionMove( track_p, wAction_t, coOrd );
+BOOL_T GetBezierMiddle( track_p, coOrd * );
+BOOL_T ConvertToArcs (coOrd[4], dynArr_t *, BOOL_T, wDrawColor, DIST_T);
+track_p NewBezierTrack(coOrd[4], trkSeg_t *, int);
+double BezierLength(coOrd[4], dynArr_t);
+double BezierMinRadius(coOrd[4],dynArr_t);
+void UpdateParms(wDrawColor color,long width);
+
diff --git a/app/bin/cblock.c b/app/bin/cblock.c
index 3c627e9..b1b14a8 100644
--- a/app/bin/cblock.c
+++ b/app/bin/cblock.c
@@ -47,10 +47,19 @@
*/
#include <ctype.h>
-#include "track.h"
-#include "trackx.h"
+#include <stdlib.h>
+#include <string.h>
+
#include "compound.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "trackx.h"
+#include "utility.h"
EXPORT TRKTYP_T T_BLOCK = -1;
@@ -151,8 +160,8 @@ static descData_t blockDesc[] = {
/*NM*/ { DESC_STRING, N_("Name"), &blockData.name },
/*SC*/ { DESC_STRING, N_("Script"), &blockData.script },
/*LN*/ { DESC_DIM, N_("Length"), &blockData.length },
-/*E0*/ { DESC_POS, N_("End Pt 1: X"), &blockData.endPt[0] },
-/*E1*/ { DESC_POS, N_("End Pt 2: X"), &blockData.endPt[1] },
+/*E0*/ { DESC_POS, N_("End Pt 1: X,Y"), &blockData.endPt[0] },
+/*E1*/ { DESC_POS, N_("End Pt 2: X,Y"), &blockData.endPt[1] },
{ DESC_NULL } };
static void UpdateBlock (track_p trk, int inx, descData_p descUpd, BOOL_T needUndoStart )
@@ -196,12 +205,18 @@ static DIST_T DistanceBlock (track_p t, coOrd * p )
blockData_p xx = GetblockData(t);
DIST_T closest, current;
int iTrk = 1;
-
- closest = GetTrkDistance ((&(xx->trackList))[0].t, *p);
+ coOrd pos = *p;
+ closest = GetTrkDistance ((&(xx->trackList))[0].t, &pos);
+ coOrd best_pos = pos;
for (; iTrk < xx->numTracks; iTrk++) {
- current = GetTrkDistance ((&(xx->trackList))[iTrk].t, *p);
- if (current < closest) closest = current;
+ pos = *p;
+ current = GetTrkDistance ((&(xx->trackList))[iTrk].t, &pos);
+ if (current < closest) {
+ closest = current;
+ best_pos = pos;
+ }
}
+ *p = best_pos;
return closest;
}
diff --git a/app/bin/ccontrol.c b/app/bin/ccontrol.c
index 9428e1a..8ff0396 100644
--- a/app/bin/ccontrol.c
+++ b/app/bin/ccontrol.c
@@ -47,10 +47,18 @@
static const char rcsid[] = "@(#) : $Id$";
#include <ctype.h>
-#include "track.h"
-#include "trackx.h"
+#include <string.h>
+
#include "compound.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "layout.h"
+#include "param.h"
+#include "track.h"
+#include "trackx.h"
+#include "utility.h"
EXPORT TRKTYP_T T_CONTROL = -1;
@@ -476,21 +484,18 @@ static STATUS_T CmdControl ( wAction_t action, coOrd pos )
InfoMessage(_("Place control"));
return C_CONTINUE;
case C_DOWN:
- SnapPos(&pos);
- DDrawControl( &tempD, pos, GetScaleRatio(curScaleInx), wDrawColorBlack );
- return C_CONTINUE;
- case C_MOVE:
- SnapPos(&pos);
- DDrawControl( &tempD, pos, GetScaleRatio(curScaleInx), wDrawColorBlack );
+ case C_MOVE:
+ SnapPos(&pos);
+ DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
return C_CONTINUE;
case C_UP:
SnapPos(&pos);
- DDrawControl( &tempD, pos, GetScaleRatio(curScaleInx), wDrawColorBlack );
+ DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
CreateNewControl(pos);
return C_TERMINATE;
case C_REDRAW:
case C_CANCEL:
- DDrawControl( &tempD, pos, GetScaleRatio(curScaleInx), wDrawColorBlack );
+ DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
return C_CONTINUE;
default:
return C_CONTINUE;
diff --git a/app/bin/ccornu.c b/app/bin/ccornu.c
new file mode 100644
index 0000000..b67d245
--- /dev/null
+++ b/app/bin/ccornu.c
@@ -0,0 +1,1240 @@
+/** \file ccornu.c
+ * Cornu Command. Draw or modify a Cornu Easement Track.
+ */
+/* XTrkCad - Model Railroad CAD
+ *
+ * Cornu curves are a family of mathematically defined curves that define spirals that Euler spirals and elastica come from.
+ *
+ * They have the useful property for us that curvature increases linearly along the curve which
+ * means the acceleration towards the center of the curve also increases evenly. Railways have long understood that
+ * smoothly changing the radius is key to passenger comfort and reduced derailments. The railway versions of these
+ * curves were called variously called easements, Talbot or Euler spirals.
+ *
+ * In XTrackCAD often want to change radius smoothly between two tracks whose end position, angle and curvature are known.
+ *
+ * Finding the right part(s) of the Cornu to fit the gap (if one is available) is mathematically complex,
+ * but fortunately Raph Levien published a PhD thesis on this together with his mathematical libraries as
+ * open source. He was doing work on font design where the Cornu shapes make beautiful smooth fonts. He
+ * was faced with the reality, though, that graphics packages do not include these shapes as native objects
+ * and so his solution was to produce a set of Bezier curves that approximate the solution.
+ *
+ * We already have a tool that can produce a set of arcs and straight line to approximate a Bezier - so that in the end
+ * for an easement track we will have an array of Bezier, each of which is an array of Arcs and Lines. The tool will
+ * use the approximations for most of its work.
+ *
+ * The inputs for the Cornu are the end points, angles and radii. To match the Cornu algorithm's expectations we input
+ * these as a set of knots (points on lines). One point is always the desired end point and the other two are picked
+ * direct the code to derive the other two end conditions. By specifying that the desired end point is a "one-way"
+ * knot we ensure that the result has smooth ends of either zero or fixed radius.
+ *
+ * When reading back the output, we simply ignore the results before the first end point knot and after the last.
+ *
+ * Because we are mathematically deriving the output, we can alter the end conditions and recalculate. This allows
+ * support of modify for Cornu Easements and also movement of tracks that are connected via a Cornu easement to another track.
+ *
+ * Note that unlike the existing Easements in XTrkCAD, the degree of sharpness (the rate of change of curvature)
+ * is derived not defined. By adjusting the ends, one can have an infinite set of sharpness solutions.
+ *
+ * Cornu will not find a solution for every set of input conditions, or may propose one that is impractical such as
+ * huge loops or tiny curves. These are mathematically correct, but not useful. In these cases the answer is to change the
+ * end conditions (more space between the ends, different angles or different radii).
+ *
+ * Note that every time we change the Cornu end points we have to recalculate the Bezier approximation,
+ * which recalculates the arc approximations, but that still means that the majority of the time we are using the approximation.
+ *
+ * Cornus do not have cusps, but can result in smooth loops. If there is too much looping, the code will reject the easement.
+ *
+ * This program is built and founded upon Raph Levien's seminal work and relies on an adaptation of his Cornu library.
+ * As with the Bezier work, it also relies on the pages about Bezier curves that PoMax put up at https://pomax.github.io/bezierinfo
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include "track.h"
+#include "spiro.h"
+#include "spiroentrypoints.h"
+#include "bezctx_xtrkcad.h"
+#include "draw.h"
+#include "ccurve.h"
+#include "ccornu.h"
+#include "tcornu.h"
+#include "cstraigh.h"
+#include "drawgeom.h"
+#include "cjoin.h"
+#include "i18n.h"
+#include "common.h"
+#include "utility.h"
+#include "math.h"
+#include "param.h"
+#include "layout.h"
+#include "cundo.h"
+#include "messages.h"
+#include "cselect.h"
+
+extern drawCmd_t tempD;
+extern TRKTYP_T T_BEZIER;
+extern TRKTYP_T T_CORNU;
+
+
+/*
+ * STATE INFO
+ */
+enum Cornu_States { NONE,
+ POS_1,
+ LOC_2,
+ POS_2,
+ PICK_POINT,
+ POINT_PICKED,
+ TRACK_SELECTED };
+
+static struct {
+ enum Cornu_States state;
+ coOrd pos[2];
+ int selectPoint;
+ wDrawColor color;
+ DIST_T width;
+ track_p trk[2];
+ EPINX_T ep[2];
+ DIST_T radius[2];
+ ANGLE_T angle[2];
+ ANGLE_T arcA0[2];
+ ANGLE_T arcA1[2];
+ coOrd center[2];
+ curveType_e trackType[2];
+
+ BOOL_T extend[2];
+ trkSeg_t extendSeg[2];
+
+ trkSeg_t ep1Segs[2];
+ int ep1Segs_da_cnt;
+ trkSeg_t ep2Segs[2];
+ int ep2Segs_da_cnt;
+ dynArr_t crvSegs_da;
+ int crvSegs_da_cnt;
+ trkSeg_t trk1Seg;
+ trkSeg_t trk2Seg;
+ track_p selectTrack;
+ DIST_T minRadius;
+ BOOL_T circleorHelix[2];
+
+ bezctx * bezc;
+ } Da;
+
+
+
+/**
+ * Draw a EndPoint.
+ * A Cornu end Point has a filled circle surrounded by another circle for endpoint
+ */
+int createEndPoint(
+ trkSeg_t sp[], //seg pointer for up to 2 trkSegs (ends and line)
+ coOrd pos0, //end on curve
+ BOOL_T point_selected,
+ BOOL_T point_selectable,
+ BOOL_T track_modifyable
+ )
+{
+ DIST_T d, w;
+ d = tempD.scale*0.25;
+ w = tempD.scale/tempD.dpi; /*double width*/
+ sp[0].u.c.center = pos0;
+ sp[0].u.c.a0 = 0.0;
+ sp[0].u.c.a1 = 360.0;
+ sp[0].width = w;
+ sp[0].u.c.radius = d/4;
+ sp[0].color = (point_selected>=0)?drawColorRed:drawColorBlack;
+ if (track_modifyable)
+ sp[0].type = SEG_CRVLIN;
+ else
+ sp[0].type = SEG_FILCRCL;
+ if (point_selectable) {
+ sp[1].u.c.center = pos0;
+ sp[1].u.c.a0 = 0.0;
+ sp[1].u.c.a1 = 360.0;
+ sp[1].u.c.radius = d/2;
+ sp[1].type = SEG_CRVLIN;
+ sp[1].width = w;
+ sp[1].color = drawColorRed;
+ return 2;
+ }
+ return 1;
+}
+
+
+/*
+ * Add element to DYNARR pointed to by caller from segment handed in
+ */
+void addSegCornu(dynArr_t * const array_p, trkSeg_p seg) {
+ trkSeg_p s;
+
+
+ DYNARR_APPEND(trkSeg_t, * array_p, 10); //Adds 1 to cnt
+ s = &DYNARR_N(trkSeg_t,* array_p,array_p->cnt-1);
+ s->type = seg->type;
+ s->bezSegs.max = 0;
+ s->bezSegs.cnt = 0;
+ if (s->bezSegs.ptr) MyFree(s->bezSegs.ptr);
+ s->bezSegs.ptr = NULL;
+ s->color = seg->color;
+ s->width = seg->width;
+ if ((s->type == SEG_BEZLIN || s->type == SEG_BEZTRK) && seg->bezSegs.cnt) {
+ s->u.b.angle0 = seg->u.b.angle0; //Copy all the rest
+ s->u.b.angle3 = seg->u.b.angle3;
+ s->u.b.length = seg->u.b.length;
+ s->u.b.minRadius = seg->u.b.minRadius;
+ for (int i=0;i<4;i++) s->u.b.pos[i] = seg->u.b.pos[i];
+ s->u.b.radius0 = seg->u.b.radius3;
+ for (int i = 0; i<seg->bezSegs.cnt; i++) {
+ addSegCornu(&s->bezSegs, (((trkSeg_p)seg->bezSegs.ptr) + i)); //recurse for copying embedded Beziers as in Cornu joint
+ }
+ } else {
+ s->u = seg->u;
+ }
+}
+EXPORT void SetKnots(spiro_cp knots[6], coOrd posk[6]) {
+ for (int i = 0; i < 6; i++) {
+ knots[i].x = posk[i].x;
+ knots[i].y = posk[i].y;
+ }
+ knots[0].ty = SPIRO_OPEN_CONTOUR;
+ knots[1].ty = SPIRO_G2;
+ knots[2].ty = SPIRO_RIGHT;
+ knots[3].ty = SPIRO_LEFT;
+ knots[4].ty = SPIRO_G2;
+ knots[5].ty = SPIRO_END_OPEN_CONTOUR;
+}
+
+BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p, BOOL_T spots) {
+ array_p->cnt = 0;
+ //Create LH knots
+ //Find remote end point of track, create start knot
+ int ends[2];
+ ends[0] = 2; ends[1] = 3;
+ spiro_cp knots[6];
+ coOrd posk[6];
+ BOOL_T back;
+ ANGLE_T angle1;
+
+ if (Da.bezc) free(Da.bezc);
+
+ Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots);
+
+ coOrd pos0 = pos[0];
+
+ if (radius[0] == 0.0) {
+ Translate(&posk[0],pos0,angle[0],10);
+ Translate(&posk[1],pos0,angle[0],5);
+ } else {
+ angle1 = FindAngle(center[0],pos[0]);
+ if (NormalizeAngle(angle1 - angle[0])<180) back = TRUE;
+ else back = FALSE;
+ posk[0] = pos[0];
+ Rotate(&posk[0],center[0],(back)?-10:10);
+ posk[1] = pos[0];
+ Rotate(&posk[1],center[0],(back)?-5:5);
+ }
+ posk[2] = pos[0];
+
+ posk[3] = pos[1];
+
+ coOrd pos1 = pos[1];
+
+ if (radius[1] == 0.0 ) {
+ Translate(&posk[4],pos1,angle[1],5);
+ Translate(&posk[5],pos1,angle[1],10);
+ } else {
+ angle1 = FindAngle(center[1],pos[1]);
+ if (NormalizeAngle(angle1 - angle[1])>180) back = TRUE;
+ else back = FALSE;
+ posk[4] = pos[1];
+ Rotate(&posk[4],center[1],(back)?5:-5);
+ posk[5] = pos[1];
+ Rotate(&posk[5],center[1],(back)?10:-10);
+ }
+ SetKnots(knots,posk);
+ TaggedSpiroCPsToBezier(knots,Da.bezc);
+ if (!bezctx_xtrkcad_close(Da.bezc)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Set up the call to Cornu0. Take the conditions of the two ends from the connected tracks.
+ */
+BOOL_T CallCornu(coOrd pos[2], track_p trk[2], EPINX_T ep[2], dynArr_t * array_p, cornuParm_t * cp) {
+
+ trackParams_t params;
+ ANGLE_T angle;
+ for (int i=0;i<2;i++) {
+ if (trk[i]) {
+ if (!GetTrackParams(PARAMS_CORNU,trk[i],pos[i],&params)) return FALSE;
+ cp->pos[i] = pos[i];
+ if (Da.ep[i]>=0) angle = GetTrkEndAngle(trk[i],ep[i]);
+ else angle = params.angle; //Turntable only
+ if (Da.circleorHelix[i]) { //Helix/Circle only
+ cp->radius[i] = params.arcR;
+ cp->center[i] = params.arcP;
+ cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
+ } else if (params.type == curveTypeStraight) {
+ cp->angle[i] = NormalizeAngle(angle+180); //Because end always backwards
+ cp->radius[i] = 0.0;
+ } else if ((params.type == curveTypeCornu || params.type == curveTypeBezier) && params.arcR == 0.0 ) {
+ cp->radius[i] = 0.0;
+ cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); //Use point not end
+ } else if (params.type == curveTypeCurve) {
+ cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
+ cp->radius[i] = params.arcR;
+ cp->center[i] = params.arcP;
+ } else if ((params.type == curveTypeCornu || params.type == curveTypeBezier) && params.arcR != 0.0 ){
+ cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
+ cp->radius[i] = params.arcR;
+ cp->center[i] = params.arcP;
+ } else {
+ cp->angle[i] = NormalizeAngle(angle+180); //Unknown - treat like straight
+ cp->radius[i] = params.arcR;
+ cp->center[i] = params.arcP;
+ }
+ }
+ }
+
+ return CallCornu0(pos,cp->center,cp->angle,cp->radius,array_p,TRUE);
+}
+
+
+/*
+ * Draw Cornu while editing it. It consists of up to five elements - the ends, the curve and one or two End Points.
+ *
+ */
+
+EXPORT void DrawCornuCurve(
+ trkSeg_p first_trk,
+ trkSeg_p point1,
+ int ep1Segs_cnt,
+ trkSeg_p curveSegs,
+ int crvSegs_cnt,
+ trkSeg_p point2,
+ int ep2Segs_cnt,
+ trkSeg_p second_trk,
+ trkSeg_p extend1_trk,
+ trkSeg_p extend2_trk,
+ wDrawColor color
+ ) {
+ long oldDrawOptions = tempD.funcs->options;
+ tempD.funcs->options = wDrawOptTemp;
+ long oldOptions = tempD.options;
+ tempD.options = DC_TICKS;
+ tempD.orig = mainD.orig;
+ tempD.angle = mainD.angle;
+ if (first_trk)
+ DrawSegs( &tempD, zero, 0.0, first_trk, 1, trackGauge, drawColorBlack );
+ if (crvSegs_cnt && curveSegs)
+ DrawSegs( &tempD, zero, 0.0, curveSegs, crvSegs_cnt, trackGauge, color );
+ if (second_trk)
+ DrawSegs( &tempD, zero, 0.0, second_trk, 1, trackGauge, drawColorBlack );
+ if (ep1Segs_cnt && point1)
+ DrawSegs( &tempD, zero, 0.0, point1, ep1Segs_cnt, trackGauge, drawColorBlack );
+ if (ep2Segs_cnt && point2)
+ DrawSegs( &tempD, zero, 0.0, point2, ep2Segs_cnt, trackGauge, drawColorBlack );
+ if (extend1_trk)
+ DrawSegs( &tempD, zero, 0.0, extend1_trk, 1, trackGauge, drawColorBlack);
+ if (extend2_trk)
+ DrawSegs( &tempD, zero, 0.0, extend2_trk, 1, trackGauge, drawColorBlack);
+ tempD.funcs->options = oldDrawOptions;
+ tempD.options = oldOptions;
+
+}
+
+/*
+ * If Track, make it red if the radius is below minimum
+ */
+void DrawTempCornu() {
+
+
+ DrawCornuCurve(&Da.trk1Seg,
+ &Da.ep1Segs[0],Da.ep1Segs_da_cnt,
+ (trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da_cnt,
+ &Da.ep2Segs[0],Da.ep2Segs_da_cnt,
+ &Da.trk2Seg,
+ Da.extend[0]?&Da.extendSeg[0]:NULL,
+ Da.extend[1]?&Da.extendSeg[1]:NULL,
+ Da.minRadius<(GetLayoutMinTrackRadius()-EPSILON)?drawColorRed:drawColorBlack);
+
+}
+
+void CreateBothEnds(int selectPoint) {
+ BOOL_T selectable[2],modifyable[2];
+ selectable[0] = Da.trk[0] && !QueryTrack(Da.trk[0],Q_IS_CORNU);
+ modifyable[0] = Da.trk[0] && QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY);
+ selectable[1] = Da.trk[1] && !QueryTrack(Da.trk[1],Q_IS_CORNU);
+ modifyable[1] = Da.trk[1] && QueryTrack(Da.trk[1],Q_CORNU_CAN_MODIFY);
+ if (selectPoint == -1) {
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0]);
+ Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1]);
+ } else if (selectPoint == 0 || selectPoint == 1) {
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],selectPoint == 0,selectable[0],modifyable[0]);
+ Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],selectPoint == 1,selectable[1],modifyable[1]);
+ } else {
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0]);
+ Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1]);
+ }
+}
+
+BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track_end) {
+ trackParams_t trackParams;
+ if (!GetTrackParams(PARAMS_CORNU, t, pos, &trackParams)) return FALSE;
+ Da.radius[end] = 0.0;
+ Da.center[end] = zero;
+ Da.circleorHelix[end] = FALSE;
+ Da.trackType[end] = trackParams.type;
+ if (trackParams.type == curveTypeCurve) {
+ Da.arcA0[end] = trackParams.arcA0;
+ Da.arcA1[end] = trackParams.arcA1;
+ Da.radius[end] = trackParams.arcR;
+ Da.center[end] = trackParams.arcP;
+ if (trackParams.circleOrHelix) {
+ Da.circleorHelix[end] = TRUE;
+ Da.angle[end] = trackParams.track_angle; //For Now
+ } else {
+ Da.angle[end] = NormalizeAngle(trackParams.track_angle + (track_end?180:0));
+ }
+ } else if (trackParams.type == curveTypeBezier) {
+ Da.angle[end] = NormalizeAngle(trackParams.track_angle+(track_end?180:0));
+ if (trackParams.arcR == 0) {
+ Da.radius[end] = 0;
+ Da.center[end] = zero;
+ } else {
+ Da.arcA0[end] = trackParams.arcA0;
+ Da.arcA1[end] = trackParams.arcA1;
+ Da.radius[end] = trackParams.arcR;
+ Da.center[end] = trackParams.arcP;
+ }
+ } else if (trackParams.type == curveTypeCornu) {
+ int ep = trackParams.ep;
+ Da.angle[end] = NormalizeAngle(trackParams.cornuAngle[ep]+(track_end?180:0));
+ Da.radius[end] = trackParams.cornuRadius[ep];
+ Da.pos[end] = trackParams.cornuEnd[ep];
+ Da.center[end] = trackParams.cornuCenter[ep];
+ } else if (trackParams.type == curveTypeStraight) {
+ if (Da.ep[end]>=0)
+ Da.angle[end] = NormalizeAngle(GetTrkEndAngle(t,track_end)+180); //Ignore params.angle because it gives from nearest end
+ else {
+ Da.angle[end] = NormalizeAngle(trackParams.angle+180); //Turntable
+ Da.pos[end] = trackParams.lineEnd; //End moved to constrain angle
+ }
+ }
+ return TRUE;
+}
+
+void CorrectHelixAngles() {
+ if ( Da.circleorHelix[0] ) {
+ Da.ep[0] = PickArcEndPt( Da.center[0], Da.pos[0], Da.pos[1] );
+ if (Da.ep[0] == 1) Da.angle[0] = NormalizeAngle(Da.angle[0]+180);
+ }
+ if ( Da.circleorHelix[1] ) {
+ Da.ep[1] = PickArcEndPt( Da.center[1], Da.pos[1], Da.pos[0] );
+ if (Da.ep[1] == 1) Da.angle[1] = NormalizeAngle(Da.angle[1]+180);
+ }
+}
+
+BOOL_T CheckHelix(track_p trk) {
+ if ( Da.trk[0] && QueryTrack(Da.trk[0],Q_HAS_VARIABLE_ENDPOINTS)) {
+ track_p t = GetTrkEndTrk(Da.trk[0],Da.ep[0]);
+ if ( t != NULL && t != trk) {
+ ErrorMessage( MSG_TRK_ALREADY_CONN, _("First") );
+ return FALSE;
+ }
+ }
+ if ( Da.trk[1] && QueryTrack(Da.trk[1],Q_HAS_VARIABLE_ENDPOINTS)) {
+ track_p t = GetTrkEndTrk(Da.trk[1],Da.ep[1]);
+ if ( t != NULL && t != trk) {
+ ErrorMessage( MSG_TRK_ALREADY_CONN, _("Second") );
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void SetUpCornuParms(cornuParm_t * cp) {
+ cp->center[0] = Da.center[0];
+ cp->angle[0] = Da.angle[0];
+ cp->radius[0] = Da.radius[0];
+ cp->center[1] = Da.center[1];
+ cp->angle[1] = Da.angle[1];
+ cp->radius[1] = Da.radius[1];
+}
+
+/*
+ * AdjustCornuCurve
+ *
+ * Called to adjust the curve either when creating it or modifying it
+ * States are "PICK_POINT" and "POINT_PICKED" and "TRACK_SELECTED".
+ *
+ * In PICK_POINT, the user can select an end-point to drag and release in POINT_PICKED. They can also
+ * hit Enter (which saves the changes) or ESC (which cancels them).
+ *
+ * Deal with extended tracks from ends.
+ *
+ */
+EXPORT STATUS_T AdjustCornuCurve(
+ wAction_t action,
+ coOrd pos,
+ cornuMessageProc message )
+{
+ track_p t;
+ DIST_T d;
+ ANGLE_T a, a2;
+ DIST_T dd;
+ EPINX_T ep;
+ cornuParm_t cp;
+
+
+ if (Da.state != PICK_POINT && Da.state != POINT_PICKED && Da.state != TRACK_SELECTED) return C_CONTINUE;
+
+ switch ( action & 0xFF) {
+
+ case C_START:
+ Da.selectPoint = -1;
+ Da.extend[0] = FALSE;
+ Da.extend[1] = FALSE;
+ CreateBothEnds(Da.selectPoint);
+ Da.crvSegs_da.cnt = 0;
+ SetUpCornuParms(&cp);
+ if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
+ InfoMessage( _("Select End-Point") );
+ DrawTempCornu();
+ return C_CONTINUE;
+
+ case C_DOWN:
+ if (Da.state != PICK_POINT) return C_CONTINUE;
+ dd = 10000.0;
+ Da.selectPoint = -1;
+ for (int i=0;i<2;i++) {
+ d = FindDistance(Da.pos[i],pos);
+ if (d < dd) {
+ dd = d;
+ Da.selectPoint = i;
+ }
+ }
+ if (!IsClose(dd) ) Da.selectPoint = -1;
+ if (Da.selectPoint == -1) {
+ wBeep();
+ InfoMessage( _("Not close enough to end point, reselect") );
+ return C_CONTINUE;
+ } else if (Da.trk[Da.selectPoint] && QueryTrack(Da.trk[Da.selectPoint],Q_IS_CORNU)){
+ wBeep();
+ InfoMessage( _("Is Cornu End -> Not Selectable") );
+ return C_CONTINUE;
+ } else {
+ pos = Da.pos[Da.selectPoint];
+ Da.state = POINT_PICKED;
+ InfoMessage( _("Drag point %d to new location and release it"),Da.selectPoint+1 );
+ }
+ DrawTempCornu(); //wipe out
+ CreateBothEnds(Da.selectPoint);
+ SetUpCornuParms(&cp);
+ if (CallCornu(Da.pos, Da.trk,Da.ep, &Da.crvSegs_da, &cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ Da.minRadius = CornuMinRadius(Da.pos, Da.crvSegs_da);
+ DrawTempCornu();
+ return C_CONTINUE;
+
+ case C_MOVE:
+ if (Da.state != POINT_PICKED) {
+ InfoMessage(_("Pick any circle to adjust it by dragging - Enter to accept, Esc to cancel"));
+ return C_CONTINUE;
+ }
+ //If locked, reset pos to be on line from other track
+ int sel = Da.selectPoint;
+ coOrd pos2 = pos;
+ BOOL_T inside = FALSE;
+ if (Da.trk[sel]) { //There is a track
+ if (OnTrack(&pos,FALSE,TRUE) == Da.trk[sel]) { //And the pos is on it
+ inside = TRUE;
+ if (!QueryTrack(Da.trk[Da.selectPoint],Q_CORNU_CAN_MODIFY)) { //Turnouts
+ InfoMessage(_("Track can't be split"));
+ if (Da.ep[sel]>=0) //Ignore if turntable
+ pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ }
+ } else {
+ pos = pos2; //Put Back to original position as outside track
+ }
+ // Stop the user extending right through the other track
+ if (Da.ep[sel]>=0 && QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY)) { //For non-turnouts
+ if ((!QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)) // But Not Helix or Circle
+ && (!QueryTrack(Da.trk[sel],Q_HAS_VARIABLE_ENDPOINTS))) { // Not a Turntable
+ DIST_T ab = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]));
+ DIST_T ac = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),pos);
+ DIST_T cb = FindDistance(GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]), pos);
+ if (cb<minLength) {
+ InfoMessage(_("Too close to other end of selected Track"));
+ return C_CONTINUE;
+ }
+ if ((ac>=cb) && (ac>=ab)) { //Closer to far end and as long as the track
+ pos = GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]); //Make other end of track
+ }
+ }
+ }
+ }
+ DrawTempCornu(); //wipe out old
+ Da.extend[sel] = FALSE;
+ if(!Da.trk[sel]) { //Cornu with no ends
+ if (Da.radius[sel] == 0) { //Straight
+ Da.extendSeg[sel].type = SEG_STRTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ Da.extendSeg[sel].u.l.pos[1-sel] = Da.pos[sel];
+ d = FindDistance( Da.extendSeg[sel].u.l.pos[1-sel], pos );
+ a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel]));
+ if (cos(D2R(a))<=0) {
+ Translate( &Da.extendSeg[sel].u.l.pos[sel],
+ Da.extendSeg[sel].u.l.pos[1-sel],
+ Da.angle[sel], - d * cos(D2R(a)));
+ pos = Da.extendSeg[sel].u.l.pos[1-sel];
+ Da.extend[sel] = TRUE;
+ }
+ } else { //Curve
+ Da.extendSeg[sel].type = SEG_CRVTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ Da.extendSeg[sel].u.c.center = Da.center[sel];
+ Da.extendSeg[sel].u.c.radius = Da.radius[sel];
+ a = FindAngle( Da.center[sel], pos );
+ PointOnCircle( &pos, Da.center[sel], Da.radius[sel], a );
+ a2 = FindAngle(Da.center[sel],Da.pos[sel]);
+ if (((Da.angle[sel] < 180) && (a2>90 && a2<270)) ||
+ ((Da.angle[sel] > 180) && (a2<90 || a2>270))) {
+ Da.extendSeg[sel].u.c.a0 = a;
+ Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a);
+ } else {
+ Da.extendSeg[sel].u.c.a0 = a2;
+ Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2);
+ }
+ if (Da.extendSeg[sel].u.c.a1 == 0 || Da.extendSeg[sel].u.c.a1 >180 )
+ Da.extend[sel] = FALSE;
+ else
+ Da.extend[sel] = TRUE;
+ }
+ } else { //Cornu with ends
+ if (inside) Da.pos[sel] = pos;
+ if (!GetConnectedTrackParms(Da.trk[sel],pos,sel,Da.ep[sel])) {
+ DrawTempCornu();
+ wBeep();
+ return C_CONTINUE; //Stop drawing
+ }
+ CorrectHelixAngles();
+ if (!inside) { //Extend the track
+ if (Da.trackType[sel] == curveTypeStraight) { //Extend with a straight
+ Da.extendSeg[sel].type = SEG_STRTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ if (Da.ep[sel]>=0) {
+ Da.extendSeg[sel].u.l.pos[0] = GetTrkEndPos( Da.trk[sel], Da.ep[sel] );
+ a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,GetTrkEndPos(Da.trk[sel],Da.ep[sel])));
+ } else { //Turntable when unconnected
+ Da.extendSeg[sel].u.l.pos[0] = Da.pos[sel];
+ a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel]));
+ }
+ // Remove any extend in opposite direction for Turntable/Turnouts
+ if ((QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS) && Da.ep[sel]>=0)
+ && (!QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY))
+ && (a>90 && a<270)) {
+ Da.extend[sel] = FALSE; //Turntable with point and extension is other side of well
+ Da.pos[sel] = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ } else {
+ Da.extend[sel] = TRUE;
+ d = FindDistance( Da.extendSeg[sel].u.l.pos[0], pos );
+ Translate( &Da.extendSeg[sel].u.l.pos[1],
+ Da.extendSeg[sel].u.l.pos[0],
+ Da.angle[sel], -d * cos(D2R(a)));
+ Da.pos[sel] = pos = Da.extendSeg[sel].u.l.pos[1];
+ }
+ } else if (Da.trackType[sel] == curveTypeCurve) { //Extend with temp curve
+ Da.extendSeg[sel].type = SEG_CRVTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ Da.extendSeg[sel].u.c.center = Da.center[sel];
+ Da.extendSeg[sel].u.c.radius = Da.radius[sel];
+ a = FindAngle( Da.center[sel], pos );
+ PointOnCircle( &pos, Da.center[sel], Da.radius[sel], a );
+ a2 = FindAngle(Da.center[sel],GetTrkEndPos(Da.trk[sel],Da.ep[sel]));
+ if ((Da.angle[sel] < 180 && (a2>90 && a2 <270)) ||
+ (Da.angle[sel] > 180 && (a2<90 || a2 >270))) {
+ Da.extendSeg[sel].u.c.a0 = a2;
+ Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2);
+ } else {
+ Da.extendSeg[sel].u.c.a0 = a;
+ Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a);
+ }
+ if (Da.extendSeg[sel].u.c.a1 == 0.0 || Da.extendSeg[sel].u.c.a1 >180
+ || (Da.extendSeg[sel].u.c.a0 >= Da.arcA0[sel] && Da.extendSeg[sel].u.c.a0 < Da.arcA0[sel]+Da.arcA1[sel]
+ && Da.extendSeg[sel].u.c.a0 + Da.extendSeg[sel].u.c.a1 <= Da.arcA0[sel] + Da.arcA1[sel])
+ ) {
+ Da.extend[sel] = FALSE;
+ Da.pos[sel] = pos;
+ } else {
+ Da.extend[sel] = TRUE;
+ Da.pos[sel] = pos;
+ }
+
+ } else { //Bezier and Cornu that we are joining TO can't extend
+ DrawTempCornu(); //put back
+ wBeep();
+ InfoMessage(_("Must be on the %s Track"),Da.trackType[sel]==curveTypeBezier?"Bezier":Da.trackType[sel]==curveTypeCornu?"Cornu":"Unknown Type");
+ pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ return C_CONTINUE;
+ }
+ }
+ }
+
+ CreateBothEnds(Da.selectPoint);
+ SetUpCornuParms(&cp); //In case we want to use these because the ends are not on the track
+
+ if (CallCornu(Da.pos, Da.trk, Da.ep, &Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
+ DIST_T rin = Da.radius[0];
+ InfoMessage( _("Cornu : Min Radius=%s Max Rate of Radius Change=%s Length=%s Winding Arc=%s"),
+ FormatDistance(Da.minRadius),
+ FormatDistance(CornuMaxRateofChangeofCurvature(Da.pos,Da.crvSegs_da,&rin)),
+ FormatDistance(CornuLength(Da.pos,Da.crvSegs_da)),
+ FormatDistance(CornuTotalWindingArc(Da.pos,Da.crvSegs_da)));
+ DrawTempCornu();
+ return C_CONTINUE;
+
+ case C_UP:
+ if (Da.state != POINT_PICKED) return C_CONTINUE;
+ ep = 0;
+ DrawTempCornu(); //wipe out
+ Da.selectPoint = -1;
+ CreateBothEnds(Da.selectPoint);
+ SetUpCornuParms(&cp);
+ if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
+ InfoMessage(_("Pick on point to adjust it along track - Enter to confirm, ESC to abort"));
+ DrawTempCornu();
+ Da.state = PICK_POINT;
+ return C_CONTINUE;
+
+ case C_OK: //C_OK is not called by Modify.
+ if ( Da.state == PICK_POINT ) {
+ Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
+ if (CornuTotalWindingArc(Da.pos,Da.crvSegs_da)>4*360) {
+ wBeep();
+ InfoMessage(_("Cornu has too complex shape - adjust end pts"));
+ return C_CONTINUE;
+ }
+ if (!CheckHelix(NULL)) {
+ wBeep();
+ return C_CONTINUE;
+ }
+ for (int i=0;i<2;i++) {
+ if (FindDistance(Da.pos[i],GetTrkEndPos(Da.trk[i],1-Da.ep[i])) < minLength) {
+ wBeep();
+ InfoMessage(_("Cornu end %d too close to other end of connect track - reposition it"),i+1);
+ return C_CONTINUE;
+ }
+ }
+
+ DrawTempCornu();
+ UndoStart( _("Create Cornu"),"newCornu curve");
+ t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius,(trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt);
+ if (t==NULL) {
+ wBeep();
+ InfoMessage(_("Cornu Create Failed for p1[%0.3f,%0.3f] p2[%0.3f,%0.3f], c1[%0.3f,%0.3f] c2[%0.3f,%0.3f], a1=%0.3f a2=%0.3f, r1=%s r2=%s"),
+ Da.pos[0].x,Da.pos[0].y,
+ Da.pos[1].x,Da.pos[1].y,
+ Da.center[0].x,Da.center[0].y,
+ Da.center[1].x,Da.center[1].y,
+ Da.angle[0],Da.angle[1],
+ FormatDistance(Da.radius[0]),FormatDistance(Da.radius[1]));
+ return C_TERMINATE;
+ }
+
+ CopyAttributes( Da.trk[0], t );
+
+ for (int i=0;i<2;i++) {
+ UndoModify(Da.trk[i]);
+ MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0);
+ if ((GetTrkType(Da.trk[i])==T_BEZIER) || (GetTrkType(Da.trk[i])==T_CORNU)) { //Bezier split position not precise, so readjust Cornu
+ GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i]);
+ ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180);
+ SetCornuEndPt(t,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
+ }
+ if (Da.ep[i]>=0)
+ ConnectTracks(Da.trk[i],Da.ep[i],t,i);
+ }
+ UndoEnd();
+ DrawNewTrack(t);
+ Da.state = NONE;
+ MainRedraw();
+ MapRedraw();
+ return C_TERMINATE;
+ }
+ return C_CONTINUE;
+
+ case C_REDRAW:
+ DrawTempCornu();
+ return C_CONTINUE;
+
+ default:
+ return C_CONTINUE;
+ }
+
+
+}
+
+struct extraData {
+ cornuData_t cornuData;
+ };
+
+/**
+ * CmdCornuModify
+ *
+ * Called from Modify Command - this function deals with the real (old) track and calls AdjustCornuCurve to tune up the new one
+ * Sequence is this -
+ * - The C_START is called from CmdModify C_DOWN action if a track has being selected. The old track is hidden, the editable one is shown.
+ * - C_MOVES will be ignored until a C_UP ends the track selection and moves the state to PICK_POINT,
+ * - C_DOWN then hides the track and shows the Cornu circles. Selects a point (if close enough and available) and the state moves to POINT_PICKED
+ * - C_MOVE drags the point around modifying the curve
+ * - C_UP puts the state back to PICK_POINT (pick another)
+ * - C_OK (Enter/Space) creates the new track, deletes the old and shows the changed track.
+ * - C_CANCEL (Esc) sets the state to NONE and reshows the original track unchanged.
+ *
+ */
+STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos) {
+ track_p t;
+ struct extraData *xx = GetTrkExtraData(trk);
+
+ switch (action&0xFF) {
+ case C_START:
+ Da.state = NONE;
+ DYNARR_RESET(trkSeg_t,Da.crvSegs_da);
+ Da.ep1Segs_da_cnt = 0;
+ Da.ep2Segs_da_cnt = 0;
+ Da.extend[0] = FALSE;
+ Da.extend[1] = FALSE;
+ Da.selectPoint = -1;
+ Da.selectTrack = NULL;
+
+
+ Da.selectTrack = trk;
+ Da.trk[0] = GetTrkEndTrk( trk, 0 );
+ if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk);
+ Da.trk[1] = GetTrkEndTrk( trk, 1 );
+ if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk);
+
+ for (int i=0;i<2;i++) {
+ Da.pos[i] = xx->cornuData.pos[i]; //Copy parms from old trk
+ Da.radius[i] = xx->cornuData.r[i];
+ Da.angle[i] = xx->cornuData.a[i];
+ Da.center[i] = xx->cornuData.c[i];
+ }
+
+
+ if ((Da.trk[0] && (!QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[0],Q_CAN_EXTEND))) &&
+ (Da.trk[1] && (!QueryTrack(Da.trk[1],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[1],Q_CAN_EXTEND)))) {
+ wBeep();
+ ErrorMessage("Both Ends of this Cornu are UnAdjustable");
+ return C_TERMINATE;
+ }
+
+ InfoMessage(_("Track picked - now select a Point"));
+ Da.state = TRACK_SELECTED;
+ DrawTrack(Da.selectTrack,&mainD,wDrawColorWhite); //Wipe out real track, draw replacement
+ return AdjustCornuCurve(C_START, pos, InfoMessage);
+
+ case C_DOWN:
+ if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up
+ return AdjustCornuCurve(C_DOWN, pos, InfoMessage);
+
+
+ case C_MOVE:
+ if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up and down
+ return AdjustCornuCurve(C_MOVE, pos, InfoMessage);
+
+ case C_UP:
+ if (Da.state == TRACK_SELECTED) {
+ Da.state = PICK_POINT; //First time up, next time pick a point
+ }
+ return AdjustCornuCurve(C_UP, pos, InfoMessage); //Run Adjust
+
+ case C_TEXT:
+ if ((action>>8) != 32)
+ return C_CONTINUE;
+ /* no break */
+ case C_OK:
+ if (Da.state != PICK_POINT) { //Too early - abandon
+ InfoMessage(_("No changes made"));
+ Da.state = NONE;
+ //DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
+ return C_CANCEL;
+ }
+ if (!CheckHelix(trk)) {
+ wBeep();
+ return C_CONTINUE;
+ }
+ UndoStart( _("Modify Cornu"), "newCornu - CR" );
+ for (int i=0;i<2;i++) {
+ if (!Da.trk[i] && Da.extend[i]) {
+ if (Da.extendSeg[i].type == SEG_STRTRK) {
+ Da.trk[i] = NewStraightTrack(Da.extendSeg[i].u.l.pos[0],Da.extendSeg[i].u.l.pos[1]);
+ if (Da.trk[i]) Da.ep[i] = 1-i;
+ } else {
+ Da.trk[i] = NewCurvedTrack(Da.extendSeg[i].u.c.center,fabs(Da.extendSeg[i].u.c.radius),
+ Da.extendSeg[i].u.c.a0,Da.extendSeg[i].u.c.a1,FALSE);
+ if (Da.angle[i]>180)
+ Da.ep[i] = (Da.extendSeg[i].u.c.a0>90 && Da.extendSeg[i].u.c.a0<270)?0:1;
+ else
+ Da.ep[i] = (Da.extendSeg[i].u.c.a0>90 && Da.extendSeg[i].u.c.a0<270)?1:0;
+ }
+ if (!Da.trk[i]) {
+ wBeep();
+ InfoMessage(_("Cornu Extension Create Failed for end %d"),i);
+ return C_TERMINATE;
+ }
+
+ }
+ }
+
+ t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt);
+ if (t==NULL) {
+ wBeep();
+ InfoMessage(_("Cornu Create Failed for p1[%0.3f,%0.3f] p2[%0.3f,%0.3f], c1[%0.3f,%0.3f] c2[%0.3f,%0.3f], a1=%0.3f a2=%0.3f, r1=%s r2=%s"),
+ Da.pos[0].x,Da.pos[0].y,
+ Da.pos[1].x,Da.pos[1].y,
+ Da.center[0].x,Da.center[0].y,
+ Da.center[1].x,Da.center[1].y,
+ Da.angle[0],Da.angle[1],
+ FormatDistance(Da.radius[0]),FormatDistance(Da.radius[1]));
+ UndoUndo();
+ MainRedraw();
+ MapRedraw();
+ //DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
+ return C_TERMINATE;
+ }
+
+ DeleteTrack(trk, TRUE);
+
+ if (Da.trk[0]) UndoModify(Da.trk[0]);
+ if (Da.trk[1]) UndoModify(Da.trk[1]);
+
+ for (int i=0;i<2;i++) { //Attach new track
+ if (Da.trk[i] && Da.ep[i] != -1) { //Like the old track
+ MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0);
+ if (GetTrkType(Da.trk[i])==T_BEZIER) { //Bezier split position not precise, so readjust Cornu
+ GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i]);
+ ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180);
+ SetCornuEndPt(t,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
+ }
+ if (Da.ep[i]>= 0)
+ ConnectTracks(t,i,Da.trk[i],Da.ep[i]);
+ }
+ }
+ UndoEnd();
+ MainRedraw();
+ MapRedraw();
+ Da.state = NONE;
+ //DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
+ return C_TERMINATE;
+
+ case C_CANCEL:
+ InfoMessage(_("Modify Cornu Cancelled"));
+ Da.state = NONE;
+ //DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
+ MainRedraw();
+ MapRedraw();
+ return C_TERMINATE;
+
+ case C_REDRAW:
+ return AdjustCornuCurve(C_REDRAW, pos, InfoMessage);
+ }
+
+ return C_CONTINUE;
+
+}
+
+/*
+ * Find length by adding up the underlying segments. The segments can be straights, curves or bezier.
+ */
+DIST_T CornuLength(coOrd pos[4],dynArr_t segs) {
+
+ DIST_T dd = 0.0;
+ if (segs.cnt == 0 ) return dd;
+ for (int i = 0;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ dd += fabs(t.u.c.radius*D2R(t.u.c.a1));
+ } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) {
+ dd +=CornuLength(t.u.b.pos,t.bezSegs);
+ } else if (t.type == SEG_STRLIN || t.type == SEG_STRTRK ) {
+ dd += FindDistance(t.u.l.pos[0],t.u.l.pos[1]);
+ }
+ }
+ return dd;
+}
+
+DIST_T CornuMinRadius(coOrd pos[4],dynArr_t segs) {
+ DIST_T r = 100000.0, rr;
+ if (segs.cnt == 0 ) return r;
+ for (int i = 0;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ rr = fabs(t.u.c.radius);
+ } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) {
+ rr = CornuMinRadius(t.u.b.pos, t.bezSegs);
+ } else rr = 100000.00;
+ if (rr<r) r = rr;
+ }
+ return r;
+}
+
+DIST_T CornuTotalWindingArc(coOrd pos[4],dynArr_t segs) {
+ DIST_T rr = 0;
+ if (segs.cnt == 0 ) return 0;
+ for (int i = 0;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ rr += t.u.c.a1;
+ } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) {
+ rr += CornuTotalWindingArc(t.u.b.pos, t.bezSegs);
+ }
+ }
+ return rr;
+}
+
+DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4], dynArr_t segs, DIST_T * last_c) {
+ DIST_T r_max = 0.0, rc, lc = 0;
+ lc = * last_c;
+ segProcData_t segProcData;
+ if (segs.cnt == 0 ) return r_max;
+ for (int i = 0;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_FILCRCL) continue;
+ SegProc(SEGPROC_LENGTH,&t,&segProcData);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ rc = fabs(1/t.u.c.radius - lc)/segProcData.length.length/2;
+ lc = 1/t.u.c.radius;
+ } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) {
+ rc = CornuMaxRateofChangeofCurvature(t.u.b.pos, t.bezSegs,&lc); //recurse
+ } else {
+ rc = fabs(0-lc)/segProcData.length.length/2;
+ lc = 0;
+ }
+ if (rc>r_max) r_max = rc;
+ }
+ * last_c = lc;
+ return r_max;
+}
+
+/*
+ * Create a Cornu Curve Track
+ * Sequence is
+ * 1. Place 1st End
+ * 2. Place 2nd End
+ * 3 to n. Select and drag around points until done
+ * n+1. Confirm with enter or Cancel with Esc
+ */
+STATUS_T CmdCornu( wAction_t action, coOrd pos )
+{
+ track_p t;
+ cornuParm_t cp;
+
+ Da.color = lineColor;
+ Da.width = (double)lineWidth/mainD.dpi;
+
+ switch (action&0xFF) {
+
+ case C_START:
+ Da.state = NONE;
+ Da. selectPoint = -1;
+ for (int i=0;i<2;i++) {
+ Da.pos[i] = zero;
+ }
+ Da.trk[0] = Da.trk[1] = NULL;
+ //tempD.orig = mainD.orig;
+
+ DYNARR_RESET(trkSeg_t,Da.crvSegs_da);
+ Da.ep1Segs_da_cnt = 0;
+ Da.ep2Segs_da_cnt = 0;
+ Da.extend[0] = FALSE;
+ Da.extend[1] = FALSE;
+ if (selectedTrackCount==0)
+ InfoMessage( _("Left click - join with Cornu track") );
+ else
+ InfoMessage( _("Left click - join with Cornu track, Shift Left click - move to join") );
+ return C_CONTINUE;
+
+ case C_DOWN:
+ if ( Da.state == NONE || Da.state == LOC_2) { //Set the first or second point
+ coOrd p = pos;
+ int end = Da.state==NONE?0:1;
+ EPINX_T ep;
+ if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
+ if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where
+ if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) {
+ InfoMessage(_("Helix Already Connected"));
+ return C_CONTINUE;
+ }
+ ep = -1; //Not a real ep yet
+ } else ep = PickUnconnectedEndPointSilent(p, t);
+ if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) ep=-1; //Ignore Turntable Unconnected
+ else if (ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle
+ wBeep();
+ InfoMessage(_("No Unconnected end point on that track"));
+ return C_CONTINUE;
+ }
+ Da.trk[end] = t;
+ Da.ep[end] = ep; // Note: -1 for Turntable or Circle
+ if (ep ==-1) pos = p;
+ else pos = GetTrkEndPos(t,ep);
+ Da.pos[end] = pos;
+ InfoMessage( _("Place 2nd end point of Cornu track on track with an unconnected end-point") );
+ } else {
+ wBeep();
+ InfoMessage(_("No Unconnected Track End there"));
+ return C_CONTINUE;
+ }
+ if (Da.state == NONE) {
+ if (!GetConnectedTrackParms(t, pos, 0, Da.ep[0])) {
+ Da.trk[0] = NULL;
+ return C_CONTINUE;
+ }
+ Da.state = POS_1;
+ Da.selectPoint = 0;
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE, !QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY));
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
+ InfoMessage( _("Move 1st end point of Cornu track along track 1") );
+ } else {
+ if ( Da.trk[0] == t) {
+ ErrorMessage( MSG_JOIN_CORNU_SAME );
+ Da.trk[1] = NULL;
+ return C_CONTINUE;
+ }
+ if (!GetConnectedTrackParms(t, pos, 1, Da.ep[1])) {
+ Da.trk[1] = NULL; //Turntable Fail
+ return C_CONTINUE;
+ }
+ CorrectHelixAngles();
+ Da.selectPoint = 1;
+ Da.state = POINT_PICKED;
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack); //Wipe out initial Arm
+ CreateBothEnds(1);
+ if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da, &cp))
+ Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ DrawTempCornu();
+ InfoMessage( _("Move 2nd end point of Cornu track along track 2") );
+ }
+ return C_CONTINUE;
+ } else {
+ return AdjustCornuCurve( action&0xFF, pos, InfoMessage );
+ }
+ return C_CONTINUE;
+
+ case C_MOVE:
+ if (Da.state == NONE) {
+ InfoMessage("Place 1st end point of Cornu track on unconnected end-point");
+ return C_CONTINUE;
+ }
+ if (Da.state == POS_1) {
+ EPINX_T ep = 0;
+ BOOL_T found = FALSE;
+ int end = Da.state==POS_1?0:1;
+ if(!QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[0],Q_CAN_ADD_ENDPOINTS)) {
+ InfoMessage(_("Can't Split - Locked to End Point"));
+ return C_CONTINUE;
+ }
+ if (Da.trk[0] != OnTrack(&pos, FALSE, TRUE)) {
+ wBeep();
+ InfoMessage(_("Point not on track 1"));
+ Da.state = POS_1;
+ Da.selectPoint = 1;
+ return C_CONTINUE;
+ }
+ t = Da.trk[0];
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
+ if (!GetConnectedTrackParms(t, pos, ep, Da.ep[ep])) {
+ Da.state = POS_1;
+ Da.selectPoint = 1;
+ return C_CONTINUE;
+ }
+ Da.pos[ep] = pos;
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],TRUE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY));
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
+ } else {
+ return AdjustCornuCurve( action&0xFF, pos, InfoMessage );
+ }
+ return C_CONTINUE;
+
+ case C_UP:
+ if (Da.state == POS_1 && Da.trk[0]) {
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
+ Da.state = LOC_2;
+ InfoMessage( _("Put other end of Cornu on a track with an unconnected end point") );
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY));
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
+ return C_CONTINUE;
+ } else {
+ return AdjustCornuCurve( action&0xFF, pos, InfoMessage );
+ }
+ case C_TEXT:
+ if (Da.state != PICK_POINT || (action>>8) != 32) //Space is same as Enter.
+ return C_CONTINUE;
+ /* no break */
+ case C_OK:
+ if (Da.state != PICK_POINT) return C_CONTINUE;
+ return AdjustCornuCurve( C_OK, pos, InfoMessage);
+
+ case C_REDRAW:
+ if ( Da.state != NONE ) {
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,Da.ep2Segs,Da.ep2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, NULL, &Da.extendSeg[0],&Da.extendSeg[1],Da.color);
+ }
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ if (Da.state != NONE) {
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,Da.ep2Segs,Da.ep2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, NULL, &Da.extendSeg[0],&Da.extendSeg[1],Da.color);
+ Da.ep1Segs_da_cnt = 0;
+ Da.ep2Segs_da_cnt = 0;
+ Da.crvSegs_da_cnt = 0;
+ for (int i=0;i<2;i++) {
+ Da.radius[i] = 0.0;
+ Da.angle[i] = 0.0;
+ Da.center[i] = zero;
+ Da.trk[i] = NULL;
+ Da.ep[i] = -1;
+ Da.pos[i] = zero;
+ }
+ //DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
+ }
+ Da.state = NONE;
+ return C_CONTINUE;
+
+ default:
+
+ return C_CONTINUE;
+ }
+
+}
+
+
+EXPORT void InitCmdCornu( wMenu_p menu )
+{
+
+}
diff --git a/app/bin/ccornu.h b/app/bin/ccornu.h
new file mode 100644
index 0000000..a11e713
--- /dev/null
+++ b/app/bin/ccornu.h
@@ -0,0 +1,23 @@
+/*
+ * ccornu.h
+ *
+ * Created on: May 28, 2017
+ * Author: richardsa
+ */
+
+#ifndef APP_BIN_CCORNU_H_
+#define APP_BIN_CCORNU_H_
+
+
+typedef void (*cornuMessageProc)( char *, ... );
+
+
+#endif /* APP_BIN_CCORNU_H_ */
+
+STATUS_T CmdCornu( wAction_t action, coOrd pos );
+DIST_T CornuMinRadius(coOrd pos[4],dynArr_t segs);
+DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4],dynArr_t segs,DIST_T * last_c);
+DIST_T CornuLength(coOrd pos[4],dynArr_t segs);
+DIST_T CornuTotalWindingArc(coOrd pos[4],dynArr_t segs);
+
+STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos);
diff --git a/app/bin/ccurve.c b/app/bin/ccurve.c
index b284669..58bb5c1 100644
--- a/app/bin/ccurve.c
+++ b/app/bin/ccurve.c
@@ -1,8 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/ccurve.c,v 1.4 2008-03-06 19:35:04 m_fischer Exp $
- *
+/** \file ccurve.c
* CURVE
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -23,12 +20,25 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <math.h>
+#include <string.h>
+
#include "ccurve.h"
-#include "cstraigh.h"
+
#include "cjoin.h"
+#include "cstraigh.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
+#include "wlib.h"
+#include "cbezier.h"
/*
* STATE INFO
@@ -39,12 +49,15 @@ static struct {
coOrd pos0;
coOrd pos1;
curveData_t curveData;
+ track_p trk;
+ EPINX_T ep;
+ BOOL_T down;
} Da;
static long curveMode;
-static void DrawArrowHeads(
+EXPORT void DrawArrowHeads(
trkSeg_p sp,
coOrd pos,
ANGLE_T angle,
@@ -89,26 +102,34 @@ EXPORT STATUS_T CreateCurve(
long mode,
curveMessageProc message )
{
+ track_p t;
DIST_T d;
- ANGLE_T a;
- static coOrd pos0;
+ ANGLE_T a, angle1, angle2;
+ static coOrd pos0, p;
int inx;
switch ( action ) {
case C_START:
DYNARR_SET( trkSeg_t, tempSegs_da, 8 );
+ Da.down = FALSE; //Not got a valid start yet
switch ( curveMode ) {
case crvCmdFromEP1:
- InfoMessage( _("Drag from End-Point in direction of curve") );
+ if (track)
+ message(_("Drag from End-Point in direction of curve - Shift locks to track open end-point") );
+ else
+ message (_("Drag from End-Point in direction of curve") );
break;
case crvCmdFromTangent:
- InfoMessage( _("Drag from End-Point to Center") );
+ if (track)
+ message(_("Drag from End-Point to Center - Shift locks to track open end-point") );
+ else
+ message(_("Drag from End-Point to Center") );
break;
case crvCmdFromCenter:
- InfoMessage( _("Drag from Center to End-Point") );
+ message(_("Drag from Center to End-Point") );
break;
case crvCmdFromChord:
- InfoMessage( _("Drag to other end of chord") );
+ message(_("Drag from one to other end of chord") );
break;
}
return C_CONTINUE;
@@ -118,14 +139,40 @@ EXPORT STATUS_T CreateCurve(
tempSegs(inx).width = 0;
}
tempSegs_da.cnt = 0;
- SnapPos( &pos );
+ p = pos;
+ BOOL_T found = FALSE;
+ Da.trk = NULL;
+ if ((mode == crvCmdFromEP1 || mode == crvCmdFromTangent) && track && (MyGetKeyState() & WKEY_SHIFT) != 0) {
+ if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
+ EPINX_T ep = PickUnconnectedEndPointSilent(p, t);
+ if (ep != -1) {
+ Da.trk = t;
+ Da.ep = ep;
+ pos = GetTrkEndPos(t, ep);
+ found = TRUE;
+ } else {
+ Da.pos0=pos;
+ message(_("No unconnected end-point on track - Try again or release Shift and click"));
+ return C_CONTINUE;
+ }
+ } else {
+ Da.pos0=pos;
+ message(_("Not on a track - Try again or release Shift and click"));
+ return C_CONTINUE;
+ }
+ Da.down = TRUE;
+ }
+ Da.down = TRUE;
+ if (!found) SnapPos( &pos );
pos0 = pos;
+ Da.pos0 = pos;
switch (mode) {
case crvCmdFromEP1:
tempSegs(0).type = (track?SEG_STRTRK:SEG_STRLIN);
tempSegs(0).color = color;
tempSegs(0).width = width;
- message( _("Drag to set angle") );
+ if (Da.trk) message(_("End Locked: Drag out curve start"));
+ else message(_("Drag along curve start") );
break;
case crvCmdFromTangent:
case crvCmdFromCenter:
@@ -135,12 +182,14 @@ EXPORT STATUS_T CreateCurve(
tempSegs(1).u.c.a0 = 0;
tempSegs(1).u.c.a1 = 360;
tempSegs(2).type = SEG_STRLIN;
- message( mode==crvCmdFromTangent?_("Drag from End-Point to Center"):_("Drag from Center to End-Point") );
+ if (Da.trk && mode==crvCmdFromTangent) message(_("End Locked: Drag out to center"));
+ else
+ message( mode==crvCmdFromTangent?_("Drag from End-Point to Center"):_("Drag from Center to End-Point") );
break;
case crvCmdFromChord:
tempSegs(0).type = (track?SEG_STRTRK:SEG_STRLIN);
tempSegs(0).color = color;
- tempSegs(0).width = width;
+ tempSegs(0).width = width;
message( _("Drag to other end of chord") );
break;
}
@@ -148,16 +197,34 @@ EXPORT STATUS_T CreateCurve(
return C_CONTINUE;
case C_MOVE:
+ if (!Da.down) return C_CONTINUE;
+ if (Da.trk) {
+ angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk, Da.ep));
+ angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1);
+ if (mode ==crvCmdFromEP1) {
+ if (angle2 > 90.0 && angle2 < 270.0)
+ Translate( &pos, pos0, angle1, -FindDistance( pos0, pos )*cos(D2R(angle2)) );
+ else pos = pos0;
+ } else {
+ DIST_T dp = -FindDistance(pos0, pos)*sin(D2R(angle2));
+ if (angle2 > 180.0)
+ Translate( &pos, pos0, angle1+90.0, dp );
+ else
+ Translate( &pos, pos0, angle1-90.0, dp );
+ }
+ } else SnapPos(&pos);
tempSegs(0).u.l.pos[1] = pos;
d = FindDistance( pos0, pos );
a = FindAngle( pos0, pos );
switch ( mode ) {
case crvCmdFromEP1:
- message( _("Angle=%0.3f"), PutAngle(a) );
+ if (Da.trk) message( _("Start Locked: Drag out curve start - Angle=%0.3f"), PutAngle(a));
+ else message( _("Drag out curve start - Angle=%0.3f"), PutAngle(a) );
tempSegs_da.cnt = 1;
break;
case crvCmdFromTangent:
- message( _("Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) );
+ if (Da.trk) message( _("Tangent Locked: Drag out center - Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) );
+ else message( _("Drag out center - Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) );
tempSegs(1).u.c.center = pos;
DrawArrowHeads( &tempSegs(2), pos0, FindAngle(pos0,pos)+90, TRUE, wDrawColorBlack );
tempSegs_da.cnt = 7;
@@ -181,10 +248,30 @@ EXPORT STATUS_T CreateCurve(
break;
}
return C_CONTINUE;
-
case C_UP:
+ if (!Da.down) return C_CONTINUE;
+ if (Da.trk) {
+ angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk, Da.ep));
+ angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1);
+ if (mode == crvCmdFromEP1) {
+ if (angle2 > 90.0 && angle2 < 270.0) {
+ Translate( &pos, pos0, angle1, -FindDistance( pos0, pos )*cos(D2R(angle2)) );
+ Da.pos1 = pos;
+ } else {
+ ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(0.0) );
+ return C_TERMINATE;
+ }
+ } else {
+ DIST_T dp = -FindDistance(pos0, pos)*sin(D2R(angle2));
+ if (angle2 > 180.0)
+ Translate( &pos, pos0, angle1+90.0, dp );
+ else
+ Translate( &pos, pos0, angle1-90.0, dp );
+ Da.pos1 = pos;
+ }
+ }
switch (mode) {
- case crvCmdFromEP1:
+ case crvCmdFromEP1:
DrawArrowHeads( &tempSegs(1), pos, FindAngle(pos,pos0)+90, TRUE, drawColorRed );
tempSegs_da.cnt = 6;
break;
@@ -221,7 +308,9 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos )
case C_START:
curveMode = (long)commandContext;
Da.state = -1;
+ Da.pos0 = pos;
tempSegs_da.cnt = 0;
+ STATUS_T rcode;
return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage );
case C_TEXT:
@@ -232,25 +321,29 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos )
case C_DOWN:
if ( Da.state == -1 ) {
- SnapPos( &pos );
+ //SnapPos( &pos );
Da.pos0 = pos;
Da.state = 0;
- return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage );
+ rcode = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage );
+ if (!Da.down) Da.state = -1;
+ return rcode;
+ //Da.pos0 = pos;
} else {
tempSegs_da.cnt = segCnt;
return C_CONTINUE;
}
case C_MOVE:
+ if (Da.state<0) return C_CONTINUE;
mainD.funcs->options = wDrawOptTemp;
DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
if ( Da.state == 0 ) {
- SnapPos( &pos );
- Da.pos1 = pos;
+ Da.pos1 = pos;
rc = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage );
} else {
- SnapPos( &pos );
- PlotCurve( curveMode, Da.pos0, Da.pos1, pos, &Da.curveData, TRUE );
+ // SnapPos( &pos );
+ if (Da.trk) PlotCurve( curveMode, Da.pos0, Da.pos1, pos, &Da.curveData, FALSE );
+ else PlotCurve( curveMode, Da.pos0, Da.pos1, pos, &Da.curveData, TRUE );
if (Da.curveData.type == curveTypeStraight) {
tempSegs(0).type = SEG_STRTRK;
tempSegs(0).u.l.pos[0] = Da.pos0;
@@ -290,6 +383,7 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos )
case C_UP:
+ if (Da.state<0) return C_CONTINUE;
mainD.funcs->options = wDrawOptTemp;
DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
if (Da.state == 0) {
@@ -313,6 +407,10 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos )
}
UndoStart( _("Create Straight Track"), "newCurve - straight" );
t = NewStraightTrack( Da.pos0, Da.curveData.pos1 );
+ if (Da.trk) {
+ EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t);
+ if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep);
+ }
UndoEnd();
} else if (Da.curveData.type == curveTypeCurve) {
if ((d= Da.curveData.curveRadius * Da.curveData.a1 *2.0*M_PI/360.0) <= minLength) {
@@ -322,6 +420,10 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos )
UndoStart( _("Create Curved Track"), "newCurve - curve" );
t = NewCurvedTrack( Da.curveData.curvePos, Da.curveData.curveRadius,
Da.curveData.a0, Da.curveData.a1, 0 );
+ if (Da.trk) {
+ EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t);
+ if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep);
+ }
UndoEnd();
} else {
return C_ERROR;
@@ -344,6 +446,7 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos )
DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
mainD.funcs->options = 0;
tempSegs_da.cnt = 0;
+ Da.trk = NULL;
}
Da.state = -1;
return C_CONTINUE;
@@ -381,12 +484,12 @@ static void ComputeHelix( paramGroup_p, int, void * );
static paramFloatRange_t r0_360 = { 0, 360 };
static paramFloatRange_t r0_1000000 = { 0, 1000000 };
static paramIntegerRange_t i1_1000000 = { 1, 1000000 };
-static paramFloatRange_t r1_1000000 = { 1, 1000000 };
+static paramFloatRange_t r1_10000 = { 1, 10000 };
static paramFloatRange_t r0_100= { 0, 100 };
static paramData_t helixPLs[] = {
{ PD_FLOAT, &helixElev, "elev", PDO_DIM, &r0_1000000, N_("Elevation Difference") },
- { PD_FLOAT, &helixRadius, "radius", PDO_DIM, &r1_1000000, N_("Radius") },
+ { PD_FLOAT, &helixRadius, "radius", PDO_DIM, &r1_10000, N_("Radius") },
{ PD_LONG, &helixTurns, "turns", 0, &i1_1000000, N_("Turns") },
{ PD_FLOAT, &helixAngSep, "angSep", 0, &r0_360, N_("Angular Separation") },
{ PD_FLOAT, &helixGrade, "grade", 0, &r0_100, N_("Grade") },
@@ -396,7 +499,7 @@ static paramData_t helixPLs[] = {
static paramGroup_t helixPG = { "helix", PGO_PREFMISCGROUP, helixPLs, sizeof helixPLs/sizeof helixPLs[0] };
static paramData_t circleRadiusPLs[] = {
- { PD_FLOAT, &circleRadius, "radius", PDO_DIM, &r1_1000000 } };
+ { PD_FLOAT, &circleRadius, "radius", PDO_DIM, &r1_10000 } };
static paramGroup_t circleRadiusPG = { "circle", 0, circleRadiusPLs, sizeof circleRadiusPLs/sizeof circleRadiusPLs[0] };
@@ -604,7 +707,19 @@ static STATUS_T CmdCircleCommon( wAction_t action, coOrd pos, BOOL_T helix )
case C_UP:
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ if (helixRadius > mapD.size.x && helixRadius > mapD.size.y) {
+ ErrorMessage( MSG_RADIUS_TOO_BIG );
+ return C_ERROR;
+ }
+ if (circleRadius > mapD.size.x && circleRadius > mapD.size.y) {
+ ErrorMessage( MSG_RADIUS_TOO_BIG );
+ return C_ERROR;
+ }
if ( helix ) {
+ if (helixRadius > 10000) {
+ ErrorMessage( MSG_RADIUS_GTR_10000 );
+ return C_ERROR;
+ }
UndoStart( _("Create Helix Track"), "newHelix" );
t = NewCurvedTrack( tempSegs(0).u.c.center, helixRadius, 0.0, 0.0, helixTurns );
} else {
@@ -612,6 +727,10 @@ static STATUS_T CmdCircleCommon( wAction_t action, coOrd pos, BOOL_T helix )
ErrorMessage( MSG_RADIUS_GTR_0 );
return C_ERROR;
}
+ if ((circleRadius > 100000) || (helixRadius > 10000)) {
+ ErrorMessage( MSG_RADIUS_GTR_10000 );
+ return C_ERROR;
+ }
UndoStart( _("Create Circle Track"), "newCircle" );
t = NewCurvedTrack( tempSegs(0).u.c.center, circleRadius, 0.0, 0.0, 0 );
}
@@ -655,56 +774,15 @@ static STATUS_T CmdHelix( wAction_t action, coOrd pos )
return CmdCircleCommon( action, pos, TRUE );
}
-#ifdef LATER
-static struct {
- coOrd pos;
- DIST_T radius;
- } Dc2;
-
-
-static STATUS_T CmdCircle2( wAction_t action, coOrd pos )
-{
-
- switch (action) {
-
- case C_START:
- InfoMessage( _("Place circle center") );
- return C_CONTINUE;
-
- case C_DOWN:
- Dc2.pos = pos;
- InfoMessage( _("Drag to set radius") );
- return C_CONTINUE;
-
- case C_MOVE:
- dc2.radius = ConstrainR( FindDistance( Dc2.pos, pos ) );
- InfoMessage( "%s", FormatDistance(dc2.radius) );
- return C_CONTINUE;
-
- case C_UP:
- curCommand = cmdCircle;
- InfoMessage( _("Place circle") );
- return C_CONTINUE;
-
- default:
- return C_CONTINUE;
- }
-}
-#endif
-
-
-
-#include "bitmaps/helix.xpm"
#include "bitmaps/curve1.xpm"
#include "bitmaps/curve2.xpm"
#include "bitmaps/curve3.xpm"
#include "bitmaps/curve4.xpm"
+#include "bitmaps/bezier.xpm"
#include "bitmaps/circle1.xpm"
#include "bitmaps/circle2.xpm"
#include "bitmaps/circle3.xpm"
-
-
EXPORT void InitCmdCurve( wMenu_p menu )
{
@@ -713,6 +791,7 @@ EXPORT void InitCmdCurve( wMenu_p menu )
AddMenuButton( menu, CmdCurve, "cmdCurveTangent", _("Curve from Tangent"), wIconCreatePixMap( curve2_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE2, (void*)1 );
AddMenuButton( menu, CmdCurve, "cmdCurveCenter", _("Curve from Center"), wIconCreatePixMap( curve3_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE3, (void*)2 );
AddMenuButton( menu, CmdCurve, "cmdCurveChord", _("Curve from Chord"), wIconCreatePixMap( curve4_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE4, (void*)3 );
+ AddMenuButton( menu, CmdBezCurve, "cmdBezier", _("Bezier Curve"), wIconCreatePixMap(bezier_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_BEZIER, (void*)bezCmdCreateTrack );
ButtonGroupEnd();
ButtonGroupBegin( _("Circle Track"), "cmdCurveSetCmd", _("Circle Tracks") );
@@ -726,10 +805,18 @@ EXPORT void InitCmdCurve( wMenu_p menu )
}
-EXPORT void InitCmdHelix( wMenu_p menu )
-{
- AddMenuButton( menu, CmdHelix, "cmdHelix", _("Helix"), wIconCreatePixMap(helix_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_HELIX, NULL );
- ParamRegister( &helixPG );
- RegisterChangeNotification( ChangeHelixW );
+/**
+* Append the helix command to the pulldown menu. The helix doesn't use an icon, so it is only
+* available through the pulldown
+*
+* \param varname1 IN pulldown menu
+* \return
+*/
+void InitCmdHelix(wMenu_p menu)
+{
+ AddMenuButton(menu, CmdHelix, "cmdHelix", _("Helix"), NULL, LEVEL0_50,
+ IC_STICKY|IC_POPUP2, ACCL_HELIX, NULL);
+ ParamRegister(&helixPG);
+ RegisterChangeNotification(ChangeHelixW);
}
diff --git a/app/bin/ccurve.h b/app/bin/ccurve.h
index 1b2c7f6..c9d1c8c 100644
--- a/app/bin/ccurve.h
+++ b/app/bin/ccurve.h
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/ccurve.h,v 1.1 2005-12-07 15:47:36 rc-flyer Exp $
+/** \file ccurve.h
+ * Definitions for curve commands
*/
/* XTrkCad - Model Railroad CAD
@@ -20,6 +20,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef HAVE_CCURVE_H
+#define HAVE_CCURVE_H
+
+#include "draw.h"
+#include "track.h"
+#include "wlib.h"
+#include "utility.h"
typedef struct {
curveType_e type;
@@ -27,12 +34,14 @@ typedef struct {
coOrd pos1;
DIST_T curveRadius;
ANGLE_T a0, a1;
+ BOOL_T negative;
} curveData_t;
#define crvCmdFromEP1 (0)
#define crvCmdFromTangent (1)
#define crvCmdFromCenter (2)
#define crvCmdFromChord (3)
+#define crvCmdFromCornu (4)
#define circleCmdFixedRadius (0)
#define circleCmdFromTangent (1)
@@ -45,4 +54,7 @@ void PlotCurve( long, coOrd, coOrd, coOrd, curveData_t *, BOOL_T );
track_p NewCurvedTrack( coOrd, DIST_T, ANGLE_T, ANGLE_T, long );
DIST_T CurveDescriptionDistance( coOrd, track_p );
STATUS_T CurveDescriptionMove( track_p, wAction_t, coOrd );
-BOOL_T GetCurveMiddle( track_p, coOrd * );
+BOOL_T GetCurveMiddle( track_p , coOrd * );
+void DrawArrowHeads(trkSeg_p sp, coOrd pos, ANGLE_T angle, BOOL_T bidirectional, wDrawColor color );
+
+#endif // !HAVE_CCURVE_H
diff --git a/app/bin/cdraw.c b/app/bin/cdraw.c
index efdb51a..418f32a 100644
--- a/app/bin/cdraw.c
+++ b/app/bin/cdraw.c
@@ -20,12 +20,22 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
#include "ccurve.h"
+#include "cbezier.h"
#include "drawgeom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
+#include "misc.h"
-#include <stdint.h>
+extern TRKTYP_T T_BZRLIN;
extern void wSetSelectedFontSize(int size);
@@ -200,14 +210,15 @@ static struct {
wIndex_t dimenSize;
descPivot_t pivot;
wIndex_t fontSizeInx;
- char text[STR_SIZE];
- LAYER_T layer;
+ char text[STR_LONG_SIZE];
+ unsigned int layer;
+ char polyType[STR_SIZE];
} drawData;
-typedef enum { E0, E1, CE, RA, LN, AL, A1, A2, VC, LW, CO, BE, OR, DS, TP, TA, TS, TX, PV, LY } drawDesc_e;
+typedef enum { E0, E1, CE, RA, LN, AL, A1, A2, VC, LW, CO, BE, OR, DS, TP, TA, TS, TX, PV, LY, PT } drawDesc_e;
static descData_t drawDesc[] = {
-/*E0*/ { DESC_POS, N_("End Pt 1: X"), &drawData.endPt[0] },
-/*E1*/ { DESC_POS, N_("End Pt 2: X"), &drawData.endPt[1] },
-/*CE*/ { DESC_POS, N_("Center: X"), &drawData.center },
+/*E0*/ { DESC_POS, N_("End Pt 1: X,Y"), &drawData.endPt[0] },
+/*E1*/ { DESC_POS, N_("End Pt 2: X,Y"), &drawData.endPt[1] },
+/*CE*/ { DESC_POS, N_("Center: X,Y"), &drawData.center },
/*RA*/ { DESC_DIM, N_("Radius"), &drawData.radius },
/*LN*/ { DESC_DIM, N_("Length"), &drawData.length },
/*AL*/ { DESC_FLOAT, N_("Angle"), &drawData.angle },
@@ -219,12 +230,13 @@ static descData_t drawDesc[] = {
/*BE*/ { DESC_LIST, N_("Lumber"), &drawData.benchChoice },
/*OR*/ { DESC_LIST, N_("Orientation"), &drawData.benchOrient },
/*DS*/ { DESC_LIST, N_("Size"), &drawData.dimenSize },
-/*TP*/ { DESC_POS, N_("Origin: X"), &drawData.endPt[0] },
+/*TP*/ { DESC_POS, N_("Origin: X,Y"), &drawData.endPt[0] },
/*TA*/ { DESC_FLOAT, N_("Angle"), &drawData.angle },
/*TS*/ { DESC_EDITABLELIST, N_("Font Size"), &drawData.fontSizeInx },
-/*TX*/ { DESC_STRING, N_("Text"), &drawData.text },
+/*TX*/ { DESC_TEXT, N_("Text"), &drawData.text },
/*PV*/ { DESC_PIVOT, N_("Pivot"), &drawData.pivot },
/*LY*/ { DESC_LAYER, N_("Layer"), &drawData.layer },
+/*PT*/ { DESC_STRING, N_("Type"), &drawData.polyType },
{ DESC_NULL } };
int drawSegInx;
@@ -241,14 +253,15 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final )
struct extraData *xx = GetTrkExtraData(trk);
trkSeg_p segPtr;
coOrd mid;
- const char * text;
long fontSize;
if ( drawSegInx==-1 )
return;
- if ( inx == -1 )
- return;
segPtr = &xx->segs[drawSegInx];
+ if ( inx == -1 ) {
+ if (segPtr->type != SEG_TEXT) return;
+ else inx = TX; //Always look at TextField for SEG_TEXT on "Done"
+ }
MainRedraw();
MapRedraw();
UndrawNewTrack( trk );
@@ -286,7 +299,7 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final )
if ( segPtr->type != SEG_CRVLIN ) {
drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] );
} else {
- drawData.length = segPtr->u.c.radius*2*M_PI*segPtr->u.c.a1/360.0;
+ drawData.length = fabs(segPtr->u.c.radius)*2*M_PI*segPtr->u.c.a1/360.0;
}
drawDesc[LN].mode |= DESC_CHANGE;
break;
@@ -375,12 +388,14 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final )
segPtr->u.t.fontSize = fontSize;
break;
case TX:
- text = wStringGetValue( (wString_p)drawDesc[TX].control0 );
- if ( text && text[0] && strcmp( segPtr->u.t.string, text ) != 0 ) {
+ if ( wTextGetModified((wText_p)drawDesc[TX].control0 )) {
+ int len = wTextGetSize((wText_p)drawDesc[TX].control0);
MyFree( segPtr->u.t.string );
- segPtr->u.t.string = MyStrdup( text );
- /*(char*)drawDesc[TX].valueP = segPtr->u.t.string;*/
+ segPtr->u.t.string = (char *)MyMalloc(len+1);
+ wTextGetText((wText_p)drawDesc[TX].control0, segPtr->u.t.string, len+1);
+ segPtr->u.t.string[len] = '\0'; //Make sure of null term
}
+
break;
case LY:
SetTrkLayer( trk, drawData.layer);
@@ -400,6 +415,7 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len )
trkSeg_p segPtr;
int inx;
char * title = NULL;
+ char * polyType = NULL;
DistanceSegs( xx->orig, xx->angle, xx->segCnt, xx->segs, &pos, &drawSegInx );
@@ -462,7 +478,7 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len )
break;
case SEG_CRVLIN:
REORIGIN( drawData.center, segPtr->u.c.center, xx->angle, xx->orig );
- drawData.radius = segPtr->u.c.radius;
+ drawData.radius = fabs(segPtr->u.c.radius);
drawDesc[CE].mode =
drawDesc[RA].mode = 0;
if ( segPtr->u.c.a1 >= 360.0 ) {
@@ -479,7 +495,7 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len )
break;
case SEG_FILCRCL:
REORIGIN( drawData.center, segPtr->u.c.center, xx->angle, xx->orig );
- drawData.radius = segPtr->u.c.radius;
+ drawData.radius = fabs(segPtr->u.c.radius);
drawDesc[CE].mode =
drawDesc[RA].mode = 0;
drawDesc[LW].mode = DESC_IGNORE;
@@ -488,21 +504,37 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len )
case SEG_POLY:
drawData.pointCount = segPtr->u.p.cnt;
drawDesc[VC].mode = DESC_RO;
- title = _("Poly Line");
+ drawDesc[PT].mode = DESC_RO;
+ switch (segPtr->u.p.polyType) {
+ case RECTANGLE:
+ polyType = _("Rectangle");
+ break;
+ default:
+ polyType = _("Freeform");
+ }
+ strncpy( drawData.polyType, polyType, sizeof drawData.polyType );
+ title = _("Polygonal Line");
break;
case SEG_FILPOLY:
drawData.pointCount = segPtr->u.p.cnt;
drawDesc[VC].mode = DESC_RO;
drawDesc[LW].mode = DESC_IGNORE;
+ drawDesc[PT].mode = DESC_RO;
+ switch (segPtr->u.p.polyType) {
+ case RECTANGLE:
+ polyType =_("Rectangle");
+ break;
+ default:
+ polyType = _("Freeform");
+ }
+ strncpy( drawData.polyType, polyType, sizeof drawData.polyType );
title = _("Polygon");
break;
case SEG_TEXT:
REORIGIN( drawData.endPt[0], segPtr->u.t.pos, xx->angle, xx->orig );
- //drawData.angle = NormalizeAngle( segPtr->u.t.angle );
drawData.angle = NormalizeAngle( xx->angle );
strncpy( drawData.text, segPtr->u.t.string, sizeof drawData.text );
- /*drawData.fontSize = segPtr->u.t.fontSize;*/
- /*(char*)drawDesc[TX].valueP = segPtr->u.t.string;*/
+ drawData.text[sizeof drawData.text-1] ='\0';
drawDesc[TP].mode =
drawDesc[TS].mode =
drawDesc[TX].mode =
@@ -541,7 +573,7 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len )
static void DrawDraw( track_p t, drawCmd_p d, wDrawColor color )
{
struct extraData * xx = GetTrkExtraData(t);
- if ( (d->options&DC_QUICK) == 0 )
+ if ( (d->funcs->options&DC_QUICK) == 0 )
DrawSegs( d, xx->orig, xx->angle, xx->segs, xx->segCnt, 0.0, color );
}
@@ -668,7 +700,7 @@ static ANGLE_T GetAngleDraw(
pos.x -= xx->orig.x;
pos.y -= xx->orig.y;
Rotate( &pos, zero, -xx->angle );
- angle = GetAngleSegs( xx->segCnt, xx->segs, pos, NULL );
+ angle = GetAngleSegs( xx->segCnt, xx->segs, &pos, NULL, NULL, NULL, NULL, NULL);
if ( ep0 ) *ep0 = -1;
if ( ep1 ) *ep1 = -1;
return NormalizeAngle( angle + xx->angle );
@@ -767,7 +799,69 @@ EXPORT BOOL_T OnTableEdgeEndPt( track_p trk, coOrd * pos )
return FALSE;
}
+EXPORT BOOL_T GetClosestEndPt( track_p trk, coOrd * pos)
+{
+ struct extraData *xx;
+
+ if (GetTrkType(trk) == T_DRAW) {
+ ignoredTableEdge = NULL;
+ xx = GetTrkExtraData(trk);
+ if (xx->segCnt < 1)
+ return FALSE;
+ DIST_T dd0,dd1;
+ coOrd p00,p0,p1;
+ p00 = *pos;
+ if (GetTrkType(trk) == T_DRAW) {
+ Rotate(&p00,xx->orig,-xx->angle);
+ p00.x -= xx->orig.x;
+ p00.y -= xx->orig.y;
+ switch (xx->segs[0].type) {
+ case SEG_CRVLIN:
+ PointOnCircle( &p0, xx->segs[0].u.c.center, fabs(xx->segs[0].u.c.radius), xx->segs[0].u.c.a0 );
+ dd0 = FindDistance( p00, p0);
+ PointOnCircle( &p1, xx->segs[0].u.c.center, fabs(xx->segs[0].u.c.radius), xx->segs[0].u.c.a0 + xx->segs[0].u.c.a1);
+ dd1 = FindDistance( p00, p1);
+ break;
+ case SEG_STRLIN:
+ dd0 = FindDistance( p00, xx->segs[0].u.l.pos[0]);
+ p0 = xx->segs[0].u.l.pos[0];
+ dd1 = FindDistance( p00, xx->segs[0].u.l.pos[1]);
+ p1 = xx->segs[0].u.l.pos[1];
+ break;
+ case SEG_BEZLIN:
+ dd0 = FindDistance( p00, xx->segs[0].u.b.pos[0]);
+ p0 = xx->segs[0].u.b.pos[0];
+ dd1 = FindDistance( p00, xx->segs[0].u.b.pos[3]);
+ p1 = xx->segs[0].u.b.pos[3];
+ break;
+ default:
+ return FALSE;
+ }
+ p0.x += xx->orig.x;
+ p0.y += xx->orig.y;
+ Rotate(&p0,xx->orig,xx->angle);
+ p1.x += xx->orig.x;
+ p1.y += xx->orig.y;
+ Rotate(&p1,xx->orig,xx->angle);
+ } else if (GetTrkType(trk) == T_BZRLIN) {
+ coOrd p0,p1;
+ xx = GetTrkExtraData(trk);
+ p0 = xx->segs[0].u.b.pos[0];
+ p1 = xx->segs[0].u.b.pos[3];
+ dd0 = FindDistance(p00,p0);
+ dd1 = FindDistance(p00,p1);
+ } else return FALSE;
+ if (dd0>dd1) {
+ * pos = p1;
+ return TRUE;
+ } else {
+ * pos = p0;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
static void DrawRedraw(void);
@@ -783,15 +877,13 @@ static void DrawRedraw( void )
MapRedraw();
}
-
static wIndex_t benchChoice;
static wIndex_t benchOrient;
static wIndex_t dimArrowSize;
-static wDrawColor lineColor;
+wDrawColor lineColor = 1;
+long lineWidth = 0;
static wDrawColor benchColor;
-#ifdef LATER
-static wIndex_t benchInx;
-#endif
+
static paramIntegerRange_t i0_100 = { 0, 100, 25 };
static paramData_t drawPLs[] = {
@@ -802,7 +894,11 @@ static paramData_t drawPLs[] = {
#define drawBenchColorPD (drawPLs[2])
{ PD_COLORLIST, &benchColor, "benchcolor", PDO_NORECORD, NULL, N_("Color") },
#define drawBenchChoicePD (drawPLs[3])
- { PD_DROPLIST, &benchChoice, "benchlist", PDO_NOPREF|PDO_NORECORD|PDO_LISTINDEX, (void*)80, N_("Lumber Type") },
+#ifdef WINDOWS
+ { PD_DROPLIST, &benchChoice, "benchlist", PDO_NOPREF|PDO_NORECORD|PDO_LISTINDEX, (void*)120, N_("Lumber Type") },
+#else
+ { PD_DROPLIST, &benchChoice, "benchlist", PDO_NOPREF|PDO_NORECORD|PDO_LISTINDEX, (void*)145, N_("Lumber Type") },
+#endif
#define drawBenchOrientPD (drawPLs[4])
#ifdef WINDOWS
{ PD_DROPLIST, &benchOrient, "benchorient", PDO_NOPREF|PDO_NORECORD|PDO_LISTINDEX, (void*)45, "", 0 },
@@ -832,6 +928,7 @@ static char * objectName[] = {
N_("Filled Circle"),
N_("Filled Box"),
N_("Polygon"),
+ N_("Bezier Line"),
NULL};
static STATUS_T CmdDraw( wAction_t action, coOrd pos )
@@ -842,6 +939,8 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos )
char * labels[3];
static char labelName[40];
+ wAction_t act2 = (action&0xFF) | (bezCmdCreateLine<<8);
+
switch (action&0xFF) {
case C_START:
@@ -870,6 +969,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos )
case OP_CIRCLE3:
case OP_BOX:
case OP_POLY:
+ case OP_BEZLIN:
controls[0] = drawWidthPD.control;
controls[1] = drawColorPD.control;
controls[2] = NULL;
@@ -879,6 +979,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos )
InfoSubstituteControls( controls, labels );
drawWidthPD.option &= ~PDO_NORECORD;
drawColorPD.option &= ~PDO_NORECORD;
+ lineWidth = drawCmdContext.Width;
break;
case OP_FILLCIRCLE2:
case OP_FILLCIRCLE3:
@@ -935,12 +1036,17 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos )
infoSubst = FALSE;
}
ParamGroupRecord( &drawPG );
+ if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos);
DrawGeomMouse( C_START, pos, &drawCmdContext );
return C_CONTINUE;
case wActionLDown:
ParamLoadData( &drawPG );
+ if (drawCmdContext.Op == OP_BEZLIN) {
+ act2 = action | (bezCmdCreateLine<<8);
+ return CmdBezCurve(act2, pos);
+ }
if ( drawCmdContext.Op == OP_BENCH ) {
drawCmdContext.benchOption = GetBenchData( (long)wListGetItemContext((wList_p)drawBenchChoicePD.control, benchChoice ), benchOrient );
drawCmdContext.Color = benchColor;
@@ -963,22 +1069,29 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos )
case wActionRUp:
case wActionText:
case C_CMDMENU:
- SnapPos( &pos );
+ if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos);
+ if (!((MyGetKeyState() & WKEY_SHIFT) != 0)) {
+ SnapPos( &pos );
+ }
return DrawGeomMouse( action, pos, &drawCmdContext );
case C_CANCEL:
InfoSubstituteControls( NULL, NULL );
+ if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos);
return DrawGeomMouse( action, pos, &drawCmdContext );
case C_OK:
+ if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos);
return DrawGeomMouse( (0x0D<<8|wActionText), pos, &drawCmdContext );
/*DrawOk( NULL );*/
case C_FINISH:
+ if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos);
return DrawGeomMouse( (0x0D<<8|wActionText), pos, &drawCmdContext );
/*DrawOk( NULL );*/
case C_REDRAW:
+ if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos);
return DrawGeomMouse( action, pos, &drawCmdContext );
default:
@@ -1004,6 +1117,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos )
#include "bitmaps/dfilbox.xpm"
#include "bitmaps/dpoly.xpm"
#include "bitmaps/dfilpoly.xpm"
+#include "bitmaps/dbezier.xpm"
typedef struct {
char **xpm;
@@ -1023,7 +1137,8 @@ static drawData_t dcurveCmds[] = {
{ dcurve1_xpm, OP_CURVE1, N_("Curve End"), N_("Draw Curve from End"), "cmdDrawCurveEndPt", ACCL_DRAWCURVE1 },
{ dcurve2_xpm, OP_CURVE2, N_("Curve Tangent"), N_("Draw Curve from Tangent"), "cmdDrawCurveTangent", ACCL_DRAWCURVE2 },
{ dcurve3_xpm, OP_CURVE3, N_("Curve Center"), N_("Draw Curve from Center"), "cmdDrawCurveCenter", ACCL_DRAWCURVE3 },
- { dcurve4_xpm, OP_CURVE4, N_("Curve Chord"), N_("Draw Curve from Chord"), "cmdDrawCurveChord", ACCL_DRAWCURVE4 } };
+ { dcurve4_xpm, OP_CURVE4, N_("Curve Chord"), N_("Draw Curve from Chord"), "cmdDrawCurveChord", ACCL_DRAWCURVE4 },
+ { dbezier_xpm, OP_BEZLIN, N_("Bezier Curve"), N_("Draw Bezier"), "cmdDrawBezierCurve", ACCL_DRAWBEZLINE } };
static drawData_t dcircleCmds[] = {
/*{ dcircle1_xpm, OP_CIRCLE1, "Circle Fixed Radius", "Draw Fixed Radius Circle", "cmdDrawCircleFixedRadius", ACCL_DRAWCIRCLE1 },*/
{ dcircle2_xpm, OP_CIRCLE3, N_("Circle Tangent"), N_("Draw Circle from Tangent"), "cmdDrawCircleTangent", ACCL_DRAWCIRCLE2 },
@@ -1052,12 +1167,11 @@ static drawStuff_t drawStuff[4];
static drawStuff_t drawStuff[4] = {
{ "cmdDrawLineSetCmd", N_("Straight Objects"), N_("Draw Straight Objects"), 4, dlineCmds },
- { "cmdDrawCurveSetCmd", N_("Curved Lines"), N_("Draw Curved Lines"), 4, dcurveCmds },
+ { "cmdDrawCurveSetCmd", N_("Curved Lines"), N_("Draw Curved Lines"), 5, dcurveCmds },
{ "cmdDrawCircleSetCmd", N_("Circle Lines"), N_("Draw Circles"), 4, dcircleCmds },
{ "cmdDrawShapeSetCmd", N_("Shapes"), N_("Draw Shapes"), 4, dshapeCmds} };
-
static void ChangeDraw( long changes )
{
wIndex_t choice, orient;
@@ -1079,6 +1193,15 @@ static void DrawDlgUpdate(
int inx,
void * valueP )
{
+ if (drawCmdContext.Op == OP_BEZLIN) {
+ if ( (inx == 0 && pg->paramPtr[inx].valueP == &drawCmdContext.Width) ||
+ (inx == 1 && pg->paramPtr[inx].valueP == &lineColor))
+ {
+ lineWidth = drawCmdContext.Width;
+ UpdateParms(lineColor, lineWidth);
+ }
+ }
+
if ( inx >= 0 && pg->paramPtr[inx].valueP == &benchChoice )
BenchUpdateOrientationList( (long)wListGetItemContext( (wList_p)drawBenchChoicePD.control, (wIndex_t)*(long*)valueP ), (wList_p)drawBenchOrientPD.control );
}
@@ -1108,9 +1231,7 @@ EXPORT void InitCmdDraw( wMenu_p menu )
ParamRegister( &drawPG );
RegisterChangeNotification( ChangeDraw );
-#ifdef LATER
- InitCommand( cmdDraw, N_("Draw"), draw_bits, LEVEL0_50, IC_POPUP|IC_CMDMENU, ACCL_DRAW );
-#endif
+
}
@@ -1168,7 +1289,6 @@ EXPORT track_p NewText(
return trk;
}
-
EXPORT BOOL_T ReadText( char * line )
{
coOrd pos;
@@ -1190,6 +1310,10 @@ EXPORT BOOL_T ReadText( char * line )
return FALSE;
}
+ char * old = text;
+ text = ConvertFromEscapedText(text);
+ MyFree(old);
+
trk = NewText( index, pos, angle, text, textSize, color );
SetTrkLayer( trk, layer );
MyFree(text);
diff --git a/app/bin/celev.c b/app/bin/celev.c
index 164ea43..2677f2e 100644
--- a/app/bin/celev.c
+++ b/app/bin/celev.c
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/celev.c,v 1.4 2008-03-06 19:35:05 m_fischer Exp $
+/** /file celev.c
+ * ELEVATION
*/
/* XTrkCad - Model Railroad CAD
@@ -19,16 +19,16 @@
* along with this program; 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 "track.h"
#include "cselect.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
-
-/*****************************************************************************
- *
- * ELEVATION
- *
- */
+#include "param.h"
+#include "track.h"
static wWin_p elevW;
diff --git a/app/bin/cgroup.c b/app/bin/cgroup.c
index 76b15ca..b173987 100644
--- a/app/bin/cgroup.c
+++ b/app/bin/cgroup.c
@@ -1,6 +1,4 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cgroup.c,v 1.2 2008-01-20 23:29:15 mni77 Exp $
- *
+/** \file cgroup.c
* Compound tracks: Group
*
*/
@@ -24,10 +22,23 @@
*/
#include <ctype.h>
-#include "track.h"
+#include <math.h>
+#include <string.h>
+
#include "compound.h"
-#include "shrtpath.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "tbezier.h"
+#include "tcornu.h"
+#include "common.h"
+#include "messages.h"
+#include "param.h"
+#include "shrtpath.h"
+#include "track.h"
+#include "utility.h"
+
/*****************************************************************************
*
@@ -46,6 +57,10 @@ static char groupPartno[STR_SIZE];
static char groupTitle[STR_SIZE];
static int groupCompoundCount = 0;
+extern TRKTYP_T T_BZRTRK;
+extern TRKTYP_T T_BZRLIN;
+extern TRKTYP_T T_CORNU;
+
typedef struct {
int segInx;
EPINX_T segEP;
@@ -666,7 +681,11 @@ static char * FindPathBtwEP(
if ( ep1+ep2 != 1 )
AbortProg( "findPathBtwEP" );
*flip = ( ep1 == 1 );
- return "\1\0\0";
+ if (GetTrkType(trk) == T_CORNU ) { // Cornu doesn't have a path but lots of segs!
+ cp = CreateSegPathList(trk); // Make path
+LOG( log_group, 2, ( " Group: Cornu path:%s \n", cp ) )
+ } else cp = "\1\0\0"; //One segment (but could be a Bezier)
+ return cp;
}
cp = (char *)xx->paths;
pos1 = GetTrkEndPos(trk,ep1);
@@ -678,7 +697,7 @@ static char * FindPathBtwEP(
pos2.x -= xx->orig.x;
pos2.y -= xx->orig.y;
while ( cp[0] ) {
- cp += strlen(cp)+1;
+ cp += strlen(cp)+1; //Ignore Path Name
while ( cp[0] ) {
cp0 = cp;
epN = -1;
@@ -691,8 +710,8 @@ static char * FindPathBtwEP(
if ( epN != -1 ) {
GetSegInxEP( cp[-1], &segInx, &segEP );
if ( CheckTurnoutEndPoint( &xx->segs[segInx], epN==0?pos1:pos2, 1-segEP ) ) {
- *flip = epN==0;
- return cp0;
+ *flip = epN==0; // If its reversed, set up to be flipped or noted
+ return cp0; //Found path between EPs
}
}
cp++;
@@ -995,6 +1014,12 @@ static void GroupOk( void * junk )
DrawSegs( &groupD, xx->orig, xx->angle, segPtr, 1, trackGauge, wDrawColorBlack );
}
}
+ } else if (GetTrkType(trk) == T_BEZIER || GetTrkType(trk) == T_BZRLIN ) {
+ DYNARR_APPEND(trkSeg_t, trackSegs_da, 10);
+ segPtr = &trackSegs(trackSegs_da.cnt-1);
+ GetBezierSegmentFromTrack(trk,segPtr);
+ } else if (GetTrkType(trk) == T_CORNU) {
+ GetBezierSegmentsFromCornu(trk,&trackSegs_da); //Only give back Bezier - cant be undone
} else {
segCnt = tempSegs_da.cnt;
oldOptions = groupD.options;
@@ -1072,6 +1097,7 @@ static void GroupOk( void * junk )
}
/* Make sure no turnouts in groupTrk list have a path end which is not an EndPt */
+ //TODO Add Trap Points (which are Turnouts with a bumper track)
for ( inx=0; inx<groupTrk_da.cnt; inx++ ) {
trk = groupTrk(0).trk;
if ( GetTrkType( trk ) == T_TURNOUT ) {
@@ -1391,7 +1417,7 @@ if ( log_group >= 1 && logTable(log_group).level > log_group ) {
for ( pinx=0; pinx<trackSegs_da.cnt; pinx++ ) {
if ( segFlip(pinx) < 0 ) {
LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) );
- SegProc( SEGPROC_FLIP, &trackSegs(pinx), NULL );
+ SegProc( SEGPROC_FLIP, &trackSegs(pinx), NULL );
}
}
@@ -1413,7 +1439,7 @@ LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) );
if ( path == NULL )
AbortProg( "Missing Path T%d:%d.%d", GetTrkIndex(groupP->trk), ppp->ep2, ppp->ep1 );
if ( flip ) path += strlen((char *)path)-1;
- while ( *path ) {
+ while ( *path && (path >= ppp->path) ) { //Add Guard for flip backwards
DYNARR_APPEND( char, pathPtr_da, 10 );
pathChar = *path;
flip1 = flip;
@@ -1568,6 +1594,7 @@ EXPORT void DoGroup( void )
xx = NULL;
groupSegCnt = 0;
groupCompoundCount = 0;
+
while ( TrackIterate( &trk ) ) {
if ( GetTrkSelected( trk ) ) {
trkType = GetTrkType(trk);
@@ -1575,9 +1602,8 @@ EXPORT void DoGroup( void )
xx = GetTrkExtraData(trk);
groupSegCnt += xx->segCnt;
GroupCopyTitle( xtitle(xx) );
- } else {
+ } else
groupSegCnt += 1;
- }
}
}
if ( groupSegCnt <= 0 ) {
diff --git a/app/bin/chndldto.c b/app/bin/chndldto.c
index 2e1f826..fa88398 100644
--- a/app/bin/chndldto.c
+++ b/app/bin/chndldto.c
@@ -1,7 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/chndldto.c,v 1.4 2008-03-06 19:35:05 m_fischer Exp $
- *
- * CURVE
+/** \file chndlto.c
+ * Handlaid turnout
*
*/
@@ -23,13 +21,17 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <math.h>
+
#include "ccurve.h"
-#include "cstraigh.h"
#include "cjoin.h"
#include "compound.h"
-#include <math.h>
+#include "cstraigh.h"
+#include "cundo.h"
#include "i18n.h"
+#include "messages.h"
+#include "track.h"
+#include "utility.h"
#define PTRACE(X)
@@ -297,7 +299,7 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 ))
ep2b = 0;
break;
case SEG_CRVTRK:
- trk2b = NewCurvedTrack( segP->u.c.center, segP->u.c.radius, segP->u.c.a0, segP->u.c.a1, 0 );
+ trk2b = NewCurvedTrack( segP->u.c.center, fabs(segP->u.c.radius), segP->u.c.a0, segP->u.c.a1, 0 );
ep2b = (right?0:1);
}
if (trk2 == NULL) {
diff --git a/app/bin/chotbar.c b/app/bin/chotbar.c
index f138cbb..188ad27 100644
--- a/app/bin/chotbar.c
+++ b/app/bin/chotbar.c
@@ -21,10 +21,13 @@
*/
#include <ctype.h>
-#include "track.h"
-#include "compound.h"
-
#include <stdint.h>
+#include <string.h>
+
+#include "compound.h"
+#include "fileio.h"
+#include "messages.h"
+#include "track.h"
EXPORT DIST_T curBarScale = -1;
EXPORT long hotBarLabels = 0;
@@ -73,7 +76,7 @@ static void HotBarHighlight( int inx )
{
wPos_t x0;
if ( inx >= hotBarCurrStart && inx < hotBarCurrEnd ) {
- x0 = (wPos_t)((hotBarMap(inx).x-hotBarMap((int)hotBarCurrStart).x)*hotBarD.dpi+2);
+ x0 = (wPos_t)((hotBarMap(inx).x-hotBarMap((int)hotBarCurrStart).x)*hotBarD.dpi);
wDrawFilledRectangle( hotBarD.d, x0, 0, (wPos_t)(hotBarMap(inx).w*hotBarD.dpi-2), hotBarHeight, wDrawColorBlack, wDrawOptTemp );
}
}
@@ -101,30 +104,32 @@ static void RedrawHotBar( wDraw_p dd, void * data, wPos_t w, wPos_t h )
}
if ( hotBarLabels && !hotBarFp )
hotBarFp = wStandardFont( F_HELV, FALSE, FALSE );
+ wPos_t textSize = wMessageGetHeight(0L);
for ( inx=hotBarCurrStart; inx < hotBarMap_da.cnt; inx++ ) {
tbm = &hotBarMap(inx);
barScale = tbm->barScale;
- x = tbm->x - hotBarMap(hotBarCurrStart).x + 2.0/hotBarD.dpi;
+ x = tbm->x - hotBarMap(hotBarCurrStart).x;
if ( x + tbm->w > barWidth ) {
break;
}
orig.y = hh/2.0*barScale - tbm->size.y/2.0 - tbm->orig.y;
if ( hotBarLabels ) {
- orig.y += 8/hotBarD.dpi*barScale;
+ orig.y += textSize/hotBarD.dpi*barScale;
if ( tbm->labelW > tbm->objectW ) {
x += (tbm->labelW-tbm->objectW)/2;
}
}
x *= barScale;
- orig.x = x - tbm->orig.x;
+ orig.x = x;
hotBarD.scale = barScale;
hotBarD.size.x = barWidth*barScale;
hotBarD.size.y = barHeight*barScale;
tbm->proc( HB_DRAW, tbm->context, &hotBarD, &orig );
if ( hotBarLabels ) {
- orig.x = x - (tbm->labelW-tbm->objectW)/2*barScale;
- orig.y = 2*barScale/hotBarD.dpi;
- DrawString( &hotBarD, orig, 0.0, tbm->proc( HB_BARTITLE, tbm->context, NULL, NULL ), hotBarFp, hotBarFs*barScale, drawColorBlack );
+ hotBarD.scale = 1.0;
+ orig.x = tbm->x - hotBarMap(hotBarCurrStart).x;
+ orig.y = 2.0/hotBarD.dpi; //Draw Label under icon
+ DrawString( &hotBarD, orig, 0.0, tbm->proc( HB_BARTITLE, tbm->context, NULL, NULL ), hotBarFp, hotBarFs, drawColorBlack );
}
}
hotBarCurrEnd = inx;
@@ -220,7 +225,8 @@ static void SelectHotBar( wDraw_p d, void * context, wAction_t action, wPos_t w,
}
x = w/hotBarD.dpi + hotBarMap(hotBarCurrStart).x;
for ( inx=hotBarCurrStart; inx<hotBarCurrEnd; inx++ ) {
- if ( x < hotBarMap(inx).x + hotBarMap(inx).w ) {
+ if ((x >= hotBarMap(inx).x) && //leave spaces between buttons
+ (x <= hotBarMap(inx).x + hotBarMap(inx).w )) {
break;
}
}
@@ -231,7 +237,7 @@ static void SelectHotBar( wDraw_p d, void * context, wAction_t action, wPos_t w,
px += (wPos_t)(tbm->w*hotBarD.dpi/2);
titleP = tbm->proc( HB_LISTTITLE, tbm->context, NULL, NULL );
px -= wLabelWidth( titleP ) / 2;
- wControlSetBalloon( (wControl_p)hotBarD.d, px, -5, titleP );
+ wControlSetBalloon( (wControl_p)hotBarD.d, px, -20, titleP );
switch (action & 0xff) {
case wActionLDown:
pos.x = mainD.size.x+mainD.orig.x;
@@ -380,7 +386,7 @@ EXPORT void AddHotBarElement(
tbm->w = tbm->labelW;
}
}
- hotBarWidth += tbm->w;
+ hotBarWidth += tbm->w + 2/hotBarD.dpi;
}
@@ -440,8 +446,9 @@ EXPORT void LayoutHotBar( void )
wWinGetSize( mainW, &winWidth, &winHeight );
hotBarHeight = hotBarDrawHeight;
- if ( hotBarLabels)
- hotBarHeight += 8;
+ if ( hotBarLabels) {
+ hotBarHeight += wMessageGetHeight(0L);
+ }
if (hotBarLeftB == NULL) {
wIcon_p bm_p;
if (winWidth < 50)
@@ -450,18 +457,18 @@ EXPORT void LayoutHotBar( void )
hotBarLeftB = wButtonCreate( mainW, 0, 0, "hotBarLeft", (char*)bm_p, BO_ICON, 0, DoHotBarLeft, NULL );
bm_p = wIconCreateBitMap( 16, 16, turnbarr_bits, wDrawColorBlack );
hotBarRightB = wButtonCreate( mainW, 0, 0, "hotBarRight", (char*)bm_p, BO_ICON, 0, DoHotBarRight, NULL );
- hotBarD.d = wDrawCreate( mainW, 0, 0, NULL, BD_NOCAPTURE, 100, hotBarHeight, NULL, RedrawHotBar, SelectHotBar );
+ hotBarD.d = wDrawCreate( mainW, 0, 0, NULL, BD_NOCAPTURE|BD_NOFOCUS, 100, hotBarHeight, NULL, RedrawHotBar, SelectHotBar );
hotBarD.dpi = wDrawGetDPI( hotBarD.d );
hotBarD.scale = 1.0;
initialize = TRUE;
}
buttonWidth = wControlGetWidth((wControl_p)hotBarLeftB);
wControlSetPos( (wControl_p)hotBarLeftB, 0, toolbarHeight );
- wControlSetPos( (wControl_p)hotBarRightB, winWidth-buttonWidth, toolbarHeight );
+ wControlSetPos( (wControl_p)hotBarRightB, winWidth-20-buttonWidth, toolbarHeight );
wControlSetPos( (wControl_p)hotBarD.d, buttonWidth, toolbarHeight );
- wDrawSetSize( hotBarD.d, winWidth-buttonWidth*2, hotBarHeight+2 );
- hotBarD.size.x = ((double)(winWidth-buttonWidth*2))/hotBarD.dpi*hotBarD.scale;
- hotBarD.size.y = (double)hotBarHeight/hotBarD.dpi*hotBarD.scale;
+ wDrawSetSize( hotBarD.d, winWidth-20-buttonWidth*2, hotBarHeight+2 );
+ hotBarD.size.x = ((double)(winWidth-20-buttonWidth*2))/hotBarD.dpi*hotBarD.scale;
+ hotBarD.size.y = (double)hotBarDrawHeight/hotBarD.dpi*hotBarD.scale; //Exclude Label from calc
wControlShow( (wControl_p)hotBarLeftB, TRUE );
wControlShow( (wControl_p)hotBarRightB, TRUE );
wControlShow( (wControl_p)hotBarD.d, TRUE );
diff --git a/app/bin/cjoin.c b/app/bin/cjoin.c
index e8d72eb..8cfa3d4 100644
--- a/app/bin/cjoin.c
+++ b/app/bin/cjoin.c
@@ -29,7 +29,15 @@
#include "ccurve.h"
#include "cstraigh.h"
#include "cjoin.h"
+#include "ccornu.h"
#include "i18n.h"
+#include "utility.h"
+#include "math.h"
+#include "messages.h"
+#include "param.h"
+#include "cundo.h"
+#include "cselect.h"
+#include "fileio.h"
static int log_join = 0;
@@ -444,18 +452,25 @@ static STATUS_T CmdJoin(
DIST_T eR[2];
BOOL_T ok;
- switch (action) {
+ switch (action&0xFF) {
case C_START:
- InfoMessage( _("Left click - join with track, Shift Left click - move to join") );
+ if (selectedTrackCount==0)
+ InfoMessage( _("Left click - join with track") );
+ else
+ InfoMessage( _("Left click - join with track, Shift Left click - move to join") );
Dj.state = 0;
Dj.joinMoveState = 0;
/*ParamGroupRecord( &easementPG );*/
+ if (easementVal < 0)
+ return CmdCornu(action, pos);
return C_CONTINUE;
case C_DOWN:
if ( (Dj.state == 0 && (MyGetKeyState() & WKEY_SHIFT) != 0) || Dj.joinMoveState != 0 )
return DoMoveToJoin( pos );
+ if (easementVal < 0.0)
+ return CmdCornu(action, pos);
DYNARR_SET( trkSeg_t, tempSegs_da, 3 );
tempSegs(0).color = drawColorBlack;
@@ -545,6 +560,8 @@ LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
tempSegs_da.cnt = 0;
case C_MOVE:
+ if (easementVal < 0)
+ return CmdCornu(action, pos);
LOG( log_join, 3, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
if (Dj.state != 2)
@@ -580,6 +597,8 @@ LOG( log_join, 3, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
((Dj.inp[0].params.ep==0)?-90.0:90.0) );
break;
case curveTypeNone:
+ case curveTypeBezier:
+ case curveTypeCornu:
break;
}
@@ -655,6 +674,11 @@ LOG( log_join, 3, (" -E POS0=[%0.3f %0.3f] POS1=[%0.3f %0.3f]\n",
d = Dj.inp[0].params.arcR * a1 * 2.0*M_PI/360.0;
}
break;
+ case curveTypeCornu:
+ case curveTypeBezier:
+ case curveTypeNone:
+ InfoMessage( _("First Track Type not supported for non-Cornu Join") );
+ goto errorReturn;
default:
AbortProg( "cmdJoin - unknown type[0]" );
}
@@ -682,6 +706,11 @@ LOG( log_join, 3, (" -E POS0=[%0.3f %0.3f] POS1=[%0.3f %0.3f]\n",
d = Dj.inp[1].params.arcR * a1 * 2.0*M_PI/360.0;
}
break;
+ case curveTypeCornu:
+ case curveTypeBezier:
+ case curveTypeNone:
+ InfoMessage( _("Second Track Type not supported for non-Cornu Join") );
+ goto errorReturn;
default:
AbortProg( "cmdJoin - unknown type[1]" );
}
@@ -775,8 +804,13 @@ errorReturn:
return C_CONTINUE;
case C_UP:
- if (Dj.state == 0)
- return C_CONTINUE;
+
+ if (Dj.state == 0) {
+ if (easementVal<0)
+ return CmdCornu(action, pos);
+ else
+ return C_CONTINUE;
+ }
if (Dj.state == 1) {
InfoMessage( _("Select 2nd track") );
return C_CONTINUE;
@@ -801,6 +835,8 @@ errorReturn:
Dj.jRes.arcA0, Dj.jRes.arcA1, 0 );
break;
case curveTypeNone:
+ case curveTypeBezier:
+ case curveTypeCornu:
return C_CONTINUE;
}
@@ -822,65 +858,26 @@ errorReturn:
DrawNewTrack( trk );
return rc;
-#ifdef LATER
- case C_LCLICK:
- if ( (MyGetKeyState() & WKEY_SHIFT) == 0 ) {
- rc = CmdJoin( C_DOWN, pos );
- if (rc == C_TERMINATE)
- return rc;
- return CmdJoin( C_UP, pos );
- }
- if ( selectedTrackCount <= 0 ) {
- ErrorMessage( MSG_NO_SELECTED_TRK );
- return C_CONTINUE;
- }
- if ( (Dj.inp[Dj.joinMoveState].trk = OnTrack( &pos, TRUE, TRUE )) == NULL )
- return C_CONTINUE;
- if (!CheckTrackLayer( Dj.inp[Dj.joinMoveState].trk ) )
- return C_CONTINUE;
- Dj.inp[Dj.joinMoveState].params.ep = PickUnconnectedEndPoint( pos, Dj.inp[Dj.joinMoveState].trk ); /* CHECKME */
- if ( Dj.inp[Dj.joinMoveState].params.ep == -1 ) {
-#ifdef LATER
- ErrorMessage( MSG_NO_ENDPTS );
-#endif
- return C_CONTINUE;
- }
-#ifdef LATER
- if ( GetTrkEndTrk( Dj.inp[Dj.joinMoveState].trk, Dj.inp[Dj.joinMoveState].params.ep ) ) {
- ErrorMessage( MSG_SEL_EP_CONN );
- return C_CONTINUE;
- }
-#endif
- if (Dj.joinMoveState == 0) {
- Dj.joinMoveState++;
- InfoMessage( GetTrkSelected(Dj.inp[0].trk)?
- _("Click on an unselected End-Point"):
- _("Click on a selected End-Point") );
- return C_CONTINUE;
- }
- if ( GetTrkSelected(Dj.inp[0].trk) == GetTrkSelected(Dj.inp[1].trk) ) {
- ErrorMessage( MSG_2ND_TRK_NOT_SEL_UNSEL, GetTrkSelected(Dj.inp[0].trk)
- ? _("unselected") : _("selected") );
- return C_CONTINUE;
- }
- if (GetTrkSelected(Dj.inp[0].trk))
- MoveToJoin( Dj.inp[0].trk, Dj.inp[0].params.ep, Dj.inp[1].trk, Dj.inp[1].params.ep );
- else
- MoveToJoin( Dj.inp[1].trk, Dj.inp[1].params.ep, Dj.inp[0].trk, Dj.inp[0].params.ep );
- Dj.joinMoveState = 0;
- return C_TERMINATE;
- break;
-#endif
case C_CANCEL:
case C_REDRAW:
+
+
if ( Dj.joinMoveState == 1 || Dj.state == 1 ) {
DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
- }
+ } else if (easementVal<0 )
+ return CmdCornu(action,pos);
+
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
break;
+ case C_TEXT:
+ case C_OK:
+ if (easementVal<0 )
+ return CmdCornu(action,pos);
}
+
+
return C_CONTINUE;
}
diff --git a/app/bin/cjoin.h b/app/bin/cjoin.h
index 021e0a1..8d9c7e3 100644
--- a/app/bin/cjoin.h
+++ b/app/bin/cjoin.h
@@ -1,7 +1,6 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cjoin.h,v 1.1 2005-12-07 15:47:39 rc-flyer Exp $
+/** \file cjoin.h
+ * Prototypes and definitions related to the "join" command
*/
-
/* XTrkCad - Model Railroad CAD
* Copyright (C) 2005 Dave Bullis
*
@@ -20,6 +19,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef HAVE_CJOIN_H
+#define HAVE_CJOIN_H
+
+#include "common.h"
+#include "wlib.h"
+#include "track.h"
+
#define E_NOTREQ (0)
#define E_REQ (1)
#define E_ERROR (2)
@@ -42,3 +48,6 @@ void UndoJoint( track_p, EPINX_T, track_p, EPINX_T );
void DrawJointTrack( drawCmd_p, coOrd, ANGLE_T, DIST_T, DIST_T, DIST_T, DIST_T, BOOL_T, BOOL_T, BOOL_T, track_p, EPINX_T, EPINX_T, DIST_T, wDrawColor, long );
DIST_T JointDistance( coOrd *, coOrd, ANGLE_T, DIST_T, DIST_T, DIST_T, DIST_T, BOOL_T, BOOL_T );
coOrd GetJointSegEndPos( coOrd, ANGLE_T, DIST_T, DIST_T, DIST_T, DIST_T, BOOL_T, BOOL_T, BOOL_T, EPINX_T, ANGLE_T * );
+
+#endif // !HAVE_CJOIN_H
+
diff --git a/app/bin/cmisc.c b/app/bin/cmisc.c
index 1e2ea39..227a7d0 100644
--- a/app/bin/cmisc.c
+++ b/app/bin/cmisc.c
@@ -20,16 +20,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <stdint.h>
+
#include "common.h"
+#include "cundo.h"
#include "i18n.h"
-
-/*****************************************************************************
- *
- * DESCRIPTION WINDOW
- *
- */
-
+#include "messages.h"
+#include "param.h"
+#include "track.h"
EXPORT wIndex_t describeCmdInx;
EXPORT BOOL_T inDescribeCmd;
@@ -45,6 +43,8 @@ static BOOL_T descNeedDrawHilite;
static wPos_t describeW_posy;
static wPos_t describeCmdButtonEnd;
+static unsigned int editableLayerList[NUM_LAYERS]; /**< list of non-frozen layers */
+static int * layerValue; /**pointer to current Layer (int *) */
static paramFloatRange_t rdata = { 0, 0, 100, PDO_NORANGECHECK_HIGH|PDO_NORANGECHECK_LOW };
static paramIntegerRange_t idata = { 0, 0, 100, PDO_NORANGECHECK_HIGH|PDO_NORANGECHECK_LOW };
@@ -52,225 +52,339 @@ static paramTextData_t tdata = { 300, 150 };
static char * pivotLabels[] = { N_("First"), N_("Middle"), N_("Second"), NULL };
static paramData_t describePLs[] = {
#define I_FLOAT_0 (0)
- { PD_FLOAT, NULL, "F1", 0, &rdata },
- { PD_FLOAT, NULL, "F2", 0, &rdata },
- { PD_FLOAT, NULL, "F3", 0, &rdata },
- { PD_FLOAT, NULL, "F4", 0, &rdata },
- { PD_FLOAT, NULL, "F5", 0, &rdata },
- { PD_FLOAT, NULL, "F6", 0, &rdata },
- { PD_FLOAT, NULL, "F7", 0, &rdata },
- { PD_FLOAT, NULL, "F8", 0, &rdata },
- { PD_FLOAT, NULL, "F9", 0, &rdata },
- { PD_FLOAT, NULL, "F10", 0, &rdata },
- { PD_FLOAT, NULL, "F11", 0, &rdata },
- { PD_FLOAT, NULL, "F12", 0, &rdata },
- { PD_FLOAT, NULL, "F13", 0, &rdata },
- { PD_FLOAT, NULL, "F14", 0, &rdata },
- { PD_FLOAT, NULL, "F15", 0, &rdata },
- { PD_FLOAT, NULL, "F16", 0, &rdata },
- { PD_FLOAT, NULL, "F17", 0, &rdata },
- { PD_FLOAT, NULL, "F18", 0, &rdata },
- { PD_FLOAT, NULL, "F19", 0, &rdata },
- { PD_FLOAT, NULL, "F20", 0, &rdata },
-#define I_FLOAT_N I_FLOAT_0+20
+ { PD_FLOAT, NULL, "F1", 0, &rdata },
+ { PD_FLOAT, NULL, "F2", 0, &rdata },
+ { PD_FLOAT, NULL, "F3", 0, &rdata },
+ { PD_FLOAT, NULL, "F4", 0, &rdata },
+ { PD_FLOAT, NULL, "F5", 0, &rdata },
+ { PD_FLOAT, NULL, "F6", 0, &rdata },
+ { PD_FLOAT, NULL, "F7", 0, &rdata },
+ { PD_FLOAT, NULL, "F8", 0, &rdata },
+ { PD_FLOAT, NULL, "F9", 0, &rdata },
+ { PD_FLOAT, NULL, "F10", 0, &rdata },
+ { PD_FLOAT, NULL, "F11", 0, &rdata },
+ { PD_FLOAT, NULL, "F12", 0, &rdata },
+ { PD_FLOAT, NULL, "F13", 0, &rdata },
+ { PD_FLOAT, NULL, "F14", 0, &rdata },
+ { PD_FLOAT, NULL, "F15", 0, &rdata },
+ { PD_FLOAT, NULL, "F16", 0, &rdata },
+ { PD_FLOAT, NULL, "F17", 0, &rdata },
+ { PD_FLOAT, NULL, "F18", 0, &rdata },
+ { PD_FLOAT, NULL, "F19", 0, &rdata },
+ { PD_FLOAT, NULL, "F20", 0, &rdata },
+ { PD_FLOAT, NULL, "F21", 0, &rdata },
+ { PD_FLOAT, NULL, "F22", 0, &rdata },
+ { PD_FLOAT, NULL, "F23", 0, &rdata },
+ { PD_FLOAT, NULL, "F24", 0, &rdata },
+ { PD_FLOAT, NULL, "F25", 0, &rdata },
+ { PD_FLOAT, NULL, "F26", 0, &rdata },
+ { PD_FLOAT, NULL, "F27", 0, &rdata },
+ { PD_FLOAT, NULL, "F28", 0, &rdata },
+ { PD_FLOAT, NULL, "F29", 0, &rdata },
+ { PD_FLOAT, NULL, "F30", 0, &rdata },
+ { PD_FLOAT, NULL, "F31", 0, &rdata },
+ { PD_FLOAT, NULL, "F32", 0, &rdata },
+ { PD_FLOAT, NULL, "F33", 0, &rdata },
+ { PD_FLOAT, NULL, "F34", 0, &rdata },
+ { PD_FLOAT, NULL, "F35", 0, &rdata },
+ { PD_FLOAT, NULL, "F36", 0, &rdata },
+ { PD_FLOAT, NULL, "F37", 0, &rdata },
+ { PD_FLOAT, NULL, "F38", 0, &rdata },
+ { PD_FLOAT, NULL, "F39", 0, &rdata },
+ { PD_FLOAT, NULL, "F40", 0, &rdata },
+#define I_FLOAT_N I_FLOAT_0+40
#define I_LONG_0 I_FLOAT_N
- { PD_LONG, NULL, "I1", 0, &idata },
- { PD_LONG, NULL, "I2", 0, &idata },
- { PD_LONG, NULL, "I3", 0, &idata },
- { PD_LONG, NULL, "I4", 0, &idata },
- { PD_LONG, NULL, "I5", 0, &idata },
+ { PD_LONG, NULL, "I1", 0, &idata },
+ { PD_LONG, NULL, "I2", 0, &idata },
+ { PD_LONG, NULL, "I3", 0, &idata },
+ { PD_LONG, NULL, "I4", 0, &idata },
+ { PD_LONG, NULL, "I5", 0, &idata },
#define I_LONG_N I_LONG_0+5
#define I_STRING_0 I_LONG_N
- { PD_STRING, NULL, "S1", 0, (void*)300 },
- { PD_STRING, NULL, "S2", 0, (void*)300 },
- { PD_STRING, NULL, "S3", 0, (void*)300 },
- { PD_STRING, NULL, "S4", 0, (void*)300 },
+ { PD_STRING, NULL, "S1", 0, (void*)300 },
+ { PD_STRING, NULL, "S2", 0, (void*)300 },
+ { PD_STRING, NULL, "S3", 0, (void*)300 },
+ { PD_STRING, NULL, "S4", 0, (void*)300 },
#define I_STRING_N I_STRING_0+4
#define I_LAYER_0 I_STRING_N
- { PD_DROPLIST, NULL, "Y1", 0, (void*)150, NULL, 0 },
+ { PD_DROPLIST, NULL, "Y1", 0, (void*)150, NULL, 0 },
#define I_LAYER_N I_LAYER_0+1
#define I_COLOR_0 I_LAYER_N
- { PD_COLORLIST, NULL, "C1", 0, NULL, N_("Color") },
+ { PD_COLORLIST, NULL, "C1", 0, NULL, N_("Color") },
#define I_COLOR_N I_COLOR_0+1
#define I_LIST_0 I_COLOR_N
- { PD_DROPLIST, NULL, "L1", 0, (void*)150, NULL, 0 },
- { PD_DROPLIST, NULL, "L2", 0, (void*)150, NULL, 0 },
+ { PD_DROPLIST, NULL, "L1", 0, (void*)150, NULL, 0 },
+ { PD_DROPLIST, NULL, "L2", 0, (void*)150, NULL, 0 },
#define I_LIST_N I_LIST_0+2
#define I_EDITLIST_0 I_LIST_N
- { PD_DROPLIST, NULL, "LE1", 0, (void*)150, NULL, BL_EDITABLE },
+ { PD_DROPLIST, NULL, "LE1", 0, (void*)150, NULL, BL_EDITABLE },
#define I_EDITLIST_N I_EDITLIST_0+1
#define I_TEXT_0 I_EDITLIST_N
- { PD_TEXT, NULL, "T1", 0, &tdata },
+ { PD_TEXT, NULL, "T1", 0, &tdata },
#define I_TEXT_N I_TEXT_0+1
#define I_PIVOT_0 I_TEXT_N
- { PD_RADIO, NULL, "P1", 0, pivotLabels, N_("Pivot"), BC_HORZ|BC_NOBORDER, 0 }
+ { PD_RADIO, NULL, "P1", 0, pivotLabels, N_("Pivot"), BC_HORZ|BC_NOBORDER, 0 }
#define I_PIVOT_N I_PIVOT_0+1
- };
+};
static paramGroup_t describePG = { "describe", 0, describePLs, sizeof describePLs/sizeof describePLs[0] };
+/**
+ * A mapping table is used to map the index in the dropdown list to the layer
+ * number. While usually this is a 1:1 translation, the values differ if there
+ * are frozen layer. Frozen layers are not shown in the dropdown list.
+ */
+
+void
+CreateEditableLayersList()
+{
+ int i = 0;
+ int j = 0;
+
+ while (i <= NUM_LAYERS) {
+ if (!GetLayerFrozen(i)) {
+ editableLayerList[j++] = i;
+ }
+
+ i++;
+ }
+}
+
+/**
+ * Search a layer in the list of editable layers.
+ *
+ * \param IN layer layer to search
+ * \return the index into the list
+ */
+
+static int
+SearchEditableLayerList(unsigned int layer)
+{
+ int i;
+
+ for (i = 0; i < NUM_LAYERS; i++) {
+ if (editableLayerList[i] == layer) {
+ return (i);
+ }
+ }
-static void DrawDescHilite( void )
+ return (-1);
+}
+
+static void DrawDescHilite(void)
{
- wPos_t x, y, w, h;
- if ( descNeedDrawHilite == FALSE )
- return;
- if (descColor==0)
- descColor = wDrawColorGray(87);
- w = (wPos_t)((descSize.x/mainD.scale)*mainD.dpi+0.5);
- h = (wPos_t)((descSize.y/mainD.scale)*mainD.dpi+0.5);
- mainD.CoOrd2Pix(&mainD,descOrig,&x,&y);
- wDrawFilledRectangle( mainD.d, x, y, w, h, descColor, wDrawOptTemp );
+ wPos_t x, y, w, h;
+
+ if (descNeedDrawHilite == FALSE) {
+ return;
+ }
+
+ if (descColor==0) {
+ descColor = wDrawColorGray(87);
+ }
+
+ w = (wPos_t)((descSize.x/mainD.scale)*mainD.dpi+0.5);
+ h = (wPos_t)((descSize.y/mainD.scale)*mainD.dpi+0.5);
+ mainD.CoOrd2Pix(&mainD,descOrig,&x,&y);
+ wDrawFilledRectangle(mainD.d, x, y, w, h, descColor, wDrawOptTemp);
}
static void DescribeUpdate(
- paramGroup_p pg,
- int inx,
- void * data )
+ paramGroup_p pg,
+ int inx,
+ void * data)
{
- coOrd hi, lo;
- descData_p ddp;
- if ( inx < 0 )
- return;
- ddp = (descData_p)pg->paramPtr[inx].context;
- if ( (ddp->mode&(DESC_RO|DESC_IGNORE)) != 0 )
- return;
- if ( ddp->type == DESC_PIVOT )
- return;
- if ( (ddp->mode&DESC_NOREDRAW) == 0 )
- DrawDescHilite();
- if ( !descUndoStarted ) {
- UndoStart( _("Change Track"), "Change Track" );
- descUndoStarted = TRUE;
- }
- if (!descTrk) return; // In case timer pops after OK
- UndoModify( descTrk );
- descUpdateFunc( descTrk, ddp-descData, descData, FALSE );
- if ( descTrk ) {
- GetBoundingBox( descTrk, &hi, &lo );
- if ( OFF_D( mapD.orig, mapD.size, descOrig, descSize ) ) {
- ErrorMessage( MSG_MOVE_OUT_OF_BOUNDS );
- }
- }
- if ( (ddp->mode&DESC_NOREDRAW) == 0 ) {
- descOrig = lo;
- descSize = hi;
- descOrig.x -= descBorder;
- descOrig.y -= descBorder;
- descSize.x -= descOrig.x-descBorder;
- descSize.y -= descOrig.y-descBorder;
- DrawDescHilite();
- }
- for ( inx = 0; inx < sizeof describePLs/sizeof describePLs[0]; inx++ ) {
- if ( (describePLs[inx].option & PDO_DLGIGNORE) != 0 )
- continue;
- ddp = (descData_p)describePLs[inx].context;
- if ( (ddp->mode&DESC_IGNORE) != 0 )
- continue;
- if ( (ddp->mode&DESC_CHANGE) == 0 )
- continue;
- ddp->mode &= ~DESC_CHANGE;
- ParamLoadControl( &describePG, inx );
- }
+ coOrd hi, lo;
+ descData_p ddp;
+
+ if (inx < 0) {
+ return;
+ }
+
+ ddp = (descData_p)pg->paramPtr[inx].context;
+
+ if ((ddp->mode&(DESC_RO|DESC_IGNORE)) != 0) {
+ return;
+ }
+
+ if (ddp->type == DESC_PIVOT) {
+ return;
+ }
+
+ if ((ddp->mode&DESC_NOREDRAW) == 0) {
+ DrawDescHilite();
+ }
+
+ if (!descUndoStarted) {
+ UndoStart(_("Change Track"), "Change Track");
+ descUndoStarted = TRUE;
+ }
+
+ if (!descTrk) {
+ return; // In case timer pops after OK
+ }
+
+ UndoModify(descTrk);
+ descUpdateFunc(descTrk, ddp-descData, descData, FALSE);
+
+ if (descTrk) {
+ GetBoundingBox(descTrk, &hi, &lo);
+
+ if (OFF_D(mapD.orig, mapD.size, descOrig, descSize)) {
+ ErrorMessage(MSG_MOVE_OUT_OF_BOUNDS);
+ }
+ }
+
+ if ((ddp->mode&DESC_NOREDRAW) == 0) {
+ descOrig = lo;
+ descSize = hi;
+ descOrig.x -= descBorder;
+ descOrig.y -= descBorder;
+ descSize.x -= descOrig.x-descBorder;
+ descSize.y -= descOrig.y-descBorder;
+ DrawDescHilite();
+ }
+
+ for (inx = 0; inx < sizeof describePLs/sizeof describePLs[0]; inx++) {
+ if ((describePLs[inx].option & PDO_DLGIGNORE) != 0) {
+ continue;
+ }
+
+ ddp = (descData_p)describePLs[inx].context;
+
+ if ((ddp->mode&DESC_IGNORE) != 0) {
+ continue;
+ }
+
+ if ((ddp->mode&DESC_CHANGE) == 0) {
+ continue;
+ }
+
+ ddp->mode &= ~DESC_CHANGE;
+ ParamLoadControl(&describePG, inx);
+ }
}
-static void DescOk( void * junk )
+static void DescOk(void * junk)
{
- wHide( describePG.win );
- if ( descTrk )
- DrawDescHilite();
-
- descUpdateFunc( descTrk, -1, descData, !descUndoStarted );
- descTrk = NULL;
- if (descUndoStarted) {
- UndoEnd();
- descUndoStarted = FALSE;
- }
- descNeedDrawHilite = FALSE;
- Reset();
+ wHide(describePG.win);
+
+ if (descTrk) {
+ DrawDescHilite();
+ }
+ if (layerValue && *layerValue>=0) {
+ SetTrkLayer(descTrk, editableLayerList[*layerValue]); //int found that is really in the parm controls.
+ }
+ layerValue = NULL; // wipe out reference
+ descUpdateFunc(descTrk, -1, descData, !descUndoStarted);
+ descTrk = NULL;
+
+ if (descUndoStarted) {
+ UndoEnd();
+ descUndoStarted = FALSE;
+ }
+
+ descNeedDrawHilite = FALSE;
+ Reset();
}
static struct {
- parameterType pd_type;
- long option;
- int first;
- int last;
- } descTypeMap[] = {
-/*NULL*/ { 0, 0 },
-/*POS*/ { PD_FLOAT, PDO_DIM, I_FLOAT_0, I_FLOAT_N },
-/*FLOAT*/ { PD_FLOAT, 0, I_FLOAT_0, I_FLOAT_N },
-/*ANGLE*/ { PD_FLOAT, PDO_ANGLE, I_FLOAT_0, I_FLOAT_N },
-/*LONG*/ { PD_LONG, 0, I_LONG_0, I_LONG_N },
-/*COLOR*/ { PD_LONG, 0, I_COLOR_0, I_COLOR_N },
-/*DIM*/ { PD_FLOAT, PDO_DIM, I_FLOAT_0, I_FLOAT_N },
-/*PIVOT*/ { PD_RADIO, 0, I_PIVOT_0, I_PIVOT_N },
-/*LAYER*/ { PD_DROPLIST,PDO_LISTINDEX, I_LAYER_0, I_LAYER_N },
-/*STRING*/ { PD_STRING,0, I_STRING_0, I_STRING_N },
-/*TEXT*/ { PD_TEXT, PDO_DLGNOLABELALIGN, I_TEXT_0, I_TEXT_N },
-/*LIST*/ { PD_DROPLIST, PDO_LISTINDEX, I_LIST_0, I_LIST_N },
-/*EDITABLELIST*/{ PD_DROPLIST, 0, I_EDITLIST_0, I_EDITLIST_N } };
-
-static wControl_p AllocateButt( descData_p ddp, void * valueP, char * label, wPos_t sep )
+ parameterType pd_type;
+ long option;
+ int first;
+ int last;
+} descTypeMap[] = {
+ /*NULL*/ { 0, 0 },
+ /*POS*/ { PD_FLOAT, PDO_DIM, I_FLOAT_0, I_FLOAT_N },
+ /*FLOAT*/ { PD_FLOAT, 0, I_FLOAT_0, I_FLOAT_N },
+ /*ANGLE*/ { PD_FLOAT, PDO_ANGLE, I_FLOAT_0, I_FLOAT_N },
+ /*LONG*/ { PD_LONG, 0, I_LONG_0, I_LONG_N },
+ /*COLOR*/ { PD_LONG, 0, I_COLOR_0, I_COLOR_N },
+ /*DIM*/ { PD_FLOAT, PDO_DIM, I_FLOAT_0, I_FLOAT_N },
+ /*PIVOT*/ { PD_RADIO, 0, I_PIVOT_0, I_PIVOT_N },
+ /*LAYER*/ { PD_DROPLIST,PDO_LISTINDEX, I_LAYER_0, I_LAYER_N },
+ /*STRING*/ { PD_STRING,0, I_STRING_0, I_STRING_N },
+ /*TEXT*/ { PD_TEXT, PDO_DLGNOLABELALIGN, I_TEXT_0, I_TEXT_N },
+ /*LIST*/ { PD_DROPLIST, PDO_LISTINDEX, I_LIST_0, I_LIST_N },
+ /*EDITABLELIST*/{ PD_DROPLIST, 0, I_EDITLIST_0, I_EDITLIST_N }
+};
+
+static wControl_p AllocateButt(descData_p ddp, void * valueP, char * label,
+ wPos_t sep)
{
- int inx;
-
- for ( inx = descTypeMap[ddp->type].first; inx<descTypeMap[ddp->type].last; inx++ ) {
- if ( (describePLs[inx].option & PDO_DLGIGNORE) != 0 ) {
- describePLs[inx].option = descTypeMap[ddp->type].option;
- if ( describeW_posy > describeCmdButtonEnd )
- describePLs[inx].option |= PDO_DLGUNDERCMDBUTT;
- describeW_posy += wControlGetHeight( describePLs[inx].control ) + sep;
- describePLs[inx].context = ddp;
- describePLs[inx].valueP = valueP;
- if ( label && ddp->type != DESC_TEXT ) {
- wControlSetLabel( describePLs[inx].control, label );
- describePLs[inx].winLabel = label;
- }
- return describePLs[inx].control;
- }
- }
- AbortProg( "allocateButt: can't find %d", ddp->type );
- return NULL;
+ int inx;
+
+ for (inx = descTypeMap[ddp->type].first; inx<descTypeMap[ddp->type].last;
+ inx++) {
+ if ((describePLs[inx].option & PDO_DLGIGNORE) != 0) {
+ describePLs[inx].option = descTypeMap[ddp->type].option;
+
+ if (describeW_posy > describeCmdButtonEnd) {
+ describePLs[inx].option |= PDO_DLGUNDERCMDBUTT;
+ }
+
+ if (sep)
+ describeW_posy += wControlGetHeight(describePLs[inx].control) + sep;
+ describePLs[inx].context = ddp;
+ describePLs[inx].valueP = valueP;
+
+ if (label && ddp->type != DESC_TEXT) {
+ wControlSetLabel(describePLs[inx].control, label);
+ describePLs[inx].winLabel = label;
+ }
+
+ return describePLs[inx].control;
+ }
+ }
+
+ AbortProg("allocateButt: can't find %d", ddp->type);
+ return NULL;
}
static void DescribeLayout(
- paramData_t * pd,
- int inx,
- wPos_t colX,
- wPos_t * x,
- wPos_t * y )
+ paramData_t * pd,
+ int inx,
+ wPos_t colX,
+ wPos_t * x,
+ wPos_t * y)
{
- descData_p ddp;
- wPos_t w, h;
-
- if ( inx < 0 )
- return;
- if ( pd->context == NULL )
- return;
- ddp = (descData_p)pd->context;
- *y = ddp->posy;
- if ( ddp->type == DESC_POS &&
- ddp->control0 != pd->control ) {
- *y += wControlGetHeight( pd->control ) + 3;
- } else if ( ddp->type == DESC_TEXT ) {
- w = tdata.width;
- h = tdata.height;
- wTextSetSize( (wText_p)pd->control, w, h );
- }
- wControlShow( pd->control, TRUE );
+ descData_p ddp;
+ wPos_t w, h;
+
+ if (inx < 0) {
+ return;
+ }
+
+ if (pd->context == NULL) {
+ return;
+ }
+
+ ddp = (descData_p)pd->context;
+ *y = ddp->posy;
+
+ if (ddp->type == DESC_POS &&
+ ddp->control0 != pd->control) {
+ *x += wControlGetWidth(pd->control) + 3;
+ } else if (ddp->type == DESC_TEXT) {
+ w = tdata.width;
+ h = tdata.height;
+ wTextSetSize((wText_p)pd->control, w, h);
+ }
+
+ wControlShow(pd->control, TRUE);
}
@@ -278,89 +392,109 @@ static void DescribeLayout(
* Creation and modification of the Describe dialog box is handled here. As the number
* of values for a track element depends on the specific type, this dialog is dynamically
* updated to hsow the changable parameters only
- *
+ *
* \param IN title Description of the selected part, shown in window title bar
* \param IN trk Track element to be described
* \param IN data
* \param IN update
*
*/
+
static wList_p setLayerL;
-void DoDescribe( char * title, track_p trk, descData_p data, descUpdate_t update )
+void DoDescribe(char * title, track_p trk, descData_p data, descUpdate_t update)
{
- int inx;
- descData_p ddp;
- char * label;
- int ro_mode;
-
- if (!inDescribeCmd)
- return;
-
- descTrk = trk;
- descData = data;
- descUpdateFunc = update;
- describeW_posy = 0;
- if ( describePG.win == NULL ) {
- /* SDB 5.13.2005 */
- ParamCreateDialog( &describePG, _("Description"), _("Done"), DescOk,
- (paramActionCancelProc) DescribeCancel,
- TRUE, DescribeLayout, F_RECALLPOS,
- DescribeUpdate );
- describeCmdButtonEnd = wControlBelow( (wControl_p)describePG.helpB );
- }
- for ( inx=0; inx<sizeof describePLs/sizeof describePLs[0]; inx++ ) {
- describePLs[inx].option = PDO_DLGIGNORE;
- wControlShow( describePLs[inx].control, FALSE );
- }
- ro_mode = (GetLayerFrozen(GetTrkLayer(trk))?DESC_RO:0);
- if (ro_mode)
- for ( ddp=data; ddp->type != DESC_NULL; ddp++ ) {
- if ( ddp->mode&DESC_IGNORE )
- continue;
- ddp->mode |= ro_mode;
- }
- for ( ddp=data; ddp->type != DESC_NULL; ddp++ ) {
- if ( ddp->mode&DESC_IGNORE )
- continue;
- label = _(ddp->label);
-
- ddp->posy = describeW_posy;
- ddp->control0 = AllocateButt( ddp, ddp->valueP, label, (ddp->type == DESC_POS?3:3) );
- wControlActive( ddp->control0, ((ddp->mode|ro_mode)&DESC_RO)==0 );
- switch (ddp->type) {
- case DESC_POS:
- ddp->control1 = AllocateButt( ddp,
- &((coOrd*)(ddp->valueP))->y,
- "Y",
- 3 );
- wControlActive( ddp->control1, ((ddp->mode|ro_mode)&DESC_RO)==0 );
- break;
- case DESC_LAYER:
- wListClear((wList_p)ddp->control0); // Rebuild list on each invovation
- for ( inx = 0; inx<NUM_LAYERS; inx++ ) {
- if (!GetLayerFrozen(inx)) // Avoid Frozen layers.
- {
- sprintf( message, "%2d : %s", inx+1, GetLayerName(inx) );
- wListAddValue( (wList_p)ddp->control0, message, NULL, (void*)(intptr_t)inx );
- }
- }
- break;
- default:
- break;
- }
- }
- ParamLayoutDialog( &describePG );
- ParamLoadControls( &describePG );
- sprintf( message, "%s (T%d)", title, GetTrkIndex(trk) );
- wWinSetTitle( describePG.win, message );
- wShow( describePG.win );
+ int inx;
+ descData_p ddp;
+ char * label;
+ int ro_mode;
+
+ if (!inDescribeCmd) {
+ return;
+ }
+
+ CreateEditableLayersList();
+ descTrk = trk;
+ descData = data;
+ descUpdateFunc = update;
+ describeW_posy = 0;
+
+ if (describePG.win == NULL) {
+ /* SDB 5.13.2005 */
+ ParamCreateDialog(&describePG, _("Description"), _("Done"), DescOk,
+ (paramActionCancelProc) DescribeCancel,
+ TRUE, DescribeLayout, F_RECALLPOS,
+ DescribeUpdate);
+ describeCmdButtonEnd = wControlBelow((wControl_p)describePG.helpB);
+ }
+
+ for (inx=0; inx<sizeof describePLs/sizeof describePLs[0]; inx++) {
+ describePLs[inx].option = PDO_DLGIGNORE;
+ wControlShow(describePLs[inx].control, FALSE);
+ }
+
+ ro_mode = (GetLayerFrozen(GetTrkLayer(trk))?DESC_RO:0);
+
+ if (ro_mode)
+ for (ddp=data; ddp->type != DESC_NULL; ddp++) {
+ if (ddp->mode&DESC_IGNORE) {
+ continue;
+ }
+
+ ddp->mode |= ro_mode;
+ }
+
+ for (ddp=data; ddp->type != DESC_NULL; ddp++) {
+ if (ddp->mode&DESC_IGNORE) {
+ continue;
+ }
+
+ label = _(ddp->label);
+ ddp->posy = describeW_posy;
+ ddp->control0 = AllocateButt(ddp, ddp->valueP, label,
+ (ddp->type == DESC_POS?3:3));
+ wControlActive(ddp->control0, ((ddp->mode|ro_mode)&DESC_RO)==0);
+
+ switch (ddp->type) {
+ case DESC_POS:
+ ddp->control1 = AllocateButt(ddp,
+ &((coOrd*)(ddp->valueP))->y,
+ NULL,
+ 0);
+ wControlActive(ddp->control1, ((ddp->mode|ro_mode)&DESC_RO)==0);
+ break;
+
+ case DESC_LAYER:
+ wListClear((wList_p)ddp->control0); // Rebuild list on each invovation
+
+ for (inx = 0; inx<NUM_LAYERS; inx++) {
+ char *layerFormattedName;
+ layerFormattedName = FormatLayerName(editableLayerList[inx]);
+ wListAddValue((wList_p)ddp->control0, layerFormattedName, NULL, (void*)(long)inx);
+ free(layerFormattedName);
+ }
+
+ *(int *)(ddp->valueP) = SearchEditableLayerList(*(int *)(ddp->valueP));
+ layerValue = (int *)(ddp->valueP);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ ParamLayoutDialog(&describePG);
+ ParamLoadControls(&describePG);
+ sprintf(message, "%s (T%d)", title, GetTrkIndex(trk));
+ wWinSetTitle(describePG.win, message);
+ wShow(describePG.win);
}
-static void DescChange( long changes )
+static void DescChange(long changes)
{
- if ( (changes&CHANGE_UNITS) && describePG.win && wWinIsVisible(describePG.win) )
- ParamLoadControls( &describePG );
+ if ((changes&CHANGE_UNITS) && describePG.win && wWinIsVisible(describePG.win)) {
+ ParamLoadControls(&describePG);
+ }
}
/*****************************************************************************
@@ -370,81 +504,93 @@ static void DescChange( long changes )
*/
-EXPORT void DescribeCancel( void )
+EXPORT void DescribeCancel(void)
{
- if ( describePG.win && wWinIsVisible(describePG.win) ) {
- if ( descTrk ) {
- descUpdateFunc( descTrk, -1, descData, TRUE );
- descTrk = NULL;
- DrawDescHilite();
- }
- wHide( describePG.win );
- if ( descUndoStarted ) {
- UndoEnd();
- descUndoStarted = FALSE;
- }
- }
- descNeedDrawHilite = FALSE;
+ if (describePG.win && wWinIsVisible(describePG.win)) {
+ if (descTrk) {
+ descUpdateFunc(descTrk, -1, descData, TRUE);
+ descTrk = NULL;
+ DrawDescHilite();
+ }
+
+ wHide(describePG.win);
+
+ if (descUndoStarted) {
+ UndoEnd();
+ descUndoStarted = FALSE;
+ }
+ }
+
+ descNeedDrawHilite = FALSE;
}
-static STATUS_T CmdDescribe( wAction_t action, coOrd pos )
+static STATUS_T CmdDescribe(wAction_t action, coOrd pos)
{
- track_p trk;
- char msg[STR_SIZE];
-
- switch (action) {
- case C_START:
- InfoMessage( _("Select track to describe") );
- descUndoStarted = FALSE;
- return C_CONTINUE;
-
- case C_DOWN:
- if ((trk = OnTrack( &pos, FALSE, FALSE )) != NULL) {
- if ( describePG.win && wWinIsVisible(describePG.win) && descTrk ) {
- DrawDescHilite();
- descUpdateFunc( descTrk, -1, descData, TRUE );
- descTrk = NULL;
- }
- descBorder = mainD.scale*0.1;
- if ( descBorder < trackGauge )
- descBorder = trackGauge;
- inDescribeCmd = TRUE;
- GetBoundingBox( trk, &descSize, &descOrig );
- descOrig.x -= descBorder;
- descOrig.y -= descBorder;
- descSize.x -= descOrig.x-descBorder;
- descSize.y -= descOrig.y-descBorder;
- descNeedDrawHilite = TRUE;
- DrawDescHilite();
- DescribeTrack( trk, msg, 255 );
- inDescribeCmd = FALSE;
- InfoMessage( msg );
- } else
- InfoMessage( "" );
- return C_CONTINUE;
-
- case C_REDRAW:
- if (describePG.win && wWinIsVisible(describePG.win) && descTrk)
- DrawDescHilite();
- break;
-
- case C_CANCEL:
- DescribeCancel();
- return C_CONTINUE;
- }
- return C_CONTINUE;
+ track_p trk;
+ char msg[STR_SIZE];
+
+ switch (action) {
+ case C_START:
+ InfoMessage(_("Select track to describe"));
+ descUndoStarted = FALSE;
+ return C_CONTINUE;
+
+ case C_DOWN:
+ if ((trk = OnTrack(&pos, FALSE, FALSE)) != NULL) {
+ if (describePG.win && wWinIsVisible(describePG.win) && descTrk) {
+ DrawDescHilite();
+ descUpdateFunc(descTrk, -1, descData, TRUE);
+ descTrk = NULL;
+ }
+
+ descBorder = mainD.scale*0.1;
+
+ if (descBorder < trackGauge) {
+ descBorder = trackGauge;
+ }
+
+ inDescribeCmd = TRUE;
+ GetBoundingBox(trk, &descSize, &descOrig);
+ descOrig.x -= descBorder;
+ descOrig.y -= descBorder;
+ descSize.x -= descOrig.x-descBorder;
+ descSize.y -= descOrig.y-descBorder;
+ descNeedDrawHilite = TRUE;
+ DrawDescHilite();
+ DescribeTrack(trk, msg, 255);
+ inDescribeCmd = FALSE;
+ InfoMessage(msg);
+ } else {
+ InfoMessage("");
+ }
+
+ return C_CONTINUE;
+
+ case C_REDRAW:
+ if (describePG.win && wWinIsVisible(describePG.win) && descTrk) {
+ DrawDescHilite();
+ }
+
+ break;
+
+ case C_CANCEL:
+ DescribeCancel();
+ return C_CONTINUE;
+ }
+
+ return C_CONTINUE;
}
#include "bitmaps/describe.xpm"
-void InitCmdDescribe( wMenu_p menu )
+void InitCmdDescribe(wMenu_p menu)
{
- describeCmdInx = AddMenuButton( menu, CmdDescribe, "cmdDescribe", _("Properties"), wIconCreatePixMap(describe_xpm),
- LEVEL0, IC_CANCEL|IC_POPUP, ACCL_DESCRIBE, NULL );
- RegisterChangeNotification( DescChange );
- ParamRegister( &describePG );
- /*AddPlaybackProc( "DESCRIBE", playbackDescribe, NULL );*/
+ describeCmdInx = AddMenuButton(menu, CmdDescribe, "cmdDescribe",
+ _("Properties"), wIconCreatePixMap(describe_xpm),
+ LEVEL0, IC_CANCEL|IC_POPUP, ACCL_DESCRIBE, NULL);
+ RegisterChangeNotification(DescChange);
+ ParamRegister(&describePG);
}
diff --git a/app/bin/cmodify.c b/app/bin/cmodify.c
index 6828ff9..594d742 100644
--- a/app/bin/cmodify.c
+++ b/app/bin/cmodify.c
@@ -1,6 +1,4 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cmodify.c,v 1.4 2008-03-06 19:35:05 m_fischer Exp $
- *
+/** \file cmodify.c
* TRACK MODIFY
*/
@@ -22,18 +20,20 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <math.h>
+
#include "cjoin.h"
#include "ccurve.h"
+#include "cbezier.h"
+#include "ccornu.h"
#include "cstraigh.h"
+#include "cundo.h"
+#include "fileio.h"
#include "i18n.h"
-
-/*****************************************************************************
- *
- * MODIFY
- *
- */
-
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
static struct {
track_p Trk;
@@ -49,12 +49,73 @@ static struct {
static int log_modify;
+static BOOL_T modifyBezierMode;
+static BOOL_T modifyCornuMode;
+
+/*
+ * Call cbezier.c CmdBezModify to alter Bezier Track and Lines.
+ * Picking a Bezier will allow control point(s) modifications until terminated with "Enter"
+ */
+static STATUS_T ModifyBezier(wAction_t action, coOrd pos) {
+ STATUS_T rc = C_CONTINUE;
+ if (Dex.Trk == NULL) return C_ERROR; //No track picked yet!
+ switch (action&0xFF) {
+ case C_START:
+ case C_DOWN:
+ case C_MOVE:
+ case C_UP:
+ case C_OK:
+ case C_TEXT:
+ rc = CmdBezModify(Dex.Trk, action, pos);
+ break;
+ case C_TERMINATE:
+ rc = CmdBezModify(Dex.Trk, action, pos);
+ Dex.Trk = NULL;
+ modifyBezierMode = FALSE;
+ break;
+ case C_REDRAW:
+ rc = CmdBezModify(Dex.Trk, action, pos);
+ break;
+ }
+ return rc;
+}
+
+/*
+ * Call ccornu.c CmdCornuModify to alter Cornu Track and Lines.
+ * Picking a Cornu will allow end point(s) modifications until terminated with "Enter"
+ */
+static STATUS_T ModifyCornu(wAction_t action, coOrd pos) {
+ STATUS_T rc = C_CONTINUE;
+ if (Dex.Trk == NULL) return C_ERROR; //No track picked yet!
+ switch (action&0xFF) {
+ case C_START:
+ case C_DOWN:
+ case C_MOVE:
+ case C_UP:
+ case C_OK:
+ case C_TEXT:
+ rc = CmdCornuModify(Dex.Trk, action, pos);
+ break;
+ case C_TERMINATE:
+ rc = CmdCornuModify(Dex.Trk, action, pos);
+ Dex.Trk = NULL;
+ modifyCornuMode = FALSE;
+ break;
+ case C_REDRAW:
+ rc = CmdCornuModify(Dex.Trk, action, pos);
+ break;
+ }
+ return rc;
+}
static STATUS_T CmdModify(
wAction_t action,
coOrd pos )
/*
- * Extend a track with a curve or straight.
+ * Extend and alter a track.
+ * Extend a track with a curve or straight and optionally an easement.
+ * Alter a ruler.
+ * Modify a Bezier.
*/
{
@@ -86,10 +147,15 @@ static STATUS_T CmdModify(
/*ChangeParameter( &easementPD );*/
trackGauge = 0.0;
changeTrackMode = modifyRulerMode = FALSE;
+ modifyBezierMode = FALSE;
+ modifyCornuMode = FALSE;
return C_CONTINUE;
case C_DOWN:
- changeTrackMode = modifyRulerMode = FALSE;
+ if (modifyBezierMode)
+ return ModifyBezier(C_DOWN, pos);
+ if (modifyCornuMode)
+ return ModifyCornu(C_DOWN, pos);
DYNARR_SET( trkSeg_t, tempSegs_da, 2 );
tempSegs(0).color = wDrawColorBlack;
tempSegs(0).width = 0;
@@ -107,9 +173,29 @@ static STATUS_T CmdModify(
Dex.Trk = NULL;
return C_CONTINUE;
}
+ if (QueryTrack( Dex.Trk, Q_CAN_MODIFY_CONTROL_POINTS )) { //Bezier
+ modifyBezierMode = TRUE;
+ if (ModifyBezier(C_START, pos) != C_CONTINUE) { //Call Start with track
+ modifyBezierMode = FALSE; //Function rejected Bezier
+ Dex.Trk =NULL;
+ tempSegs_da.cnt = 0;
+ }
+ return C_CONTINUE; //That's it
+ }
+ if (QueryTrack( Dex.Trk, Q_IS_CORNU )) { //Bezier
+ modifyCornuMode = TRUE;
+ if (ModifyCornu(C_START, pos) != C_CONTINUE) { //Call Start with track
+ modifyCornuMode = FALSE; //Function rejected Bezier
+ Dex.Trk =NULL;
+ tempSegs_da.cnt = 0;
+ }
+ return C_CONTINUE; //That's it
+ }
+
+
trackGauge = (IsTrack(Dex.Trk)?GetTrkGauge(Dex.Trk):0.0);
if ( (MyGetKeyState()&WKEY_SHIFT) &&
- QueryTrack( Dex.Trk, Q_CAN_MODIFYRADIUS ) &&
+ QueryTrack( Dex.Trk, Q_CAN_MODIFYRADIUS )&&
(inx=PickUnconnectedEndPoint(pos,Dex.Trk)) >= 0 ) {
trk = Dex.Trk;
while ( (trk1=GetTrkEndTrk(trk,1-inx)) &&
@@ -146,6 +232,10 @@ static STATUS_T CmdModify(
return ModifyRuler( C_MOVE, pos );
if (Dex.Trk == NULL)
return C_CONTINUE;
+ if ( modifyBezierMode )
+ return ModifyBezier(C_MOVE, pos);
+ if ( modifyCornuMode )
+ return ModifyCornu(C_MOVE, pos);
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
tempSegs_da.cnt = 0;
SnapPos( &pos );
@@ -165,6 +255,10 @@ static STATUS_T CmdModify(
return C_CONTINUE;
if ( modifyRulerMode )
return ModifyRuler( C_MOVE, pos );
+ if ( modifyBezierMode )
+ return ModifyBezier( C_UP, pos);
+ if (modifyCornuMode)
+ return ModifyCornu(C_UP, pos);
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
tempSegs_da.cnt = 0;
SnapPos( &pos );
@@ -181,6 +275,8 @@ static STATUS_T CmdModify(
case C_RDOWN:
changeTrackMode = TRUE;
modifyRulerMode = FALSE;
+ modifyBezierMode = FALSE;
+ modifyCornuMode = FALSE;
Dex.Trk = OnTrack( &pos, TRUE, TRUE );
if (Dex.Trk) {
if (!CheckTrackLayer( Dex.Trk ) ) {
@@ -212,10 +308,7 @@ LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n",
Dex.first = TRUE;
MainRedraw();
MapRedraw();
-#ifdef LATER
- return C_CONTINUE;
-#endif
-
+ /* no break */
case C_RMOVE:
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
tempSegs_da.cnt = 0;
@@ -226,7 +319,21 @@ LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n",
return C_CONTINUE;
Dex.first = FALSE;
Dex.pos01 = Dex.pos00;
- PlotCurve( crvCmdFromEP1, Dex.pos00, Dex.pos00x, pos, &Dex.curveData, TRUE );
+ if (Dex.params.type == curveTypeCornu) { //Restrict Cornu drag out to match end
+ ANGLE_T angle2 = NormalizeAngle(FindAngle(pos, Dex.pos00)-Dex.angle);
+ if (angle2 > 90.0 && angle2 < 270.0) {
+ if (Dex.params.cornuRadius[Dex.params.ep] == 0) {
+ Translate( &pos, Dex.pos00, Dex.angle, FindDistance( Dex.pos00, pos ) );
+ } else {
+ ANGLE_T angle = FindAngle(Dex.params.cornuCenter[Dex.params.ep],pos)-
+ FindAngle(Dex.params.cornuCenter[Dex.params.ep],Dex.pos00);
+ pos=Dex.pos00;
+ Rotate(&pos,Dex.params.cornuCenter[Dex.params.ep],angle);
+ }
+ } else pos = Dex.pos00; //Only out from end
+ PlotCurve( crvCmdFromCornu, Dex.pos00, Dex.pos00x, pos, &Dex.curveData, FALSE );
+ } else
+ PlotCurve( crvCmdFromEP1, Dex.pos00, Dex.pos00x, pos, &Dex.curveData, TRUE );
curveType = Dex.curveData.type;
if ( curveType == curveTypeStraight ) {
Dex.r1 = 0.0;
@@ -382,6 +489,8 @@ LOG( log_modify, 1, ("A0 = %0.3f, A1 = %0.3f\n",
return C_TERMINATE;
case C_REDRAW:
+ if (modifyBezierMode) return ModifyBezier(C_REDRAW, pos);
+ if (modifyCornuMode) return ModifyCornu(C_REDRAW, pos);
if ( (!changeTrackMode) && Dex.Trk && !QueryTrack( Dex.Trk, Q_MODIFY_REDRAW_DONT_UNDRAW_TRACK ) )
UndrawNewTrack( Dex.Trk );
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
@@ -390,9 +499,15 @@ LOG( log_modify, 1, ("A0 = %0.3f, A1 = %0.3f\n",
case C_TEXT:
if ( !Dex.Trk )
return C_CONTINUE;
+ if (modifyBezierMode)
+ return ModifyBezier(action, pos);
+ if (modifyCornuMode)
+ return ModifyCornu(action, pos);
return ModifyTrack( Dex.Trk, action, pos );
default:
+ if (modifyBezierMode) return ModifyBezier(action, pos);
+ if (modifyCornuMode) return ModifyCornu(action, pos);
return C_CONTINUE;
}
}
diff --git a/app/bin/cnote.c b/app/bin/cnote.c
index 88c9986..3cbd28d 100644
--- a/app/bin/cnote.c
+++ b/app/bin/cnote.c
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cnote.c,v 1.6 2008-03-10 18:59:53 m_fischer Exp $
+/** \file cnote.c
+ * NOTE
*/
/* XTrkCad - Model Railroad CAD
@@ -19,23 +19,23 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <string.h>
-#include "track.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
-
-/*****************************************************************************
- *
- * NOTE
- *
- */
+#include "param.h"
+#include "track.h"
+#include "utility.h"
static TRKTYP_T T_NOTE = -1;
static wDrawBitMap_p note_bm;
struct extraData {
- coOrd pos;
- char * text;
- };
+ coOrd pos;
+ char * text;
+};
extern BOOL_T inDescribeCmd;
@@ -49,56 +49,63 @@ static paramTextData_t noteTextData = { 300, 150 };
static paramData_t notePLs[] = {
#define I_NOTETEXT (0)
#define noteT ((wText_p)notePLs[I_NOTETEXT].control)
- { PD_TEXT, NULL, "text", PDO_DLGRESIZE, &noteTextData } };
+ { PD_TEXT, NULL, "text", PDO_DLGRESIZE, &noteTextData }
+};
static paramGroup_t notePG = { "note", 0, notePLs, sizeof notePLs/sizeof notePLs[0] };
-static track_p NewNote( wIndex_t index, coOrd p, long size )
+static track_p NewNote(wIndex_t index, coOrd p, long size)
{
- track_p t;
- struct extraData * xx;
- t = NewTrack( index, T_NOTE, 0, sizeof *xx );
- xx = GetTrkExtraData(t);
- xx->pos = p;
- xx->text = (char*)MyMalloc( (int)size + 2 );
- SetBoundingBox( t, p, p );
- return t;
+ track_p t;
+ struct extraData * xx;
+ t = NewTrack(index, T_NOTE, 0, sizeof *xx);
+ xx = GetTrkExtraData(t);
+ xx->pos = p;
+ xx->text = (char*)MyMalloc((int)size + 2);
+ SetBoundingBox(t, p, p);
+ return t;
}
-void ClearNote( void )
+void ClearNote(void)
{
- if (mainText) {
- MyFree(mainText);
- mainText = NULL;
- }
+ if (mainText) {
+ MyFree(mainText);
+ mainText = NULL;
+ }
}
-static void NoteOk( void * junk )
+static void NoteOk(void * junk)
{
- int len;
- if ( wTextGetModified(noteT) ) {
- ClearNote();
- len = wTextGetSize( noteT );
- mainText = (char*)MyMalloc( len+2 );
- wTextGetText( noteT, mainText, len );
- if (mainText[len-1] != '\n') {
- mainText[len++] = '\n';
- }
- mainText[len] = '\0';
- }
- wHide( noteW );
+ if (wTextGetModified(noteT)) {
+ int len;
+ ClearNote();
+ len = wTextGetSize(noteT);
+ mainText = (char*)MyMalloc(len+2);
+ wTextGetText(noteT, mainText, len);
+
+ if (mainText[len-1] != '\n') {
+ mainText[len++] = '\n';
+ }
+
+ mainText[len] = '\0';
+ }
+
+ wHide(noteW);
}
-void DoNote( void )
+void DoNote(void)
{
- if ( noteW == NULL ) {
- noteW = ParamCreateDialog( &notePG, MakeWindowTitle(_("Note")), _("Ok"), NoteOk, NULL, FALSE, NULL, F_RESIZE, NULL );
- }
- wTextClear( noteT );
- wTextAppend( noteT, mainText?mainText:_("Replace this text with your layout notes") );
- wTextSetReadonly( noteT, FALSE );
- wShow( noteW );
+ if (noteW == NULL) {
+ noteW = ParamCreateDialog(&notePG, MakeWindowTitle(_("Note")), _("Ok"), NoteOk,
+ NULL, FALSE, NULL, F_RESIZE, NULL);
+ }
+
+ wTextClear(noteT);
+ wTextAppend(noteT, mainText?mainText:
+ _("Replace this text with your layout notes"));
+ wTextSetReadonly(noteT, FALSE);
+ wShow(noteW);
}
@@ -107,238 +114,287 @@ void DoNote( void )
* NOTE OBJECT
*/
-static void DrawNote( track_p t, drawCmd_p d, wDrawColor color )
+static void DrawNote(track_p t, drawCmd_p d, wDrawColor color)
{
- struct extraData *xx = GetTrkExtraData(t);
- coOrd p[4];
- DIST_T dist;
- if (d->scale >= 16)
- return;
- if ( (d->funcs->options & wDrawOptTemp) == 0 ) {
- DrawBitMap( d, xx->pos, note_bm, color );
- } else {
- dist = 0.1*d->scale;
- p[0].x = p[1].x = xx->pos.x-dist;
- p[2].x = p[3].x = xx->pos.x+dist;
- p[1].y = p[2].y = xx->pos.y-dist;
- p[3].y = p[0].y = xx->pos.y+dist;
- DrawLine( d, p[0], p[1], 0, color );
- DrawLine( d, p[1], p[2], 0, color );
- DrawLine( d, p[2], p[3], 0, color );
- DrawLine( d, p[3], p[0], 0, color );
- }
+ struct extraData *xx = GetTrkExtraData(t);
+ coOrd p[4];
+
+ if (d->scale >= 16) {
+ return;
+ }
+
+ if ((d->funcs->options & wDrawOptTemp) == 0) {
+ DrawBitMap(d, xx->pos, note_bm, color);
+ } else {
+ DIST_T dist;
+ dist = 0.1*d->scale;
+ p[0].x = p[1].x = xx->pos.x-dist;
+ p[2].x = p[3].x = xx->pos.x+dist;
+ p[1].y = p[2].y = xx->pos.y-dist;
+ p[3].y = p[0].y = xx->pos.y+dist;
+ DrawLine(d, p[0], p[1], 0, color);
+ DrawLine(d, p[1], p[2], 0, color);
+ DrawLine(d, p[2], p[3], 0, color);
+ DrawLine(d, p[3], p[0], 0, color);
+ }
}
-static DIST_T DistanceNote( track_p t, coOrd * p )
+static DIST_T DistanceNote(track_p t, coOrd * p)
{
- struct extraData *xx = GetTrkExtraData(t);
- DIST_T d;
- d = FindDistance( *p, xx->pos );
- if (d < 1.0)
- return d;
- return 100000.0;
+ struct extraData *xx = GetTrkExtraData(t);
+ DIST_T d;
+ d = FindDistance(*p, xx->pos);
+
+ if (d < 1.0) {
+ return d;
+ }
+
+ return 100000.0;
}
static struct {
- coOrd pos;
- } noteData;
+ coOrd pos;
+ unsigned int layer;
+} noteData;
typedef enum { OR, LY, TX } noteDesc_e;
static descData_t noteDesc[] = {
-/*OR*/ { DESC_POS, N_("Position"), &noteData.pos },
-/*LY*/ { DESC_LAYER, N_("Layer"), NULL },
-/*TX*/ { DESC_TEXT, NULL, NULL },
- { DESC_NULL } };
-
-static void UpdateNote( track_p trk, int inx, descData_p descUpd, BOOL_T needUndoStart )
+ /*OR*/ { DESC_POS, N_("Position"), &noteData.pos },
+ /*LY*/ { DESC_LAYER, N_("Layer"), &noteData.layer },
+ /*TX*/ { DESC_TEXT, NULL, NULL },
+ { DESC_NULL }
+};
+
+static void UpdateNote(track_p trk, int inx, descData_p descUpd,
+ BOOL_T needUndoStart)
{
- struct extraData *xx = GetTrkExtraData(trk);
- int len;
-
- switch ( inx ) {
- case OR:
- UndrawNewTrack( trk );
- xx->pos = noteData.pos;
- SetBoundingBox( trk, xx->pos, xx->pos );
- DrawNewTrack( trk );
- break;
- case -1:
- if ( wTextGetModified((wText_p)noteDesc[TX].control0) ) {
- if ( needUndoStart )
- UndoStart( _("Change Track"), "Change Track" );
- UndoModify( trk );
- MyFree( xx->text );
- len = wTextGetSize( (wText_p)noteDesc[TX].control0 );
- xx->text = (char*)MyMalloc( len+2 );
- wTextGetText( (wText_p)noteDesc[TX].control0, xx->text, len );
- if (xx->text[len-1] != '\n') {
- xx->text[len++] = '\n';
- }
- xx->text[len] = '\0';
- }
- break;
- default:
- break;
- }
+ struct extraData *xx = GetTrkExtraData(trk);
+
+ switch (inx) {
+ case OR:
+ xx->pos = noteData.pos;
+ SetBoundingBox(trk, xx->pos, xx->pos);
+ MainRedraw();
+ break;
+
+ case LY:
+ SetTrkLayer(trk, noteData.layer);
+ MainRedraw();
+ break;
+
+ case -1:
+ if (wTextGetModified((wText_p)noteDesc[TX].control0)) {
+ int len;
+
+ if (needUndoStart) {
+ UndoStart(_("Change Track"), "Change Track");
+ }
+
+ UndoModify(trk);
+ MyFree(xx->text);
+ len = wTextGetSize((wText_p)noteDesc[TX].control0);
+ xx->text = (char*)MyMalloc(len+2);
+ wTextGetText((wText_p)noteDesc[TX].control0, xx->text, len);
+
+ if (xx->text[len-1] != '\n') {
+ xx->text[len++] = '\n';
+ }
+
+ xx->text[len] = '\0';
+ }
+ MainRedraw();
+ break;
+
+ default:
+ break;
+ }
}
-static void DescribeNote( track_p trk, char * str, CSIZE_T len )
+static void DescribeNote(track_p trk, char * str, CSIZE_T len)
{
- struct extraData * xx = GetTrkExtraData(trk);
-
- strcpy( str, _("Note: ") );
- len -= strlen(_("Note: "));
- str += strlen(_("Note: "));
- strncpy( str, xx->text, len );
- for (;*str;str++) {
- if (*str=='\n')
- *str = ' ';
- }
- noteData.pos = xx->pos;
- noteDesc[TX].valueP = xx->text;
- noteDesc[OR].mode = 0;
- noteDesc[TX].mode = 0;
- noteDesc[LY].mode = DESC_RO;
- DoDescribe( _("Note"), trk, noteDesc, UpdateNote );
+ struct extraData * xx = GetTrkExtraData(trk);
+ strcpy(str, _("Note: "));
+ len -= strlen(_("Note: "));
+ str += strlen(_("Note: "));
+ strncpy(str, xx->text, len);
+
+ for (; *str; str++) {
+ if (*str=='\n') {
+ *str = ' ';
+ }
+ }
+
+ noteData.pos = xx->pos;
+ noteDesc[TX].valueP = xx->text;
+ noteDesc[OR].mode = 0;
+ noteDesc[TX].mode = 0;
+ noteDesc[LY].mode = DESC_NOREDRAW;
+ DoDescribe(_("Note"), trk, noteDesc, UpdateNote);
}
-static void DeleteNote( track_p t )
+static void DeleteNote(track_p t)
{
- struct extraData *xx = GetTrkExtraData(t);
- if (xx->text)
- MyFree( xx->text );
+ struct extraData *xx = GetTrkExtraData(t);
+
+ if (xx->text) {
+ MyFree(xx->text);
+ }
}
-static BOOL_T WriteNote( track_p t, FILE * f )
+static BOOL_T WriteNote(track_p t, FILE * f)
{
- struct extraData *xx = GetTrkExtraData(t);
- int len;
- BOOL_T addNL = FALSE;
- BOOL_T rc = TRUE;
- len = strlen(xx->text);
- if ( xx->text[len-1] != '\n' ) {
- len++;
- addNL = TRUE;
- }
- rc &= fprintf(f, "NOTE %d %d 0 0 %0.6f %0.6f 0 %d\n", GetTrkIndex(t), GetTrkLayer(t),
- xx->pos.x, xx->pos.y, len )>0;
- rc &= fprintf(f, "%s%s", xx->text, addNL?"\n":"" )>0;
- rc &= fprintf(f, " END\n")>0;
- return rc;
+ struct extraData *xx = GetTrkExtraData(t);
+ int len;
+ BOOL_T addNL = FALSE;
+ BOOL_T rc = TRUE;
+ len = strlen(xx->text);
+
+ if (xx->text[len-1] != '\n') {
+ len++;
+ addNL = TRUE;
+ }
+
+ rc &= fprintf(f, "NOTE %d %d 0 0 %0.6f %0.6f 0 %d\n", GetTrkIndex(t),
+ GetTrkLayer(t),
+ xx->pos.x, xx->pos.y, len)>0;
+ rc &= fprintf(f, "%s%s", xx->text, addNL?"\n":"")>0;
+ rc &= fprintf(f, " END\n")>0;
+ return rc;
}
-static void ReadNote( char * line )
+static void ReadNote(char * line)
{
- coOrd pos;
- DIST_T elev;
- CSIZE_T size;
- char * cp;
- track_p t;
- struct extraData *xx;
- int len;
- wIndex_t index;
- wIndex_t layer;
- int lineCount;
-
- if ( strncmp( line, "NOTE MAIN", 9 ) == 0 ){
- if ( !GetArgs( line+9, paramVersion<3?"d":"0000d", &size ) )
- return;
- if (mainText)
- MyFree( mainText );
- mainText = (char*)MyMalloc( size+2 );
- cp = mainText;
- } else {
- if ( !GetArgs( line+5, paramVersion<3?"XXpYd":paramVersion<9?"dL00pYd":"dL00pfd",
- &index, &layer, &pos, &elev, &size ) ) {
- return;
- }
- t = NewNote( index, pos, size+2 );
- SetTrkLayer( t, layer );
- xx = GetTrkExtraData(t);
- cp = xx->text;
- }
- lineCount = 0;
- while (1) {
- line = GetNextLine();
- if (strncmp(line, " END", 7) == 0)
- break;
- len = strlen(line);
- if (size > 0 && size < len) {
- InputError( "NOTE text overflow", TRUE );
- size = -1;
- }
- if (size > 0) {
- if ( lineCount != 0 ) {
- strcat( cp, "\n" );
- cp++;
- size--;
- }
- strcpy( cp, line );
- cp += len;
- size -= len;
- }
- lineCount++;
- }
- if (cp[-1] != '\n')
- *cp++ = '\n';
- *cp = '\0';
+ coOrd pos;
+ DIST_T elev;
+ CSIZE_T size;
+ char * cp;
+ struct extraData *xx;
+ wIndex_t index;
+ wIndex_t layer;
+ int lineCount;
+
+ if (strncmp(line, "NOTE MAIN", 9) == 0) {
+ if (!GetArgs(line+9, paramVersion<3?"d":"0000d", &size)) {
+ return;
+ }
+
+ if (mainText) {
+ MyFree(mainText);
+ }
+
+ mainText = (char*)MyMalloc(size+2);
+ cp = mainText;
+ } else {
+ track_p t;
+
+ if (!GetArgs(line+5, paramVersion<3?"XXpYd":paramVersion<9?"dL00pYd":"dL00pfd",
+ &index, &layer, &pos, &elev, &size)) {
+ return;
+ }
+
+ t = NewNote(index, pos, size+2);
+ SetTrkLayer(t, layer);
+ xx = GetTrkExtraData(t);
+ cp = xx->text;
+ }
+
+ lineCount = 0;
+
+ while (1) {
+ int len;
+ line = GetNextLine();
+
+ if (strncmp(line, " END", 7) == 0) {
+ break;
+ }
+
+ len = strlen(line);
+
+ if (size > 0 && size < len) {
+ InputError("NOTE text overflow", TRUE);
+ size = -1;
+ }
+
+ if (size > 0) {
+ if (lineCount != 0) {
+ strcat(cp, "\n");
+ cp++;
+ size--;
+ }
+
+ strcpy(cp, line);
+ cp += len;
+ size -= len;
+ }
+
+ lineCount++;
+ }
+
+ if (cp[-1] != '\n') {
+ *cp++ = '\n';
+ }
+
+ *cp = '\0';
}
-static void MoveNote( track_p trk, coOrd orig )
+static void MoveNote(track_p trk, coOrd orig)
{
- struct extraData * xx = GetTrkExtraData( trk );
- xx->pos.x += orig.x;
- xx->pos.y += orig.y;
- SetBoundingBox( trk, xx->pos, xx->pos );
+ struct extraData * xx = GetTrkExtraData(trk);
+ xx->pos.x += orig.x;
+ xx->pos.y += orig.y;
+ SetBoundingBox(trk, xx->pos, xx->pos);
}
-static void RotateNote( track_p trk, coOrd orig, ANGLE_T angle )
+static void RotateNote(track_p trk, coOrd orig, ANGLE_T angle)
{
- struct extraData * xx = GetTrkExtraData( trk );
- Rotate( &xx->pos, orig, angle );
- SetBoundingBox( trk, xx->pos, xx->pos );
+ struct extraData * xx = GetTrkExtraData(trk);
+ Rotate(&xx->pos, orig, angle);
+ SetBoundingBox(trk, xx->pos, xx->pos);
}
-static void RescaleNote( track_p trk, FLOAT_T ratio )
+static void RescaleNote(track_p trk, FLOAT_T ratio)
{
- struct extraData * xx = GetTrkExtraData( trk );
- xx->pos.x *= ratio;
- xx->pos.y *= ratio;
+ struct extraData * xx = GetTrkExtraData(trk);
+ xx->pos.x *= ratio;
+ xx->pos.y *= ratio;
}
static trackCmd_t noteCmds = {
- "NOTE",
- DrawNote,
- DistanceNote,
- DescribeNote,
- DeleteNote,
- WriteNote,
- ReadNote,
- MoveNote,
- RotateNote,
- RescaleNote,
- NULL, /* audit */
- NULL, /* getAngle */
- NULL, /* split */
- NULL, /* traverse */
- NULL, /* enumerate */
- NULL /* redraw */ };
-
-
-BOOL_T WriteMainNote( FILE* f )
+ "NOTE",
+ DrawNote,
+ DistanceNote,
+ DescribeNote,
+ DeleteNote,
+ WriteNote,
+ ReadNote,
+ MoveNote,
+ RotateNote,
+ RescaleNote,
+ NULL, /* audit */
+ NULL, /* getAngle */
+ NULL, /* split */
+ NULL, /* traverse */
+ NULL, /* enumerate */
+ NULL /* redraw */
+};
+
+
+BOOL_T WriteMainNote(FILE* f)
{
- BOOL_T rc = TRUE;
- if (mainText && *mainText) {
- rc &= fprintf(f, "NOTE MAIN 0 0 0 0 %d\n", strlen(mainText) )>0;
- rc &= fprintf(f, "%s", mainText )>0;
- rc &= fprintf(f, " END\n")>0;
- }
- return rc;
+ BOOL_T rc = TRUE;
+
+ if (mainText && *mainText) {
+ rc &= fprintf(f, "NOTE MAIN 0 0 0 0 %lu\n", strlen(mainText))>0;
+ rc &= fprintf(f, "%s", mainText)>0;
+ rc &= fprintf(f, " END\n")>0;
+ }
+
+ return rc;
}
/*****************************************************************************
@@ -347,63 +403,71 @@ BOOL_T WriteMainNote( FILE* f )
-static STATUS_T CmdNote( wAction_t action, coOrd pos )
+static STATUS_T CmdNote(wAction_t action, coOrd pos)
{
- static coOrd oldPos;
- track_p trk;
- struct extraData * xx;
- const char* tmpPtrText;
-
- switch (action) {
- case C_START:
- InfoMessage( _("Place a note on the layout") );
- return C_CONTINUE;
- case C_DOWN:
- DrawBitMap( &tempD, pos, note_bm, normalColor );
- oldPos = pos;
- return C_CONTINUE;
- case C_MOVE:
- DrawBitMap( &tempD, oldPos, note_bm, normalColor );
- DrawBitMap( &tempD, pos, note_bm, normalColor );
- oldPos = pos;
- return C_CONTINUE;
- break;
- case C_UP:
- UndoStart( _("New Note"), "New Note" );
- trk = NewNote( -1, pos, 2 );
- DrawNewTrack( trk );
- xx = GetTrkExtraData(trk);
-
- tmpPtrText = _("Replace this text with your note");
- xx->text = (char*)MyMalloc( strlen(tmpPtrText) + 1 );
- strcpy( xx->text, tmpPtrText);
-
- inDescribeCmd = TRUE;
- DescribeNote( trk, message, sizeof message );
- inDescribeCmd = FALSE;
- return C_CONTINUE;
- case C_REDRAW:
- DrawBitMap( &tempD, oldPos, note_bm, normalColor );
- return C_CONTINUE;
- case C_CANCEL:
- DescribeCancel();
- return C_CONTINUE;
- }
- return C_INFO;
+ static coOrd oldPos;
+ track_p trk;
+ struct extraData * xx;
+ const char* tmpPtrText;
+ static int state_on = FALSE;
+
+ switch (action) {
+ case C_START:
+ InfoMessage(_("Place a note on the layout"));
+ return C_CONTINUE;
+
+ case C_DOWN:
+ state_on = TRUE;
+ oldPos = pos;
+ MainRedraw();
+ return C_CONTINUE;
+
+ case C_MOVE:
+ oldPos = pos;
+ MainRedraw();
+ return C_CONTINUE;
+ break;
+
+ case C_UP:
+ UndoStart(_("New Note"), "New Note");
+ state_on = FALSE;
+ MainRedraw();
+ trk = NewNote(-1, pos, 2);
+ DrawNewTrack(trk);
+ xx = GetTrkExtraData(trk);
+ tmpPtrText = _("Replace this text with your note");
+ xx->text = (char*)MyMalloc(strlen(tmpPtrText) + 1);
+ strcpy(xx->text, tmpPtrText);
+ inDescribeCmd = TRUE;
+ DescribeNote(trk, message, sizeof message);
+ inDescribeCmd = FALSE;
+ return C_CONTINUE;
+
+ case C_REDRAW:
+ if (state_on) DrawBitMap(&tempD, oldPos, note_bm, normalColor);
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ DescribeCancel();
+ return C_CONTINUE;
+ }
+
+ return C_INFO;
}
#include "bitmaps/note.xbm"
#include "bitmaps/cnote.xpm"
-void InitCmdNote( wMenu_p menu )
+void InitCmdNote(wMenu_p menu)
{
- ParamRegister( &notePG );
- AddMenuButton( menu, CmdNote, "cmdNote", _("Note"), wIconCreatePixMap(cnote_xpm), LEVEL0_50, IC_POPUP2, ACCL_NOTE, NULL );
+ ParamRegister(&notePG);
+ AddMenuButton(menu, CmdNote, "cmdNote", _("Note"), wIconCreatePixMap(cnote_xpm),
+ LEVEL0_50, IC_POPUP2, ACCL_NOTE, NULL);
}
-void InitTrkNote( void )
+void InitTrkNote(void)
{
- note_bm = wDrawBitMapCreate( mainD.d, note_width, note_width, 8, 8, note_bits );
- T_NOTE = InitObject( &noteCmds );
+ note_bm = wDrawBitMapCreate(mainD.d, note_width, note_width, 8, 8, note_bits);
+ T_NOTE = InitObject(&noteCmds);
}
diff --git a/app/bin/common.h b/app/bin/common.h
index e238e33..255e8d7 100644
--- a/app/bin/common.h
+++ b/app/bin/common.h
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/common.h,v 1.2 2008-02-23 07:27:15 m_fischer Exp $
+/** \file common.h
+ * Defnitions of basic types
*/
/* XTrkCad - Model Railroad CAD
@@ -23,6 +23,8 @@
#ifndef COMMON_H
#define COMMON_H
+#include <stdlib.h>
+
#ifndef TRUE
#define TRUE (1)
#define FALSE (0)
@@ -99,21 +101,18 @@ typedef struct {
abort(); \
} \
(DA).cnt = N; }
+#define DYNARR_FREE(T,DA) \
+ { if ((DA).ptr) { \
+ MyFree( (DA).ptr); \
+ (DA).ptr = NULL; \
+ } \
+ (DA).max = 0; \
+ (DA).cnt = 0; }
#ifdef WINDOWS
-#ifdef FAR
-#undef FAR
-#endif
-#ifndef WIN32
-#define FAR _far
-#else
-#define FAR
-#endif
#define M_PI 3.14159
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
-#else
-#define FAR
#endif
#if _MSC_VER >1300
diff --git a/app/bin/compound.c b/app/bin/compound.c
index ed585f7..972ff82 100644
--- a/app/bin/compound.c
+++ b/app/bin/compound.c
@@ -22,15 +22,20 @@
*/
#include <ctype.h>
-#include "track.h"
-#include "compound.h"
-#include "shrtpath.h"
+#include <math.h>
+#include <string.h>
+
+
+#include "tbezier.h"
#include "cjoin.h"
+#include "common.h"
+#include "compound.h"
+#include "cundo.h"
+#include "fileio.h"
#include "i18n.h"
-
-#if _MSC_VER >=1400
-#define strdup _strdup
-#endif
+#include "shrtpath.h"
+#include "track.h"
+#include "utility.h"
/*****************************************************************************
*
@@ -326,41 +331,6 @@ void DrawCompoundDescription(
Rotate( &p1, zero, xx->angle );
p1.x += xx->orig.x + xx->descriptionOff.x;
p1.y += xx->orig.y + xx->descriptionOff.y;
-#ifdef LATER
- maxInx = -1;
- for ( inx=0,a=0.0; a<360.0; inx++,a+=45 ) {
- Translate( &p1, p0, a, trackGauge*3 );
- dists[inx].p = p1;
- if ((trk1 = dists[inx].trk = OnTrack( &p1, FALSE, TRUE )) == NULL ||
- trk1 == trk ) {
- p1 = dists[inx].p;
- dists[inx].d = DistanceSegs( xx->orig, xx->angle, xx->segCnt, xx->segs, &p1, NULL );
- } else if ( GetTrkType(trk1) == T_TURNOUT ) {
- struct extraData *yy = GetTrkExtraData(trk1);
- dists[inx].d = DistanceSegs( yy->orig, yy->angle, yy->segCnt, yy->segs, &p1, NULL );
- } else {
- dists[inx].d = FindDistance( p0, p1 );
- }
- }
- maxD = 0; maxInx = -1;
- for ( inx=0,a=0.0; a<360.0; inx++,a+=45 ) {
- if (dists[inx].trk == NULL || dists[inx].trk == trk) {
- if (dists[inx].d > maxD) {
- maxD = dists[inx].d;
- maxInx = inx;
- }
- }
- }
- if (maxInx == -1) {
- if (dists[inx].d > maxD) {
- maxD = dists[inx].d;
- maxInx = inx;
- }
- }
- if (maxInx != -1) {
- p0 = dists[maxInx].p;
- }
-#endif
fp = wStandardFont( F_TIMES, FALSE, FALSE );
DrawBoxedString( (xx->special==TOpier)?BOX_INVERT:BOX_NONE, d, p1, desc, fp, (wFontSize_t)descriptionFontSize, color, 0.0 );
}
@@ -374,6 +344,8 @@ DIST_T CompoundDescriptionDistance(
coOrd p1;
if (GetTrkType(trk) != T_TURNOUT && GetTrkType(trk) != T_STRUCTURE)
return 100000;
+ if ( (GetTrkBits( trk ) & TB_HIDEDESC) != 0 )
+ return 100000;
p1 = xx->descriptionOrig;
Rotate( &p1, zero, xx->angle );
p1.x += xx->orig.x + xx->descriptionOff.x;
@@ -389,30 +361,37 @@ STATUS_T CompoundDescriptionMove(
{
struct extraData *xx = GetTrkExtraData(trk);
static coOrd p0, p1;
+ static BOOL_T editMode;
wDrawColor color;
switch (action) {
case C_DOWN:
+ editMode = TRUE;
REORIGIN( p0, xx->descriptionOrig, xx->angle, xx->orig )
case C_MOVE:
case C_UP:
- if (action != C_DOWN)
- DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
color = GetTrkColor( trk, &mainD );
- DrawCompoundDescription( trk, &tempD, color );
xx->descriptionOff.x = (pos.x-p0.x);
xx->descriptionOff.y = (pos.y-p0.y);
p1 = xx->descriptionOrig;
Rotate( &p1, zero, xx->angle );
p1.x += xx->orig.x + xx->descriptionOff.x;
p1.y += xx->orig.y + xx->descriptionOff.y;
- DrawCompoundDescription( trk, &tempD, color );
- if (action != C_UP)
- DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
- MainRedraw();
+ if (action == C_UP) {
+ editMode = FALSE;
+ }
+ MainRedraw();
+ MapRedraw();
return action==C_UP?C_TERMINATE:C_CONTINUE;
+ break;
+ case C_REDRAW:
+ if (editMode) {
+ DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
+ }
}
+
+
return C_CONTINUE;
}
@@ -494,8 +473,11 @@ DIST_T DistanceCompound(
static struct {
- coOrd endPt[2];
- FLOAT_T elev[2];
+ coOrd endPt[4];
+ ANGLE_T endAngle[4];
+ DIST_T endRadius[4];
+ coOrd endCenter[4];
+ FLOAT_T elev[4];
coOrd orig;
ANGLE_T angle;
char manuf[STR_SIZE];
@@ -503,23 +485,40 @@ static struct {
char partno[STR_SIZE];
long epCnt;
long segCnt;
+ long pathCnt;
FLOAT_T grade;
DIST_T length;
- LAYER_T layerNumber;
+ unsigned int layerNumber;
} compoundData;
-typedef enum { E0, Z0, E1, Z1, GR, OR, AN, MN, NM, PN, EC, SC, LY } compoundDesc_e;
+typedef enum { E0, A0, C0, R0, Z0, E1, A1, C1, R1, Z1, E2, A2, C2, R2, Z2, E3, A3, C3, R3, Z3, GR, OR, AN, MN, NM, PN, EC, SC, LY } compoundDesc_e;
static descData_t compoundDesc[] = {
-/*E0*/ { DESC_POS, N_("End Pt 1: X"), &compoundData.endPt[0] },
-/*Z0*/ { DESC_DIM, N_("Z"), &compoundData.elev[0] },
-/*E1*/ { DESC_POS, N_("End Pt 2: X"), &compoundData.endPt[1] },
-/*Z1*/ { DESC_DIM, N_("Z"), &compoundData.elev[1] },
+/*E0*/ { DESC_POS, N_("End Pt 1: X,Y"), &compoundData.endPt[0] },
+/*A0*/ { DESC_ANGLE, N_("Angle"), &compoundData.endAngle[0] },
+/*C0*/ { DESC_POS, N_("Center X,Y"), &compoundData.endCenter[0] },
+/*R0*/ { DESC_DIM, N_("Radius"), &compoundData.endRadius[0] },
+/*Z0*/ { DESC_DIM, N_("Z1"), &compoundData.elev[0] },
+/*E1*/ { DESC_POS, N_("End Pt 2: X,Y"), &compoundData.endPt[1] },
+/*A1*/ { DESC_ANGLE, N_("Angle"), &compoundData.endAngle[1] },
+/*C1*/ { DESC_POS, N_("Center X,Y"), &compoundData.endCenter[1] },
+/*R1*/ { DESC_DIM, N_("Radius"), &compoundData.endRadius[1] },
+/*Z1*/ { DESC_DIM, N_("Z2"), &compoundData.elev[1] },
+/*E2*/ { DESC_POS, N_("End Pt 3: X,Y"), &compoundData.endPt[2] },
+/*A2*/ { DESC_ANGLE, N_("Angle"), &compoundData.endAngle[2] },
+/*C2*/ { DESC_POS, N_("Center X,Y"), &compoundData.endCenter[2] },
+/*R2*/ { DESC_DIM, N_("Radius"), &compoundData.endRadius[2] },
+/*Z2*/ { DESC_DIM, N_("Z3"), &compoundData.elev[2] },
+/*E3*/ { DESC_POS, N_("End Pt 4: X,Y"), &compoundData.endPt[3] },
+/*A3*/ { DESC_ANGLE, N_("Angle"), &compoundData.endAngle[3] },
+/*C3*/ { DESC_POS, N_("Center X,Y"), &compoundData.endCenter[3] },
+/*R3*/ { DESC_DIM, N_("Radius"), &compoundData.endRadius[3] },
+/*Z3*/ { DESC_DIM, N_("Z4"), &compoundData.elev[3] },
/*GR*/ { DESC_FLOAT, N_("Grade"), &compoundData.grade },
-/*OR*/ { DESC_POS, N_("Origin: X"), &compoundData.orig },
+/*OR*/ { DESC_POS, N_("Origin: X,Y"), &compoundData.orig },
/*AN*/ { DESC_ANGLE, N_("Angle"), &compoundData.angle },
/*MN*/ { DESC_STRING, N_("Manufacturer"), &compoundData.manuf },
/*NM*/ { DESC_STRING, N_("Name"), &compoundData.name },
/*PN*/ { DESC_STRING, N_("Part No"), &compoundData.partno },
-/*EC*/ { DESC_LONG, N_("# End Pt"), &compoundData.epCnt },
+/*EC*/ { DESC_LONG, N_("# End Pts"), &compoundData.epCnt },
/*SC*/ { DESC_LONG, N_("# Segments"), &compoundData.segCnt },
/*LY*/ { DESC_LAYER, N_("Layer"), &compoundData.layerNumber },
{ DESC_NULL } };
@@ -616,36 +615,55 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee
MoveTrack( trk, pos );
ComputeCompoundBoundingBox( trk );
break;
+ case A0:
+ case A1:
+ case A2:
+ case A3:
+ if (inx==E3) ep=3;
+ else if (inx==E2) ep=2;
+ else if (inx==E1) ep=1;
+ else ep=0;
+ RotateTrack( trk, xx->orig, NormalizeAngle( compoundData.endAngle[ep]-xx->angle ) );
+ ComputeCompoundBoundingBox( trk );
+ compoundData.angle = xx->angle;
+ compoundDesc[AN].mode |= DESC_CHANGE;
+ break;
case AN:
RotateTrack( trk, xx->orig, NormalizeAngle( compoundData.angle-xx->angle ) );
ComputeCompoundBoundingBox( trk );
break;
case E0:
case E1:
- ep = (inx==E0?0:1);
+ case E2:
+ case E3:
+ if (inx==E3) ep=3;
+ else if (inx==E2) ep=2;
+ else if (inx==E1) ep=1;
+ else ep=0;
pos = GetTrkEndPos(trk,ep);
pos.x = compoundData.endPt[ep].x - pos.x;
pos.y = compoundData.endPt[ep].y - pos.y;
MoveTrack( trk, pos );
ComputeCompoundBoundingBox( trk );
- if ( compoundData.epCnt >= 2 ) {
- compoundData.endPt[1-ep] = GetTrkEndPos(trk,1-ep);
- compoundDesc[inx==E0?E1:E0].mode |= DESC_CHANGE;
- }
break;
case Z0:
case Z1:
- ep = (inx==Z0?0:1);
+ case Z2:
+ case Z3:
+ ep = (inx==Z0?0:(inx==Z1?1:(inx==Z2?2:3)));
UpdateTrkEndElev( trk, ep, GetTrkEndElevUnmaskedMode(trk,ep), compoundData.elev[ep], NULL );
if ( GetTrkEndPtCnt(trk) == 1 )
break;
- ComputeElev( trk, 1-ep, FALSE, &compoundData.elev[1-ep], NULL );
+ for (int i=0;i<compoundData.epCnt;i++) {
+ if (i==ep) continue;
+ ComputeElev( trk, i, FALSE, &compoundData.elev[i], NULL );
+ }
if ( compoundData.length > minLength )
compoundData.grade = fabs( (compoundData.elev[0]-compoundData.elev[1])/compoundData.length )*100.0;
else
compoundData.grade = 0.0;
compoundDesc[GR].mode |= DESC_CHANGE;
- compoundDesc[inx==Z0?Z1:Z0].mode |= DESC_CHANGE;
+ compoundDesc[Z0+(E1-E0)*inx].mode |= DESC_CHANGE;
break;
case LY:
SetTrkLayer( trk, compoundData.layerNumber);
@@ -653,6 +671,35 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee
default:
break;
}
+ switch ( inx ) {
+ case A0:
+ case A1:
+ case A2:
+ case A3:
+ case E0:
+ case E1:
+ case E2:
+ case E3:
+ case AN:
+ case OR:
+ for (int i=0;i<compoundData.epCnt;i++) {
+ compoundData.endPt[i] = GetTrkEndPos(trk,i);
+ compoundDesc[i*(E1-E0)+E0].mode |= DESC_CHANGE;
+ trackParams_t params;
+ compoundData.endAngle[i] = GetTrkEndAngle(trk,i);
+ compoundDesc[i*(E1-E0)+A0].mode |= DESC_CHANGE;
+ GetTrackParams(PARAMS_CORNU,trk,compoundData.endPt[i],&params);
+ compoundData.endRadius[i] = params.arcR;
+ if (params.arcR != 0.0) {
+ compoundData.endCenter[i] = params.arcP;
+ compoundDesc[i*(E1-E0)+C0].mode |= DESC_CHANGE;
+ }
+ }
+ break;
+ default:
+ break;
+ };
+
DrawNewTrack( trk );
}
@@ -691,9 +738,11 @@ void DescribeCompound(
epCnt = GetTrkEndPtCnt(trk);
fix = 0;
+ mode = 0;
for ( ep=0; ep<epCnt; ep++ ) {
if (GetTrkEndTrk(trk,ep)) {
fix = 1;
+ mode = DESC_RO;
break;
}
}
@@ -735,10 +784,15 @@ void DescribeCompound(
compoundData.segCnt = xx->segCnt;
compoundData.length = 0;
compoundData.layerNumber = GetTrkLayer( trk );
- compoundDesc[E0].mode =
- compoundDesc[Z0].mode =
- compoundDesc[E1].mode =
- compoundDesc[Z1].mode =
+
+ for ( int i=0 ; i<4 ; i++) {
+ compoundDesc[E0+(E1-E0)*i].mode = DESC_IGNORE;
+ compoundDesc[A0+(E1-E0)*i].mode = DESC_IGNORE;
+ compoundDesc[R0+(E1-E0)*i].mode = DESC_IGNORE;
+ compoundDesc[C0+(E1-E0)*i].mode = DESC_IGNORE;
+ compoundDesc[Z0+(E1-E0)*i].mode = DESC_IGNORE;
+ }
+
compoundDesc[GR].mode = DESC_IGNORE;
compoundDesc[OR].mode =
compoundDesc[AN].mode = fix?DESC_RO:0;
@@ -746,37 +800,37 @@ void DescribeCompound(
compoundDesc[NM].mode =
compoundDesc[PN].mode = 0 /*DESC_NOREDRAW*/;
compoundDesc[EC].mode =
- compoundDesc[SC].mode =
+ compoundDesc[SC].mode = DESC_RO;
compoundDesc[LY].mode = DESC_NOREDRAW;
- if ( compoundData.epCnt ) {
- if ( compoundData.epCnt <=2 ) {
- if ( GetTrkEndTrk(trk,0) || (compoundData.epCnt==2 && GetTrkEndTrk(trk,1)) )
- mode = DESC_RO;
- else
- mode = 0;
- compoundDesc[OR].mode = DESC_IGNORE;
- compoundDesc[AN].mode = DESC_IGNORE;
- compoundDesc[EC].mode = DESC_IGNORE;
- compoundData.endPt[0] = GetTrkEndPos(trk,0);
- ComputeElev( trk, 0, FALSE, &compoundData.elev[0], NULL );
- compoundDesc[E0].mode = (int)mode;
- compoundDesc[Z0].mode = (EndPtIsDefinedElev(trk,0)?0:DESC_RO)|DESC_NOREDRAW;
- if ( compoundData.epCnt == 2 ) {
- compoundData.length = GetTrkLength( trk, 0, 1 );
- compoundData.endPt[1] = GetTrkEndPos(trk,1);
- ComputeElev( trk, 1, FALSE, &compoundData.elev[1], NULL );
- compoundDesc[E1].mode = (int)mode;
- compoundDesc[Z1].mode = (EndPtIsDefinedElev(trk,1)?0:DESC_RO)|DESC_NOREDRAW;
- compoundDesc[GR].mode = DESC_RO;
- if ( compoundData.length > minLength )
- compoundData.grade = fabs( (compoundData.elev[0]-compoundData.elev[1])/compoundData.length )*100.0;
- else
- compoundData.grade = 0.0;
+ if (compoundData.epCnt >0) {
+ for (int i=0;i<compoundData.epCnt;i++) {
+ compoundDesc[A0+(E1-E0)*i].mode = (int)mode;
+ compoundDesc[R0+(E1-E0)*i].mode = DESC_RO;
+ compoundDesc[C0+(E1-E0)*i].mode = DESC_RO;
+ compoundDesc[E0+(E1-E0)*i].mode = (int)mode;
+ compoundData.endPt[i] = GetTrkEndPos(trk,i);
+ compoundData.endAngle[i] = GetTrkEndAngle(trk,i);
+ trackParams_t params;
+ GetTrackParams(PARAMS_CORNU,trk,compoundData.endPt[i],&params);
+ compoundData.endRadius[i] = params.arcR;
+ if (params.arcR != 0.0) {
+ compoundData.endCenter[i] = params.arcP;
+ } else {
+ compoundDesc[C0+(E1-E0)*i].mode = DESC_IGNORE;
+ compoundDesc[R0+(E1-E0)*i].mode = DESC_IGNORE;
}
+ ComputeElev( trk, i, FALSE, &compoundData.elev[i], NULL );
+ compoundDesc[Z0+(E1-E0)*i].mode = (EndPtIsDefinedElev(trk,i)?0:DESC_RO)|DESC_NOREDRAW;
}
+ compoundDesc[GR].mode = DESC_RO;
+ }
+ if ( compoundData.length > minLength && compoundData.epCnt > 1)
+ compoundData.grade = fabs( (compoundData.elev[0]-compoundData.elev[1])/compoundData.length )*100.0;
+ else
+ compoundData.grade = 0.0;
+ if ( compoundData.epCnt >1 ) {
DoDescribe( compoundData.epCnt>2?_("Turnout"):_("Sectional Track"), trk, compoundDesc, UpdateCompound );
} else {
- compoundDesc[EC].mode |= DESC_IGNORE;
DoDescribe( _("Structure"), trk, compoundDesc, UpdateCompound );
}
}
@@ -785,6 +839,9 @@ void DescribeCompound(
void DeleteCompound(
track_p t )
{
+ struct extraData *xx = GetTrkExtraData(t);
+ FreeFilledDraw( xx->segCnt, xx->segs );
+ MyFree( xx->segs );
}
@@ -894,6 +951,8 @@ EXPORT track_p NewCompound(
xx->pathCurr = xx->paths;
xx->segCnt = segCnt;
xx->segs = memdup( segs, segCnt * sizeof *segs );
+ trkSeg_p p = xx->segs;
+ FixUpBezierSegs(xx->segs,xx->segCnt);
ComputeCompoundBoundingBox( trk );
SetDescriptionOrig( trk );
for ( ep=0; ep<epCnt; ep++ )
diff --git a/app/bin/compound.h b/app/bin/compound.h
index a0de926..4845f78 100644
--- a/app/bin/compound.h
+++ b/app/bin/compound.h
@@ -1,4 +1,6 @@
-/* $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/compound.h,v 1.1 2005-12-07 15:47:08 rc-flyer Exp $ */
+/** \file compound.h
+ * Definitions and function prototypes for complex elements (eg. turnouts)
+ */
/* XTrkCad - Model Railroad CAD
* Copyright (C) 2005 Dave Bullis
@@ -21,6 +23,9 @@
#ifndef COMPOUND_H
#define COMPOUND_H
+#include "common.h"
+#include "track.h"
+
typedef enum { TOnormal, TOadjustable, TOpierInfo, TOpier, TOcarDesc, TOlast } TOspecial_e;
typedef struct {
@@ -91,6 +96,9 @@ struct extraData {
extern TRKTYP_T T_TURNOUT;
extern TRKTYP_T T_STRUCTURE;
+extern TRKTYP_T T_BEZIER;
+extern TRKTYP_T T_BZRLIN;
+extern TRKTYP_T T_CORNU;
extern DIST_T curBarScale;
extern dynArr_t turnoutInfo_da;
extern dynArr_t structureInfo_da;
diff --git a/app/bin/cparalle.c b/app/bin/cparalle.c
index 28e3513..8e70408 100644
--- a/app/bin/cparalle.c
+++ b/app/bin/cparalle.c
@@ -1,8 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cparalle.c,v 1.5 2009-05-25 18:11:03 m_fischer Exp $
- *
+/** \file cparalle.c
* PARALLEL
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -23,10 +20,16 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <math.h>
+
#include "ccurve.h"
#include "cstraigh.h"
+#include "cundo.h"
#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
static struct {
track_p Trk;
@@ -90,6 +93,7 @@ static STATUS_T CmdParallel( wAction_t action, coOrd pos )
}
if ( !QueryTrack( Dpa.Trk, Q_CAN_PARALLEL ) ) {
Dpa.Trk = NULL;
+ InfoMessage(_(" Track doesn't support parallel"));
return C_CONTINUE;
}
/* in case query has changed things (eg joint) */
@@ -101,6 +105,7 @@ static STATUS_T CmdParallel( wAction_t action, coOrd pos )
tempSegs_da.cnt = 0;
case C_MOVE:
+
if (Dpa.Trk == NULL) return C_CONTINUE;
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
if ( !MakeParallelTrack( Dpa.Trk, pos, parSeparation, NULL, &p0, &p1 ) ) {
diff --git a/app/bin/cprint.c b/app/bin/cprint.c
index d89d1e2..88a9151 100644
--- a/app/bin/cprint.c
+++ b/app/bin/cprint.c
@@ -1,7 +1,5 @@
/** \file cprint.c
* Printing functions.
- *
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cprint.c,v 1.6 2009-08-16 13:26:41 m_fischer Exp $
*/
/* XTrkCad - Model Railroad CAD
@@ -26,9 +24,16 @@
#include <time.h>
#include <string.h>
#include <ctype.h>
-#include "track.h"
-#include "i18n.h"
+#include <math.h>
+#include "custom.h"
+#include "fileio.h"
+#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
#define PRINT_GAUDY (0)
#define PRINT_PLAIN (1)
@@ -73,6 +78,7 @@ static long printRoadbed = 0;
static DIST_T printRoadbedWidth = 0.0;
static BOOL_T printRotate = FALSE;
static BOOL_T rotateCW = FALSE;
+static long printCenterLine = 0;
static double printScale = 16;
static long iPrintScale = 16;
@@ -101,6 +107,7 @@ static char * printPhysSizeLabels[] = { N_("Ignore Page Margins"), NULL };
static char * printGridLabels[] = { N_("Print Snap Grid"), NULL };
static char * printRulerLabels[] = { N_("Print Rulers"), NULL };
static char * printRoadbedLabels[] = { N_("Print Roadbed Outline"), NULL };
+static char * printCenterLineLabels[] = { N_("Print Centerline below Scale 1:1"), NULL };
static paramIntegerRange_t rminScale_999 = { 1, 999, 0, PDO_NORANGECHECK_HIGH };
static paramFloatRange_t r0_ = { 0, 0, 0, PDO_NORANGECHECK_HIGH };
static paramFloatRange_t r1_ = { 1, 0, 0, PDO_NORANGECHECK_HIGH };
@@ -124,19 +131,22 @@ static paramData_t printPLs[] = {
/*10*/ { PD_TOGGLE, &printGrid, "grid", PDO_DLGNOLABELALIGN, printGridLabels, NULL, BC_HORZ|BC_NOBORDER },
#define I_RULER (11)
/*11*/ { PD_TOGGLE, &printRuler, "ruler", PDO_DLGNOLABELALIGN, printRulerLabels, NULL, BC_HORZ|BC_NOBORDER },
-#define I_ROADBED (12)
-/*12*/{ PD_TOGGLE, &printRoadbed, "roadbed", PDO_DLGNOLABELALIGN, printRoadbedLabels, NULL, BC_HORZ|BC_NOBORDER },
-#define I_ROADBEDWIDTH (13)
-/*13*/{ PD_FLOAT, &printRoadbedWidth, "roadbedWidth", PDO_DIM|PDO_DLGBOXEND, &r0_, N_("Width") },
-/*14*/{ PD_FLOAT, &newPrintGrid.orig.x, "origx", PDO_DIM|PDO_DLGRESETMARGIN, &r_10_99999, N_("Origin: X"), 0, (void*)2 },
-/*15*/ { PD_FLOAT, &newPrintGrid.orig.y, "origy", PDO_DIM, &r_10_99999, N_("Y"), 0, (void*)2 },
-/*16*/ { PD_BUTTON, (void*)DoResetGrid, "reset", PDO_DLGHORZ, NULL, N_("Reset") },
-/*17*/ { PD_FLOAT, &newPrintGrid.angle, "origa", PDO_ANGLE|PDO_DLGBOXEND, &r0_360, N_("Angle"), 0, (void*)2 },
-/*18*/ { PD_BUTTON, (void*)DoPrintSetup, "setup", PDO_DLGCMDBUTTON, NULL, N_("Setup") },
-/*19*/ { PD_BUTTON, (void*)PrintClear, "clear", 0, NULL, N_("Clear") },
-#define I_PAGECNT (20)
-/*20*/ { PD_MESSAGE, N_("0 pages"), NULL, 0, (void*)80 },
-/*21*/ { PD_MESSAGE, N_("selected"), NULL, 0, (void*)80 } };
+#define I_CENTERLINE (12)
+/*12*/ { PD_TOGGLE, &printCenterLine, "centerLine", PDO_DLGNOLABELALIGN, printCenterLineLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_ROADBED (13)
+/*13*/{ PD_TOGGLE, &printRoadbed, "roadbed", PDO_DLGNOLABELALIGN, printRoadbedLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_ROADBEDWIDTH (14)
+/*14*/{ PD_FLOAT, &printRoadbedWidth, "roadbedWidth", PDO_DIM|PDO_DLGBOXEND, &r0_, N_("Width") },
+/*15*/{ PD_FLOAT, &newPrintGrid.orig.x, "origx", PDO_DIM|PDO_DLGRESETMARGIN, &r_10_99999, N_("Origin: X"), 0, (void*)2 },
+/*16*/ { PD_FLOAT, &newPrintGrid.orig.y, "origy", PDO_DIM, &r_10_99999, N_("Y"), 0, (void*)2 },
+/*17*/ { PD_BUTTON, (void*)DoResetGrid, "reset", PDO_DLGHORZ, NULL, N_("Reset") },
+/*18*/ { PD_FLOAT, &newPrintGrid.angle, "origa", PDO_ANGLE|PDO_DLGBOXEND, &r0_360, N_("Angle"), 0, (void*)2 },
+/*19*/ { PD_BUTTON, (void*)DoPrintSetup, "setup", PDO_DLGCMDBUTTON, NULL, N_("Setup") },
+/*20*/ { PD_BUTTON, (void*)PrintClear, "clear", 0, NULL, N_("Clear") },
+#define I_PAGECNT (21)
+/*21*/ { PD_MESSAGE, N_("0 pages"), NULL, 0, (void*)80 },
+/*22*/ { PD_MESSAGE, N_("selected"), NULL, 0, (void*)80 }
+};
static paramGroup_t printPG = { "print", PGO_PREFMISCGROUP, printPLs, sizeof printPLs/sizeof printPLs[0] };
@@ -158,33 +168,6 @@ static void ChangeDim( void )
MapGrid( zero, mapD.size, 0.0, currPrintGrid.orig, currPrintGrid.angle, currPrintGrid.size.x, currPrintGrid.size.y,
&x0, &x1, &y0, &y1 );
-#ifdef LATER
- d0 = sqrt( mapD.size.x * mapD.size.x + mapD.size.y * mapD.size.y );
-
- Translate( &p1, currPrintGrid.orig, currPrintGrid.angle, d0 );
- p0 = currPrintGrid.orig;
- ClipLine( &p0, &p1, zero, 0.0, mapD.size );
- d1 = FindDistance( currPrintGrid.orig, p1 );
- y1 = (int)ceil(d1/currPrintGrid.size.y);
-
- Translate( &p1, currPrintGrid.orig, currPrintGrid.angle+180, d0 );
- p0 = currPrintGrid.orig;
- ClipLine( &p0, &p1, zero, 0.0, mapD.size );
- d1 = FindDistance( currPrintGrid.orig, p1 );
- y0 = -(int)floor(d1/currPrintGrid.size.y);
-
- Translate( &p1, currPrintGrid.orig, currPrintGrid.angle+90, d0 );
- p0 = currPrintGrid.orig;
- ClipLine( &p0, &p1, zero, 0.0, mapD.size );
- d1 = FindDistance( currPrintGrid.orig, p1 );
- x1 = (int)ceil(d1/currPrintGrid.size.x);
-
- Translate( &p1, currPrintGrid.orig, currPrintGrid.angle+270, d0 );
- p0 = currPrintGrid.orig;
- ClipLine( &p0, &p1, zero, 0.0, mapD.size );
- d1 = FindDistance( currPrintGrid.orig, p1 );
- x0 = -(int)floor(d1/currPrintGrid.size.x);
-#endif
if ( x0==bm.x0 && x1==bm.x1 && y0==bm.y0 && y1==bm.y1 )
return;
@@ -385,20 +368,20 @@ static void PrintGaudyBox(
DrawString( &page_d, p00, 0.0, dat, fp, 16.0, wDrawColorBlack );
p00.y = 0.5+0.05;
- DrawTextSize( &mainD, Title1, fp, 16.0, FALSE, &textsize );
+ DrawTextSize( &mainD, GetLayoutTitle(), fp, 16.0, FALSE, &textsize );
p00.x = (pageW/2.0)-(textsize.x/2.0);
p00.y = 0.75+0.05;
- DrawString( &page_d, p00, 0.0, Title1, fp, 16.0, wDrawColorBlack );
- DrawTextSize( &mainD, Title2, fp, 16.0, FALSE, &textsize );
+ DrawString( &page_d, p00, 0.0, GetLayoutTitle(), fp, 16.0, wDrawColorBlack );
+ DrawTextSize( &mainD, GetLayoutSubtitle(), fp, 16.0, FALSE, &textsize );
p00.x = (pageW/2.0)-(textsize.x/2.0);
p00.y = 0.50+0.05;
- DrawString( &page_d, p00, 0.0, Title2, fp, 16.0, wDrawColorBlack );
+ DrawString( &page_d, p00, 0.0, GetLayoutSubtitle(), fp, 16.0, wDrawColorBlack );
sprintf( dat, _("PrintScale 1:%ld Room %s x %s Model Scale %s File %s"),
(long)printScale,
FormatDistance( roomSize.x ),
FormatDistance( roomSize.y ),
- curScaleName, curFileName );
+ curScaleName, GetLayoutFilename() );
p00.x = 0.05; p00.y = 0.25+0.05;
DrawString( &page_d, p00, 0.0, dat, fp, 16.0, wDrawColorBlack );
}
@@ -480,30 +463,17 @@ static void PrintEnableControls( void )
ParamLoadControl( &printPG, I_ROADBED );
ParamControlActive( &printPG, I_ROADBED, TRUE );
ParamControlActive( &printPG, I_ROADBEDWIDTH, TRUE );
+ ParamControlActive( &printPG, I_CENTERLINE, TRUE);
} else {
printRoadbed = 0;
ParamLoadControl( &printPG, I_ROADBED );
ParamControlActive( &printPG, I_ROADBED, FALSE );
ParamControlActive( &printPG, I_ROADBEDWIDTH, FALSE );
+ ParamControlActive( &printPG, I_CENTERLINE, FALSE );
}
}
-#ifdef LATER
-static void PrintSetOrient( void )
-/*
- * Called when print landscape/portrait toggled
- */
-{
- DrawPrintGrid();
- ParamLoadData( &printPG );
- currPrintGrid = newPrintGrid;
- ChangeDim();
- DrawPrintGrid();
-}
-#endif
-
-
static void PrintUpdate( int inx0 )
/*
* Called when print page size (x or y) is changed.
@@ -918,6 +888,7 @@ static BOOL_T PrintPage(
if (printGrid)
DrawSnapGrid( &print_d, mapD.size, FALSE );
roadbedWidth = printRoadbed?printRoadbedWidth:0.0;
+ printCenterLines = printCenterLine;
DrawTracks( &print_d, print_d.scale, minP, maxP );
if (printRegistrationMarks && printScale == 1)
DrawRegistrationMarks( &print_d );
@@ -950,7 +921,7 @@ static void DoPrintPrint( void * junk )
print_d.CoOrd2Pix = page_d.CoOrd2Pix = mainD.CoOrd2Pix;
wSetCursor( wCursorWait );
- if (!wPrintDocStart( Title1, pageCount, &copies )) {
+ if (!wPrintDocStart(GetLayoutTitle(), pageCount, &copies )) {
wSetCursor( wCursorNormal );
return;
}
diff --git a/app/bin/cprofile.c b/app/bin/cprofile.c
index d8bbc24..49c3289 100644
--- a/app/bin/cprofile.c
+++ b/app/bin/cprofile.c
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cprofile.c,v 1.4 2008-03-06 19:35:06 m_fischer Exp $
+/* \file cprofile.c
+ * Track profile
*/
/* XTrkCad - Model Railroad CAD
@@ -20,11 +20,17 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
-#include "cselect.h"
#include <math.h>
-#include "shrtpath.h"
+
+#include "custom.h"
+#include "cselect.h"
+#include "cundo.h"
#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "shrtpath.h"
+#include "track.h"
/*
@@ -484,7 +490,7 @@ static void DoProfilePrint( void * junk )
screenRatio = screenSize.y/screenSize.x;
printProfileD.size.x = w;
printProfileD.size.y = h;
- sprintf( message, _("%s Profile: %s"), sProdName, Title1 );
+ sprintf( message, _("%s Profile: %s"), sProdName, GetLayoutTitle() );
fp = wStandardFont( F_TIMES, FALSE, FALSE );
DrawTextSize( &mainD, message, fp, 24, FALSE, &textsize );
titleH = textsize.y + 6.0/mainD.dpi;
diff --git a/app/bin/cpull.c b/app/bin/cpull.c
index a10f426..d7f7c80 100644
--- a/app/bin/cpull.c
+++ b/app/bin/cpull.c
@@ -1,8 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cpull.c,v 1.4 2008-03-06 19:35:06 m_fischer Exp $
- *
+/** \file cpull.c
* Pull and Tighten commands
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -24,14 +21,15 @@
*/
#include <math.h>
-#include "track.h"
+
#include "cselect.h"
#include "compound.h"
+#include "cundo.h"
+#include "fileio.h"
#include "i18n.h"
-
-/*
- * pull track endpoint together
- */
+#include "messages.h"
+#include "track.h"
+#include "utility.h"
int debugPull = 0;
@@ -454,12 +452,20 @@ static void PullTracks(
int cnt1, cnt2;
int rc;
+ if (QueryTrack(trk1,Q_CAN_ADD_ENDPOINTS) || QueryTrack(trk2,Q_CAN_ADD_ENDPOINTS)) {
+ ConnectTurntableTracks(trk1, ep1, trk2, ep2 );
+ return;
+ }
+
+ if (ep1<0 || ep1<0 ) return;
+
if (ConnectAbuttingTracks( trk1, ep1, trk2, ep2 ))
return;
if (ConnectAdjustableTracks( trk1, ep1, trk2, ep2 ))
return;
+
p1 = GetTrkEndPos( trk1, ep1 );
p2 = GetTrkEndPos( trk2, ep2 );
a1 = GetTrkEndAngle( trk1, ep1 );
@@ -593,12 +599,22 @@ static STATUS_T CmdPull(
static EPINX_T ep1;
track_p trk2;
EPINX_T ep2;
+ static BOOL_T turntable;
+
+ int countTracksR0 = 0, countTracksR1 = 0, possibleEndPoints = 0;
+ BOOL_T found = FALSE;
+ ANGLE_T a;
+ DIST_T d;
switch (action) {
case C_START:
- InfoMessage( _("Select first End-Point to connect") );
+ if (selectedTrackCount==0)
+ InfoMessage( _("Select first end-point to connect") );
+ else
+ InfoMessage( _("Select first end-point to connect, or Right-Click for connecting selected tracks") );
trk1 = NULL;
+ turntable = FALSE;
return C_CONTINUE;
case C_LCLICK:
@@ -606,10 +622,14 @@ static STATUS_T CmdPull(
if (trk1 == NULL) {
if ((trk1 = OnTrack( &pos, TRUE, FALSE )) != NULL) {
if ((ep1 = PickUnconnectedEndPoint( pos, trk1 )) < 0) {
- trk1 = NULL;
+ if (QueryTrack(trk1, Q_CAN_ADD_ENDPOINTS)) {
+ turntable = TRUE;
+ ep1 = -1;
+ } else trk1 = NULL;
} else {
- InfoMessage( _("Select second End-Point to connect") );
+ InfoMessage( _("Select second end-point to connect") );
}
+
}
} else {
if ((trk2 = OnTrack( &pos, TRUE, FALSE )) != NULL) {
@@ -619,6 +639,15 @@ static STATUS_T CmdPull(
inError = TRUE;
return C_TERMINATE;
}
+ if (!turntable && QueryTrack(trk2, Q_CAN_ADD_ENDPOINTS)) {
+ ep2 = -1;
+ turntable = TRUE;
+ PullTracks( trk2, ep2, trk1, ep1);
+ trk1 = NULL;
+ inError = TRUE;
+ turntable = FALSE;
+ return C_TERMINATE;
+ }
}
}
} else {
@@ -635,6 +664,53 @@ static STATUS_T CmdPull(
}
return C_CONTINUE;
+ case C_RCLICK:
+ if (selectedTrackCount==0) {
+ ErrorMessage(_("Connect Multiple Tracks - Select multiple tracks to join first"));
+ return C_CONTINUE;
+ }
+ if (NoticeMessage(_("Try to Connect all Selected Tracks?"), _("Yes"), _("No"))<=0) return C_CONTINUE;
+ trk1 = NULL;
+ trk2 = NULL;
+ UndoStart( _("ReConnect"),"Try to reconnect all selected tracks");
+ for (int i=0;i<2;i++) { // Try twice - in case later joins help earlier ones and to try close ones first
+ while ( TrackIterate( &trk1 ) ) {
+ found = FALSE;
+ if ( GetTrkSelected( trk1 ) ) {
+ for (ep1=0; ep1<GetTrkEndPtCnt(trk1); ep1++) {
+ if (!GetTrkEndTrk( trk1, ep1 )) {
+ trk2 = NULL;
+ while (!found && TrackIterate(&trk2) ) {
+ if (trk1 == trk2) continue;
+ for (ep2=0; ep2<GetTrkEndPtCnt(trk2); ep2++) {
+ if (GetTrkEndTrk( trk2, ep2 )) continue;
+ d = FindDistance(GetTrkEndPos(trk1,ep1),GetTrkEndPos(trk2,ep2));
+ a = NormalizeAngle( 180+GetTrkEndAngle( trk1, ep1 ) - GetTrkEndAngle( trk2, ep2 )+(connectAngle/2.0));
+ // Take two passes. In round one favor closer connections. In round two try anything.
+ if ( (i==0 && (d < connectDistance) && (a < connectAngle)) ||
+ (i>0 && (d<3.0 && a<7.5))) { // Match PullTracks criteria in round 2
+ PullTracks(trk1,ep1,trk2,ep2);
+ if (GetTrkEndTrk( trk2, ep2 )) {
+ found = TRUE;
+ if (i==0)
+ countTracksR0++;
+ else
+ countTracksR1++;
+ break; //Stop looking
+ } else if (i==1) possibleEndPoints++;
+ }
+ }
+ }
+ if (found) break; //Next EndPoint
+ }
+ }
+ }
+ }
+ }
+ UndoEnd();
+ NoticeMessage(_("Round 1 %d and Round 2 %d tracks connected, %d close pairs of end Points were not connected"), _("Ok"), NULL, countTracksR0, countTracksR1, possibleEndPoints);
+ return C_TERMINATE;
+
case C_REDRAW:
return C_CONTINUE;
@@ -658,5 +734,5 @@ static STATUS_T CmdPull(
void InitCmdPull( wMenu_p menu )
{
- AddMenuButton( menu, CmdPull, "cmdConnect", _("Connect Sectional Tracks"), wIconCreatePixMap(pull_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP2, ACCL_CONNECT, NULL );
+ AddMenuButton( menu, CmdPull, "cmdConnect", _("Connect Two Tracks"), wIconCreatePixMap(pull_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP2|IC_RCLICK, ACCL_CONNECT, NULL );
}
diff --git a/app/bin/cruler.c b/app/bin/cruler.c
index 6566e93..b1addc6 100644
--- a/app/bin/cruler.c
+++ b/app/bin/cruler.c
@@ -20,8 +20,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include "cundo.h"
+#include "fileio.h"
#include "i18n.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
+
/*****************************************************************************
*
diff --git a/app/bin/cselect.c b/app/bin/cselect.c
index 1bafd45..861f03f 100644
--- a/app/bin/cselect.c
+++ b/app/bin/cselect.c
@@ -1,8 +1,5 @@
/** \file cselect.c
* Handle selecting / unselecting track and basic operations on the selection
- *
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cselect.c,v 1.11 2008-09-05 08:08:15 m_fischer Exp $
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -23,19 +20,30 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
-/*#include "trackx.h"*/
+#include <math.h>
+#include <string.h>
+
#include "ccurve.h"
+#include "tcornu.h"
+#include "tbezier.h"
#define PRIVATE_EXTRADATA
#include "compound.h"
+#include "cselect.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
+#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
#include "bitmaps/bmendpt.xbm"
#include "bitmaps/bma0.xbm"
#include "bitmaps/bma45.xbm"
#include "bitmaps/bma90.xbm"
#include "bitmaps/bma135.xbm"
-#include "i18n.h"
-
#define SETMOVEMODE "MOVEMODE"
@@ -55,8 +63,10 @@ static wDrawBitMap_p angle_bm[4];
long quickMove = 0;
BOOL_T importMove = 0;
int incrementalDrawLimit = 20;
+ static int microCount = 0;
static dynArr_t tlist_da;
+
#define Tlist(N) DYNARR_N( track_p, tlist_da, N )
#define TlistAppend( T ) \
{ DYNARR_APPEND( track_p, tlist_da, 10 );\
@@ -143,6 +153,7 @@ EXPORT void SetAllTrackSelect( BOOL_T select )
SelectedTrackCountChange();
if (doRedraw) {
MainRedraw();
+ MapRedraw();
} else {
wDrawDelayUpdate( mainD.d, FALSE );
}
@@ -174,6 +185,7 @@ EXPORT void InvertTrackSelect( void *ptr )
SelectedTrackCountChange();
MainRedraw();
+ MapRedraw();
}
/* Select orphaned (ie single) track pieces.
@@ -207,6 +219,7 @@ EXPORT void OrphanedTrackSelect( void *ptr )
}
SelectedTrackCountChange();
MainRedraw();
+ MapRedraw();
}
@@ -389,7 +402,7 @@ EXPORT void SelectTunnel( void )
}
-EXPORT void SelectRecount( void )
+void SelectRecount( void )
{
track_p trk;
selectedTrackCount = 0;
@@ -518,6 +531,7 @@ EXPORT void DoRefreshCompound( void )
RefreshCompound( NULL, FALSE );
UndoEnd();
MainRedraw();
+ MapRedraw();
} else {
ErrorMessage( MSG_NO_SELECTED_TRK );
}
@@ -766,9 +780,9 @@ EXPORT void DoRescale( void )
if ( rescalePG.win == NULL ) {
ParamCreateDialog( &rescalePG, MakeWindowTitle(_("Rescale")), _("Ok"), RescaleDlgOk, wHide, TRUE, NULL, F_BLOCK, RescaleDlgUpdate );
LoadScaleList( (wList_p)rescalePLs[I_RESCALE_TO_SCALE].control );
- LoadGaugeList( (wList_p)rescalePLs[I_RESCALE_TO_GAUGE].control, curScaleDescInx ); /* set correct gauge list here */
- rescaleFromScaleInx = curScaleInx;
- rescaleToScaleInx = curScaleInx;
+ LoadGaugeList( (wList_p)rescalePLs[I_RESCALE_TO_GAUGE].control, GetLayoutCurScaleDesc() ); /* set correct gauge list here */
+ rescaleFromScaleInx = GetLayoutCurScale();
+ rescaleToScaleInx = rescaleFromScaleInx;
rescalePercent = 100.0;
}
@@ -1032,6 +1046,10 @@ static void MoveTracks(
track_p trk, trk1;
EPINX_T ep, ep1;
int inx;
+ trackParams_t trackParms;
+ ANGLE_T endAngle;
+ DIST_T endRadius;
+ coOrd endCenter;
wSetCursor( wCursorWait );
/*UndoStart( "Move/Rotate Tracks", "move/rotate" );*/
@@ -1050,12 +1068,57 @@ static void MoveTracks(
RotateTrack( trk, orig, angle );
for (ep=0; ep<GetTrkEndPtCnt(trk); ep++) {
if ((trk1 = GetTrkEndTrk(trk,ep)) != NULL &&
- !GetTrkSelected(trk1)) {
+ !GetTrkSelected(trk1)) {
ep1 = GetEndPtConnectedToMe( trk1, trk );
DisconnectTracks( trk, ep, trk1, ep1 );
+ if (QueryTrack(trk1,Q_IS_CORNU)) { //Cornu at end stays connected
+ GetTrackParams(PARAMS_CORNU,trk,GetTrkEndPos(trk,ep),&trackParms);
+ if (trackParms.type == curveTypeStraight) {
+ endRadius = 0;
+ endCenter = zero;
+ } else {
+ endRadius = trackParms.arcR;
+ endCenter = trackParms.arcP;
+ }
+ DrawTrack(trk1,&mainD,wDrawColorWhite);
+ DrawTrack(trk1,&mapD,wDrawColorWhite);
+ endAngle = NormalizeAngle(GetTrkEndAngle(trk,ep)+180);
+ if (SetCornuEndPt(trk1,ep1,GetTrkEndPos(trk,ep),endCenter,endAngle,endRadius)) {
+ ConnectTracks(trk,ep,trk1,ep1);
+ DrawTrack(trk1,&mainD,wDrawColorBlack);
+ DrawTrack(trk1,&mapD,wDrawColorBlack);
+ } else {
+ DeleteTrack(trk1,TRUE);
+ ErrorMessage(_("Cornu too tight - it was deleted"));
+ }
+ } else {
+ if (QueryTrack(trk,Q_IS_CORNU)) { //I am a Cornu myself!
+ GetTrackParams(PARAMS_CORNU,trk1,GetTrkEndPos(trk1,ep1),&trackParms);
+ if (trackParms.type == curveTypeStraight) {
+ endRadius = 0;
+ endCenter = zero;
+ } else {
+ endRadius = trackParms.arcR;
+ endCenter = trackParms.arcP;
+ }
+ DrawTrack(trk,&mainD,wDrawColorWhite);
+ DrawTrack(trk1,&mapD,wDrawColorWhite);
+ endAngle = NormalizeAngle(GetTrkEndAngle(trk1,ep1)+180);
+ if (SetCornuEndPt(trk,ep,GetTrkEndPos(trk1,ep1),endCenter,endAngle,endRadius)) {
+ ConnectTracks(trk,ep,trk1,ep1);
+ DrawTrack(trk,&mainD,wDrawColorBlack);
+ DrawTrack(trk,&mapD,wDrawColorBlack);
+ } else {
+ ErrorMessage(_("Cornu selected too tight after move - it was left alone"));
+ DrawTrack(trk,&mainD,wDrawColorBlack);
+ DrawTrack(trk,&mapD,wDrawColorBlack);
+ }
+ }
+ }
DrawEndPt( &mainD, trk1, ep1, wDrawColorBlack );
}
}
+
InfoCount( inx );
#ifdef LATER
if (tlist_da.cnt <= incrementalDrawLimit)
@@ -1103,6 +1166,16 @@ void MoveToJoin(
DrawNewTrack( trk0 );
DrawNewTrack( trk1 );
}
+
+void FreeTempStrings() {
+ for (int i = 0; i<tempSegs_da.cnt; i++) {
+ if (tempSegs(i).type == SEG_TEXT) {
+ if (tempSegs(i).u.t.string)
+ MyFree(tempSegs(i).u.t.string);
+ tempSegs(i).u.t.string = NULL;
+ }
+ }
+}
static STATUS_T CmdMove(
wAction_t action,
@@ -1112,7 +1185,7 @@ static STATUS_T CmdMove(
static coOrd orig;
static int state;
- switch( action ) {
+ switch( action&0xFF) {
case C_START:
if (selectedTrackCount == 0) {
@@ -1122,7 +1195,7 @@ static STATUS_T CmdMove(
if (SelectedTracksAreFrozen()) {
return C_TERMINATE;
}
- InfoMessage( _("Drag to move selected tracks") );
+ InfoMessage( _("Drag to move selected tracks - Shift+Ctrl+Arrow micro-steps the move") );
state = 0;
break;
case C_DOWN:
@@ -1134,19 +1207,20 @@ static STATUS_T CmdMove(
orig = pos;
GetMovedTracks(quickMove != MOVE_QUICK);
SetMoveD( TRUE, base, 0.0 );
- DrawMovedTracks();
+ //DrawMovedTracks();
drawCount = 0;
state = 1;
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_MOVE:
drawEnable = enableMoveDraw;
- DrawMovedTracks();
+ //DrawMovedTracks();
base.x = pos.x - orig.x;
base.y = pos.y - orig.y;
SnapPos( &base );
SetMoveD( TRUE, base, 0.0 );
- DrawMovedTracks();
+ //DrawMovedTracks();
#ifdef DRAWCOUNT
InfoMessage( " [%s %s] #%ld", FormatDistance(base.x), FormatDistance(base.y), drawCount );
#else
@@ -1154,10 +1228,12 @@ static STATUS_T CmdMove(
#endif
drawEnable = TRUE;
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_UP:
state = 0;
- DrawMovedTracks();
+ //DrawMovedTracks();
+ FreeTempStrings();
MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, base, zero, 0.0 );
return C_TERMINATE;
@@ -1173,6 +1249,47 @@ static STATUS_T CmdMove(
DrawMovedTracks();
break;
+ case wActionExtKey:
+ if (state) return C_CONTINUE;
+ if (SelectedTracksAreFrozen()) return C_TERMINATE;
+ if ((MyGetKeyState() &
+ (WKEY_SHIFT | WKEY_CTRL)) == (WKEY_SHIFT | WKEY_CTRL)) {
+ base = zero;
+ DIST_T w = tempD.scale/tempD.dpi;
+ switch((wAccelKey_e) action>>8) {
+ case wAccelKey_Up:
+ base.y = w;
+ break;
+ case wAccelKey_Down:
+ base.y = -w;
+ break;
+ case wAccelKey_Left:
+ base.x = -w;
+ break;
+ case wAccelKey_Right:
+ base.x = w;
+ break;
+ default:
+ return C_CONTINUE;
+ break;
+ }
+
+ drawEnable = enableMoveDraw;
+ GetMovedTracks(quickMove!=MOVE_QUICK);
+ UndoStart( _("Move Tracks"), "move" );
+ SetMoveD( TRUE, base, 0.0 );
+ DrawSelectedTracksD( &mainD, wDrawColorWhite );
+ MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, base, zero, 0.0 );
+ ++microCount;
+ if (microCount>5) {
+ microCount = 0;
+ MainRedraw();
+ MapRedraw();
+ }
+ return C_CONTINUE;
+ }
+ break;
+
default:
break;
}
@@ -1214,7 +1331,7 @@ static STATUS_T CmdRotate(
if (SelectedTracksAreFrozen()) {
return C_TERMINATE;
}
- InfoMessage( _("Drag to rotate selected tracks") );
+ InfoMessage( _("Drag to rotate selected tracks, Shift+RightClick for QuickRotate Menu") );
wMenuPushEnable( rotateAlignMI, TRUE );
rotateAlignState = 0;
break;
@@ -1226,9 +1343,22 @@ static STATUS_T CmdRotate(
UndoStart( _("Rotate Tracks"), "rotate" );
if ( rotateAlignState == 0 ) {
drawnAngle = FALSE;
- angle = 0;
+ angle = 0.0;
base = orig = pos;
+ trk = OnTrack(&pos, FALSE, FALSE); //Note pollutes pos if turntable
+ if ((trk) &&
+ QueryTrack(trk,Q_CAN_ADD_ENDPOINTS)) { //Turntable snap to center if within 1/4 radius
+ trackParams_t trackParams;
+ if (GetTrackParams(PARAMS_CORNU, trk, pos, &trackParams)) {
+ DIST_T dist = FindDistance(base, trackParams.ttcenter);
+ if (dist < trackParams.ttradius/4) {
+ base = orig = trackParams.ttcenter;
+ InfoMessage( _("Center of Rotation snapped to Turntable center") );
+ }
+ }
+ }
GetMovedTracks(FALSE);
+ SetMoveD( FALSE, base, angle );
/*DrawLine( &mainD, base, orig, 0, wDrawColorBlack );
DrawMovedTracks(FALSE, orig, angle);*/
} else {
@@ -1256,20 +1386,21 @@ static STATUS_T CmdRotate(
angle = 0;
} else {
angle = NormalizeAngle(angle1-baseAngle);
- if ( angle > 90 && angle < 270 )
- angle = NormalizeAngle( angle + 180.0 );
- if ( NormalizeAngle( FindAngle( pos, pos1 ) - angle1 ) < 180.0 )
- angle = NormalizeAngle( angle + 180.0 );
+ //if ( angle > 90 && angle < 270 )
+ // angle = NormalizeAngle( angle + 180.0 );
+ //if ( NormalizeAngle( FindAngle( base, pos1 ) - angle1 ) < 180.0 )
+ // angle = NormalizeAngle( angle + 180.0 );
/*printf( "angle 1 = %0.3f\n", angle );*/
if ( angle1 > 180.0 ) angle1 -= 180.0;
InfoMessage( _("Angle %0.3f"), angle1 );
}
GetMovedTracks(TRUE);
SetMoveD( FALSE, orig, angle );
- DrawMovedTracks();
+ //DrawMovedTracks();
}
}
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_MOVE:
if ( rotateAlignState == 1 )
@@ -1285,7 +1416,7 @@ static STATUS_T CmdRotate(
ErrorMessage( MSG_2ND_TRACK_MUST_BE_UNSELECTED );
return C_CONTINUE;
}
- DrawMovedTracks();
+ //DrawMovedTracks();
angle1 = NormalizeAngle( GetAngleAtPoint( trk, pos, NULL, NULL ) );
angle = NormalizeAngle(angle1-baseAngle);
if ( angle > 90 && angle < 270 )
@@ -1296,8 +1427,9 @@ static STATUS_T CmdRotate(
InfoMessage( _("Angle %0.3f"), angle1 );
SetMoveD( FALSE, orig, angle );
/*printf( "angle 2 = %0.3f\n", angle );*/
- DrawMovedTracks();
+ //DrawMovedTracks();
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
}
if ( FindDistance( orig, pos ) > (6.0/75.0)*mainD.scale ) {
@@ -1321,7 +1453,7 @@ static STATUS_T CmdRotate(
}
DrawLine( &tempD, base, orig, 0, wDrawColorBlack );
SetMoveD( FALSE, orig, angle );
- DrawMovedTracks();
+ //DrawMovedTracks();
#ifdef DRAWCOUNT
InfoMessage( _(" Angle %0.3f #%ld"), angle, drawCount );
#else
@@ -1331,6 +1463,7 @@ static STATUS_T CmdRotate(
drawEnable = TRUE;
}
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_UP:
state = 0;
@@ -1341,19 +1474,33 @@ static STATUS_T CmdRotate(
}
return C_CONTINUE;
}
+ FreeTempStrings();
if ( rotateAlignState == 2 ) {
- DrawMovedTracks();
+ //DrawMovedTracks();
MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, orig, angle );
rotateAlignState = 0;
} else if (drawnAngle) {
DrawLine( &tempD, base, orig, 0, wDrawColorBlack );
- DrawMovedTracks();
+ //DrawMovedTracks();
MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, orig, angle );
}
MainRedraw();
+ MapRedraw();
return C_TERMINATE;
case C_CMDMENU:
+ base = pos;
+ trk = OnTrack(&pos, FALSE, FALSE); //Note pollutes pos if turntable
+ if ((trk) &&
+ QueryTrack(trk,Q_CAN_ADD_ENDPOINTS)) { //Turntable snap to center if within 1/4 radius
+ trackParams_t trackParams;
+ if (GetTrackParams(PARAMS_CORNU, trk, pos, &trackParams)) {
+ DIST_T dist = FindDistance(base, trackParams.ttcenter);
+ if (dist < trackParams.ttradius/4) {
+ cmdMenuPos = trackParams.ttcenter;
+ }
+ }
+ }
wMenuPopupShow( selectPopup2M );
return C_CONTINUE;
@@ -1371,6 +1518,20 @@ static STATUS_T CmdRotate(
return C_CONTINUE;
}
+static void QuickMove( void* pos) {
+ coOrd move_pos = *(coOrd*)pos;
+ if ( SelectedTracksAreFrozen() )
+ return;
+ wDrawDelayUpdate( mainD.d, TRUE );
+ GetMovedTracks(FALSE);
+ DrawSelectedTracksD( &mainD, wDrawColorWhite );
+ UndoStart( _("Move Tracks"), "Move Tracks" );
+ MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, move_pos, zero, 0.0 );
+ wDrawDelayUpdate( mainD.d, FALSE );
+ MainRedraw();
+ MapRedraw();
+}
+
static void QuickRotate( void* pangle )
{
ANGLE_T angle = (ANGLE_T)(long)pangle;
@@ -1382,6 +1543,8 @@ static void QuickRotate( void* pangle )
UndoStart( _("Rotate Tracks"), "Rotate Tracks" );
MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, cmdMenuPos, angle );
wDrawDelayUpdate( mainD.d, FALSE );
+ MainRedraw();
+ MapRedraw();
}
@@ -1460,11 +1623,26 @@ STATUS_T CmdMoveDescription(
ep = -1;
mode = 2;
}
+ d = CornuDescriptionDistance( pos, trk1 );
+ if ( d < dd ) {
+ dd = d;
+ trk = trk1;
+ ep = -1;
+ mode = 3;
+ }
+ d = BezierDescriptionDistance( pos, trk1 );
+ if ( d < dd ) {
+ dd = d;
+ trk = trk1;
+ ep = -1;
+ mode = 4;
+ }
}
if (trk != NULL) {
UndoStart( _("Move Label"), "Modedesc( T%d )", GetTrkIndex(trk) );
UndoModify( trk );
}
+ /* no break */
case C_MOVE:
case C_UP:
case C_REDRAW:
@@ -1478,9 +1656,13 @@ STATUS_T CmdMoveDescription(
return CompoundDescriptionMove( trk, action, pos );
case 2:
return CurveDescriptionMove( trk, action, pos );
+ case 3:
+ return CornuDescriptionMove( trk, action, pos );
+ case 4:
+ return BezierDescriptionMove( trk, action, pos );
}
}
-
+ break;
case C_CMDMENU:
moveDescTrk = OnTrack( &pos, TRUE, FALSE );
if ( moveDescTrk == NULL ) break;
@@ -1579,6 +1761,7 @@ static STATUS_T CmdFlip(
pos0 = pos1 = pos;
DrawLine( &tempD, pos0, pos1, 0, wDrawColorBlack );
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_MOVE:
DrawLine( &tempD, pos0, pos1, 0, wDrawColorBlack );
@@ -1586,6 +1769,7 @@ static STATUS_T CmdFlip(
DrawLine( &tempD, pos0, pos1, 0, wDrawColorBlack );
InfoMessage( _("Angle %0.2f"), FindAngle( pos0, pos1 ) );
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_UP:
DrawLine( &tempD, pos0, pos1, 0, wDrawColorBlack );
@@ -1593,6 +1777,7 @@ static STATUS_T CmdFlip(
FlipTracks( pos0, FindAngle( pos0, pos1 ) );
state = 0;
MainRedraw();
+ MapRedraw();
return C_TERMINATE;
#ifdef LATER
@@ -1821,6 +2006,18 @@ static STATUS_T CmdSelect(
if (selectedTrackCount <= 0) {
wMenuPopupShow( selectPopup1M );
} else {
+ coOrd base = pos;
+ track_p trk = OnTrack(&pos, FALSE, FALSE); //Note pollutes pos if turntable
+ if ((trk) &&
+ QueryTrack(trk,Q_CAN_ADD_ENDPOINTS)) { //Turntable snap to center if within 1/4 radius
+ trackParams_t trackParams;
+ if (GetTrackParams(PARAMS_CORNU, trk, pos, &trackParams)) {
+ DIST_T dist = FindDistance(base, trackParams.ttcenter);
+ if (dist < trackParams.ttradius/4) {
+ cmdMenuPos = trackParams.ttcenter;
+ }
+ }
+ }
wMenuPopupShow( selectPopup2M );
}
return C_CONTINUE;
@@ -1871,6 +2068,8 @@ EXPORT void InitCmdSelect( wMenu_p menu )
quickMove2M[1] = wMenuToggleCreate( selectPopup2M, "", _("Simple"), 0, quickMove==1, ChangeQuickMove, (void *) 1 );
quickMove2M[2] = wMenuToggleCreate( selectPopup2M, "", _("End Points"), 0, quickMove==2, ChangeQuickMove, (void *) 2 );
wMenuSeparatorCreate( selectPopup2M );
+ AddMoveMenu( selectPopup2M, QuickMove);
+ wMenuSeparatorCreate( selectPopup2M );
AddRotateMenu( selectPopup2M, QuickRotate );
rotateAlignMI = wMenuPushCreate( selectPopup2M, "", _("Align"), 0, (wMenuCallBack_p)RotateAlign, NULL );
ParamRegister( &rescalePG );
diff --git a/app/bin/cselect.h b/app/bin/cselect.h
index 890e53b..c02cc1c 100644
--- a/app/bin/cselect.h
+++ b/app/bin/cselect.h
@@ -1,6 +1,6 @@
-#ifndef CSELECT_H
-#define CSELECT_H
-
+/** \file cselect.h
+ * Definitions and function prototypes for operations on selected elements
+ */
/* XTrkCad - Model Railroad CAD
* Copyright (C) 2005 Dave Bullis
*
@@ -19,6 +19,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef CSELECT_H
+#define CSELECT_H
+
+#include "common.h"
+#include "track.h"
+
wIndex_t selectCmdInx;
wIndex_t moveCmdInx;
wIndex_t rotateCmdInx;
diff --git a/app/bin/csensor.c b/app/bin/csensor.c
index e962089..db34b95 100644
--- a/app/bin/csensor.c
+++ b/app/bin/csensor.c
@@ -47,10 +47,18 @@
static const char rcsid[] = "@(#) : $Id$";
#include <ctype.h>
-#include "track.h"
-#include "trackx.h"
+#include <string.h>
+
#include "compound.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "layout.h"
+#include "param.h"
+#include "track.h"
+#include "trackx.h"
+#include "utility.h"
EXPORT TRKTYP_T T_SENSOR = -1;
@@ -433,28 +441,23 @@ static void CreateNewSensor (coOrd orig)
static STATUS_T CmdSensor ( wAction_t action, coOrd pos )
{
-
-
switch (action) {
case C_START:
InfoMessage(_("Place sensor"));
return C_CONTINUE;
case C_DOWN:
- SnapPos(&pos);
- DDrawSensor( &tempD, pos, GetScaleRatio(curScaleInx), wDrawColorBlack );
- return C_CONTINUE;
- case C_MOVE:
- SnapPos(&pos);
- DDrawSensor( &tempD, pos, GetScaleRatio(curScaleInx), wDrawColorBlack );
+ case C_MOVE:
+ SnapPos(&pos);
+ DDrawSensor( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
return C_CONTINUE;
case C_UP:
SnapPos(&pos);
- DDrawSensor( &tempD, pos, GetScaleRatio(curScaleInx), wDrawColorBlack );
+ DDrawSensor( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
CreateNewSensor(pos);
return C_TERMINATE;
case C_REDRAW:
case C_CANCEL:
- DDrawSensor( &tempD, pos, GetScaleRatio(curScaleInx), wDrawColorBlack );
+ DDrawSensor( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
return C_CONTINUE;
default:
return C_CONTINUE;
diff --git a/app/bin/csignal.c b/app/bin/csignal.c
index 06adb19..2f02e58 100644
--- a/app/bin/csignal.c
+++ b/app/bin/csignal.c
@@ -12,7 +12,7 @@
* Author : $Author$
* Created By : Robert Heller
* Created : Sun Feb 19 13:11:45 2017
- * Last Modified : <170314.1311>
+ * Last Modified : <170417.1113>
*
* Description
*
@@ -48,10 +48,18 @@ static const char rcsid[] = "@(#) : $Id$";
#include <ctype.h>
-#include "track.h"
-#include "trackx.h"
+#include <string.h>
+
#include "compound.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "layout.h"
+#include "param.h"
+#include "track.h"
+#include "trackx.h"
+#include "utility.h"
EXPORT TRKTYP_T T_SIGNAL = -1;
@@ -515,6 +523,7 @@ static void SignalEditOk ( void * junk )
track_p trk;
signalData_p xx;
wIndex_t ia;
+ CSIZE_T newsize;
if (signalCreate_P) {
UndoStart( _("Create Signal"), "Create Signal");
@@ -526,16 +535,15 @@ static void SignalEditOk ( void * junk )
xx = GetsignalData(trk);
if (xx->numAspects != signalAspect_da.cnt) {
/* We need to reallocate the extra data. */
- /* We will delete the Signal and re-create it. */
- BOOL_T visible = GetTrkVisible(trk);
- SCALEINX_T scale = GetTrkScale(trk);
- LAYER_T layer = GetTrkLayer(trk);
- wIndex_t tindx = GetTrkIndex(trk);
- FreeTrack(trk);
- trk = NewTrack(tindx, T_SIGNAL, 0, sizeof(signalData_t)+(sizeof(signalAspect_t)*(signalAspect_da.cnt-1))+1);
- SetTrkVisible(trk,visible);
- SetTrkScale(trk,scale);
- SetTrkLayer(trk,layer);
+ for (ia = 0; ia < xx->numAspects; ia++) {
+ MyFree((&(xx->aspectList))[ia].aspectName);
+ MyFree((&(xx->aspectList))[ia].aspectScript);
+ (&(xx->aspectList))[ia].aspectName = NULL;
+ (&(xx->aspectList))[ia].aspectScript = NULL;
+ }
+ newsize = sizeof(signalData_t)+(sizeof(signalAspect_t)*(signalAspect_da.cnt-1))+1;
+ trk->extraData = MyRealloc(trk->extraData,newsize);
+ trk->extraSize = newsize;
xx = GetsignalData(trk);
}
}
@@ -769,7 +777,7 @@ static STATUS_T CmdSignal ( wAction_t action, coOrd pos )
case C_MOVE:
SnapPos(&pos);
orient = FindAngle(pos0,pos);
- DDrawSignal( &tempD, pos0, orient, 1, GetScaleRatio(curScaleInx), wDrawColorBlack );
+ DDrawSignal( &tempD, pos0, orient, 1, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
return C_CONTINUE;
case C_UP:
SnapPos(&pos);
@@ -778,7 +786,7 @@ static STATUS_T CmdSignal ( wAction_t action, coOrd pos )
return C_TERMINATE;
case C_REDRAW:
case C_CANCEL:
- DDrawSignal( &tempD, pos0, orient, 1, GetScaleRatio(curScaleInx), wDrawColorBlack );
+ DDrawSignal( &tempD, pos0, orient, 1, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
return C_CONTINUE;
default:
return C_CONTINUE;
diff --git a/app/bin/csnap.c b/app/bin/csnap.c
index 1d16136..0f0f353 100644
--- a/app/bin/csnap.c
+++ b/app/bin/csnap.c
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/csnap.c,v 1.7 2008-06-03 15:43:58 m_fischer Exp $
+/** \file csnap.c
+ * Draw Snap Grid
*/
/* XTrkCad - Model Railroad CAD
@@ -20,13 +20,19 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
-#include "i18n.h"
+#include <math.h>
+#include "custom.h"
+#include "fileio.h"
+#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
/*****************************************************************************
*
- * Draw Snap Grid
+
*
*/
diff --git a/app/bin/csplit.c b/app/bin/csplit.c
index 69642fb..6cfdcc8 100644
--- a/app/bin/csplit.c
+++ b/app/bin/csplit.c
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/csplit.c,v 1.4 2008-03-06 19:35:06 m_fischer Exp $
+/** \file csplit.c
+ * SPLIT
*/
/* XTrkCad - Model Railroad CAD
@@ -20,15 +20,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include "cundo.h"
#include "i18n.h"
-
-/*****************************************************************************
- *
- * SPLIT
- *
- */
-
+#include "messages.h"
+#include "track.h"
+#include "utility.h"
static wMenu_p splitPopupM[2];
static wMenuToggle_p splitPopupMI[2][4];
@@ -70,6 +66,7 @@ static STATUS_T CmdSplitTrack( wAction_t action, coOrd pos )
switch (action) {
case C_START:
InfoMessage( _("Select track to split") );
+ /* no break */
case C_DOWN:
case C_MOVE:
return C_CONTINUE;
@@ -82,6 +79,11 @@ static STATUS_T CmdSplitTrack( wAction_t action, coOrd pos )
onTrackInSplit = FALSE;
return C_TERMINATE;
}
+ if (!QueryTrack(trk0,Q_MODIFY_CAN_SPLIT)) {
+ onTrackInSplit = FALSE;
+ InfoMessage(_("Can't Split that Track"));
+ return C_CONTINUE;
+ }
ep0 = PickEndPoint( pos, trk0 );
onTrackInSplit = FALSE;
if (ep0 < 0) {
diff --git a/app/bin/cstraigh.c b/app/bin/cstraigh.c
index 6038c9a..7be25ee 100644
--- a/app/bin/cstraigh.c
+++ b/app/bin/cstraigh.c
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cstraigh.c,v 1.4 2008-03-06 19:35:06 m_fischer Exp $
+/** \file cstraigh.c
+ * STRAIGHT
*/
/* XTrkCad - Model Railroad CAD
@@ -19,22 +19,25 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <math.h>
-#include "track.h"
#include "cstraigh.h"
+#include "cundo.h"
+#include "fileio.h"
#include "i18n.h"
-
-/*******************************************************************************
- *
- * STRAIGHT
- *
- */
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
/*
* STATE INFO
*/
static struct {
coOrd pos0, pos1;
+ track_p trk;
+ EPINX_T ep;
+ BOOL_T down;
} Dl;
@@ -42,15 +45,46 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
{
track_p t;
DIST_T dist;
+ coOrd p;
switch (action) {
case C_START:
- InfoMessage( _("Place 1st end point of Straight track") );
+ Dl.pos0=pos;
+ Dl.pos1=pos;
+ Dl.trk = NULL;
+ Dl.ep=-1;
+ Dl.down = FALSE;
+ InfoMessage( _("Place 1st end point of straight track + Shift -> snap to unconnected endpoint") );
return C_CONTINUE;
case C_DOWN:
- SnapPos( &pos );
+ p = pos;
+ BOOL_T found = FALSE;
+ Dl.trk = NULL;
+ if ((MyGetKeyState() & WKEY_SHIFT) != 0) {
+ if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
+ EPINX_T ep = PickUnconnectedEndPointSilent(p, t);
+ if (ep != -1) {
+ Dl.trk = t;
+ Dl.ep = ep;
+ pos = GetTrkEndPos(t, ep);
+ found = TRUE;
+ } else {
+ InfoMessage(_("No unconnected end-point on track - Try again or release Shift and click"));
+ Dl.pos0=pos;
+ Dl.pos1=pos;
+ return C_CONTINUE;
+ }
+ } else {
+ InfoMessage(_("Not on a track - Try again or release Shift and click"));
+ Dl.pos0=pos;
+ Dl.pos1=pos;
+ return C_CONTINUE;
+ }
+ }
+ Dl.down = TRUE;
+ if (!found) SnapPos( &pos );
Dl.pos0 = pos;
InfoMessage( _("Drag to place 2nd end point") );
DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
@@ -62,8 +96,17 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
return C_CONTINUE;
case C_MOVE:
+ if (!Dl.down) return C_CONTINUE;
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- SnapPos( &pos );
+ ANGLE_T angle, angle2;
+ if (Dl.trk) {
+ angle = NormalizeAngle(GetTrkEndAngle( Dl.trk, Dl.ep));
+ angle2 = NormalizeAngle(FindAngle(pos, Dl.pos0)-angle);
+ if (angle2 > 90.0 && angle2 < 270.0)
+ Translate( &pos, Dl.pos0, angle, FindDistance( Dl.pos0, pos ) );
+ else pos = Dl.pos0;
+ } else SnapPos( &pos );
+
InfoMessage( _("Straight Track Length=%s Angle=%0.3f"),
FormatDistance(FindDistance( Dl.pos0, pos )),
PutAngle(FindAngle( Dl.pos0, pos )) );
@@ -73,15 +116,25 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
return C_CONTINUE;
case C_UP:
+ if (!Dl.down) return C_CONTINUE;
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
tempSegs_da.cnt = 0;
- SnapPos( &pos );
+ if (Dl.trk) {
+ angle = NormalizeAngle(GetTrkEndAngle( Dl.trk, Dl.ep));
+ angle2 = NormalizeAngle(FindAngle(pos, Dl.pos0)-angle);
+ if (angle2 > 90.0 && angle2 < 270.0)
+ Translate( &pos, Dl.pos0, angle, FindDistance( Dl.pos0, pos ));
+ else pos = Dl.pos0;
+ } else SnapPos( &pos );
if ((dist=FindDistance( Dl.pos0, pos )) <= minLength) {
ErrorMessage( MSG_TRK_TOO_SHORT, "Straight ", PutDim(fabs(minLength-dist)) );
return C_TERMINATE;
}
UndoStart( _("Create Straight Track"), "newStraight" );
t = NewStraightTrack( Dl.pos0, pos );
+ if (Dl.trk) {
+ ConnectTracks(Dl.trk, Dl.ep, t, 0);
+ }
UndoEnd();
DrawNewTrack(t);
return C_TERMINATE;
@@ -89,6 +142,7 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
case C_REDRAW:
case C_CANCEL:
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ Dl.down = FALSE;
return C_CONTINUE;
default:
diff --git a/app/bin/cstraigh.h b/app/bin/cstraigh.h
index eca7e99..30d1539 100644
--- a/app/bin/cstraigh.h
+++ b/app/bin/cstraigh.h
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cstraigh.h,v 1.1 2005-12-07 15:46:54 rc-flyer Exp $
+/** \file cstraigh.h
+ * Prototypes for straight track functions
*/
/* XTrkCad - Model Railroad CAD
@@ -20,6 +20,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef HAVE_CSTRAIGH_H
+#define HAVE_CSTRAIGH_H
+
+#include "common.h"
+#include "track.h"
+
void AdjustStraightEndPt( track_p t, EPINX_T ep, coOrd pos );
track_p NewStraightTrack( coOrd p0, coOrd p1 );
BOOL_T ExtendStraightToJoin( track_p, EPINX_T, track_p, EPINX_T );
+
+#endif // !HAVE_CSTRAIGH_H \ No newline at end of file
diff --git a/app/bin/cstruct.c b/app/bin/cstruct.c
index 1f86217..41c47e5 100644
--- a/app/bin/cstruct.c
+++ b/app/bin/cstruct.c
@@ -1,8 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cstruct.c,v 1.4 2008-03-06 19:35:06 m_fischer Exp $
- *
+/** \file cstruct.c
* T_STRUCTURE
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -24,11 +21,20 @@
*/
#include <ctype.h>
-#include "track.h"
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
#include "compound.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
-
-#include <stdint.h>
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
EXPORT TRKTYP_T T_STRUCTURE = -1;
@@ -272,7 +278,7 @@ static ANGLE_T GetAngleStruct(
pos.x -= xx->orig.x;
pos.y -= xx->orig.y;
Rotate( &pos, zero, -xx->angle );
- angle = GetAngleSegs( xx->segCnt, xx->segs, pos, NULL );
+ angle = GetAngleSegs( xx->segCnt, xx->segs, &pos, NULL, NULL, NULL, NULL, NULL);
if ( ep0 ) *ep0 = -1;
if ( ep1 ) *ep1 = -1;
return NormalizeAngle( angle+xx->angle );
@@ -403,7 +409,7 @@ static void structureChange( long changes )
maxStructureDim.x = maxStructureDim.y = 0.0;
if (structureInfo_da.cnt <= 0)
return;
- curStructure = StructAdd( LABEL_TABBED|LABEL_MANUF|LABEL_PARTNO|LABEL_DESCR, curScaleInx, structureListL, &maxStructureDim );
+ curStructure = StructAdd( LABEL_TABBED|LABEL_MANUF|LABEL_PARTNO|LABEL_DESCR, GetLayoutCurScale(), structureListL, &maxStructureDim );
wControlShow( (wControl_p)structureListL, TRUE );
if (curStructure == NULL) {
wDrawClear( structureD.d );
@@ -653,6 +659,7 @@ EXPORT STATUS_T CmdStructureAction(
DrawSegs( &tempD, Dst.pos, Dst.angle,
curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
MainRedraw();
+ MapRedraw();
InfoMessage( "[ %0.3f %0.3f ]", pos.x - origPos.x, pos.y - origPos.y );
return C_CONTINUE;
@@ -701,6 +708,7 @@ EXPORT STATUS_T CmdStructureAction(
DrawLine( &tempD, rot0, rot1, 0, wDrawColorBlack );
case C_UP:
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_CMDMENU:
@@ -854,7 +862,7 @@ EXPORT void AddHotBarStructures( void )
to = structureInfo(inx);
if ( !( IsParamValid(to->paramFileIndex) &&
to->segCnt > 0 &&
- CompatibleScale( FALSE, to->scaleInx, curScaleInx ) ) )
+ CompatibleScale( FALSE, to->scaleInx, GetLayoutCurScale()) ) )
/*( (strcmp( to->scale, "*" ) == 0 && strcasecmp( curScaleName, "DEMO" ) != 0 ) ||
strncasecmp( to->scale, curScaleName, strlen(to->scale) ) == 0 ) ) )*/
continue;
diff --git a/app/bin/cswitchmotor.c b/app/bin/cswitchmotor.c
index dbe006c..3d39a68 100644
--- a/app/bin/cswitchmotor.c
+++ b/app/bin/cswitchmotor.c
@@ -50,10 +50,17 @@
*/
#include <ctype.h>
-#include "track.h"
-#include "trackx.h"
+#include <string.h>
+
#include "compound.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "param.h"
+#include "track.h"
+#include "trackx.h"
+#include "utility.h"
EXPORT TRKTYP_T T_SWITCHMOTOR = -1;
@@ -271,7 +278,7 @@ static DIST_T DistanceSwitchMotor (track_p t, coOrd * p )
{
switchmotorData_p xx = GetswitchmotorData(t);
if (xx->turnout == NULL) return 0;
- return GetTrkDistance(xx->turnout,*p);
+ return GetTrkDistance(xx->turnout,p);
}
static void DescribeSwitchMotor (track_p trk, char * str, CSIZE_T len )
@@ -769,11 +776,11 @@ EXPORT void CheckDeleteSwitchmotor(track_p t)
track_p sm;
switchmotorData_p xx;
- sm = FindSwitchMotor( t );
- if (sm == NULL) return;
- xx = GetswitchmotorData (sm);
- NoticeMessage(_("Deleting Switch Motor %s"),_("Ok"),NULL,xx->name);
- DeleteTrack (sm, FALSE);
+ while ((sm = FindSwitchMotor( t ))) { //Cope with multiple motors for one Turnout!
+ xx = GetswitchmotorData (sm);
+ InfoMessage(_("Deleting Switch Motor %s"),xx->name);
+ DeleteTrack (sm, FALSE);
+ };
}
diff --git a/app/bin/ctext.c b/app/bin/ctext.c
index 525b55a..ca0c7c7 100644
--- a/app/bin/ctext.c
+++ b/app/bin/ctext.c
@@ -1,6 +1,5 @@
/** \file ctext.c
* Text command
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -21,8 +20,15 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include "cundo.h"
+#include "fileio.h"
#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "wlib.h"
+#include "draw.h"
+#include "misc.h"
track_p NewText( wIndex_t index, coOrd p, ANGLE_T angle, char * text, CSIZE_T textSize, wDrawColor color );
@@ -43,11 +49,13 @@ static struct {
coOrd cursPos0, cursPos1;
POS_T cursHeight;
POS_T textLen;
+ POS_T lastLineLen;
+ POS_T lastLineOffset;
coOrd pos;
ANGLE_T angle;
long size;
wIndex_t fontSizeInx;
- char text[STR_SIZE];
+ char text[STR_LONG_SIZE];
wDrawColor color;
} Dt;
@@ -70,31 +78,35 @@ static void TextDlgUpdate(
int inx,
void * context )
{
- coOrd size;
+ coOrd size, lastline;
switch (inx) {
case 0:
+ case 1:
if ( Dt.state == SHOW_TEXT) {
- DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
+ DrawMultiString( &tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0, NULL, NULL );
DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
}
UpdateFontSizeList( &Dt.size, (wList_p)textPLs[0].control, Dt.fontSizeInx );
/*wWinSetBusy( mainW, TRUE );*/
if ( Dt.state == SHOW_TEXT) {
- DrawTextSize( &mainD, Dt.text, NULL, Dt.size, TRUE, &size );
+ DrawMultiLineTextSize( &mainD, Dt.text, NULL, Dt.size, TRUE, &size, &lastline);
Dt.textLen = size.x;
+ Dt.lastLineLen = lastline.x;
+ Dt.lastLineOffset = lastline.y;
}
- DrawTextSize( &mainD, "X", NULL, Dt.size, TRUE, &size );
+ DrawTextSize( &mainD, "Aquilp", NULL, Dt.size, TRUE, &size );
Dt.cursHeight = size.y;
/*wWinSetBusy( mainW, FALSE );*/
if ( Dt.state == SHOW_TEXT) {
- Dt.cursPos0.x = Dt.cursPos1.x = Dt.pos.x+Dt.textLen;
- Dt.cursPos1.y = Dt.pos.y+Dt.cursHeight;
+ Dt.cursPos0.x = Dt.cursPos1.x = Dt.pos.x+Dt.lastLineLen;
+ Dt.cursPos1.y = Dt.pos.y+Dt.cursHeight+Dt.lastLineOffset;
DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
+ DrawMultiString( &tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0, NULL, NULL );
}
MainRedraw();
- break;
+ MapRedraw();
+ break;
}
}
@@ -105,7 +117,7 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
unsigned char c;
wControl_p controls[3];
char * labels[2];
- coOrd size;
+ coOrd size, lastline;
switch (action & 0xFF) {
case C_START:
@@ -114,6 +126,8 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
Dt.len = 0;
Dt.textLen = 0;
Dt.text[0] = '\0';
+ Dt.lastLineLen = 0;
+ Dt.lastLineOffset = 0;
if (textPD.control == NULL)
{
@@ -122,14 +136,14 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
ParamRegister(&textPG);
Dt.size = GetFontSize(Dt.fontSizeInx);
}
- Dt.size = wSelectedFontSize();
+ Dt.size = (long)wSelectedFontSize();
Dt.fontSizeInx = GetFontSizeIndex(Dt.size);
ParamLoadControls(&textPG);
ParamGroupRecord( &textPG );
if (!inPlayback)
wWinSetBusy(mainW, TRUE);
- DrawTextSize(&mainD, "X", NULL, Dt.size, TRUE, &size);
+ DrawTextSize(&mainD, "Aquilp", NULL, Dt.size, TRUE, &size);
Dt.cursHeight = size.y;
if (!inPlayback)
wWinSetBusy(mainW, FALSE);
@@ -144,28 +158,28 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
break;
case C_DOWN:
if (Dt.state != 0) {
- //DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- //DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
}
Dt.pos = pos;
- Dt.cursPos0.y = Dt.cursPos1.y = pos.y;
- Dt.cursPos0.x = Dt.cursPos1.x = pos.x + Dt.textLen;
+ Dt.cursPos0.y = Dt.cursPos1.y = pos.y + Dt.lastLineOffset;
+ Dt.cursPos0.x = Dt.cursPos1.x = pos.x + Dt.lastLineLen;
+ DrawTextSize(&mainD, "Aquilp", NULL, Dt.size, TRUE, &size); //In case fontsize change
+ Dt.cursHeight = size.y;
Dt.cursPos1.y += Dt.cursHeight;
DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
+ DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
Dt.state = SHOW_TEXT;
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_MOVE:
- //DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- //DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
Dt.pos = pos;
- Dt.cursPos0.y = Dt.cursPos1.y = pos.y;
- Dt.cursPos0.x = Dt.cursPos1.x = pos.x + Dt.textLen;
+ Dt.cursPos0.y = Dt.cursPos1.y = pos.y + Dt.lastLineOffset;
+ Dt.cursPos0.x = Dt.cursPos1.x = pos.x + Dt.lastLineLen;
Dt.cursPos1.y += Dt.cursHeight;
DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, wDrawColorBlack );
- DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
+ DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
MainRedraw();
+ MapRedraw();
return C_CONTINUE;
case C_UP:
return C_CONTINUE;
@@ -175,7 +189,7 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
return C_CONTINUE;
}
DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
+ DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
c = (unsigned char)(action >> 8);
switch (c) {
case '\b':
@@ -187,11 +201,17 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
wBeep();
}
break;
+ case '\n': // Line Feed
+ if (Dt.len < sizeof Dt.text - 1 ) {
+ Dt.text[Dt.len++] = (char)c;
+ Dt.text[Dt.len] = '\000';
+ }
+ break;
case '\015':
UndoStart( _("Create Text"), "newText - CR" );
t = NewText( 0, Dt.pos, Dt.angle, Dt.text, (CSIZE_T)Dt.size, Dt.color );
UndoEnd();
- DrawNewTrack(t);
+ DrawNewTrack(t);
Dt.state = POSITION_TEXT;
InfoSubstituteControls( NULL, NULL );
return C_TERMINATE;
@@ -201,26 +221,33 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
Dt.text[Dt.len] = '\000';
}
}
- DrawTextSize( &mainD, Dt.text, NULL, Dt.size, TRUE, &size );
+ DrawMultiLineTextSize( &mainD, Dt.text, NULL, Dt.size, TRUE, &size, &lastline);
Dt.textLen = size.x;
- Dt.cursPos0.x = Dt.cursPos1.x = Dt.pos.x + Dt.textLen;
- DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
+ Dt.lastLineLen = lastline.x;
+ Dt.lastLineOffset = lastline.y;
+ Dt.cursPos0.x = Dt.cursPos1.x = Dt.pos.x + Dt.lastLineLen;
+ Dt.cursPos0.y = Dt.cursPos1.y = Dt.pos.y + Dt.lastLineOffset;
+ DrawTextSize(&mainD, "Aquilp", NULL, Dt.size, TRUE, &size); //In case fontsize change
+ Dt.cursHeight = size.y;
+ Dt.cursPos1.y +=Dt.cursHeight;
+ MainRedraw();
+ MapRedraw();
+ //DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
+ //DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
return C_CONTINUE;
case C_REDRAW:
if (Dt.state == 1) {
DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
+ DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
}
return C_CONTINUE;
case C_CANCEL:
if (Dt.state != POSITION_TEXT) {
- //DrawString( &tempD, Dt.pos, 0.0, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color );
- //DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
Dt.state = POSITION_TEXT;
}
InfoSubstituteControls( NULL, NULL );
MainRedraw();
+ MapRedraw();
return C_TERMINATE;
case C_OK:
if (Dt.state != POSITION_TEXT) {
@@ -235,6 +262,7 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
}
InfoSubstituteControls( NULL, NULL );
MainRedraw();
+ MapRedraw();
return C_TERMINATE;
case C_FINISH:
diff --git a/app/bin/ctodesgn.c b/app/bin/ctodesgn.c
index b5ba768..392b405 100644
--- a/app/bin/ctodesgn.c
+++ b/app/bin/ctodesgn.c
@@ -26,14 +26,22 @@
#endif
#include <stdint.h>
-
#include <ctype.h>
-#include "track.h"
+#include <math.h>
+#include <string.h>
+#include <messages.h>
+
#include "ccurve.h"
-#include "cstraigh.h"
#include "compound.h"
+#include "cstraigh.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
+
#define TURNOUTDESIGNER "CTURNOUT DESIGNER"
@@ -1414,7 +1422,7 @@ static void NewTurnPrint(
wDrawString( newTurnout_d.d, POSX(3.0),
POSY(6.25), 0.0, message, fp, 30,
wDrawColorBlack, 0 );
- sprintf( message, "%s %d x %d (of %d x %d)", _("Page"), i+1, j+1, ii, jj );
+ sprintf( message, _("%s %d x %d (of %d x %d)"), _("Page"), i+1, j+1, ii, jj );
wDrawString( newTurnout_d.d, POSX(3.0),
POSY(5.75), 0.0, message, fp, 20,
wDrawColorBlack, 0 );
@@ -2176,14 +2184,14 @@ EXPORT BOOL_T WriteSegs(
case SEG_CRVLIN:
rc &= fprintf( f, "\t%c %ld %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f\n",
segs[i].type, (segs[i].type==SEG_CRVTRK?0:roadbedColorRGB), segs[i].width,
- segs[i].u.c.radius,
+ fabs(segs[i].u.c.radius),
segs[i].u.c.center.x, segs[i].u.c.center.y,
segs[i].u.c.a0, segs[i].u.c.a1 )>0;
break;
case SEG_FILCRCL:
rc &= fprintf( f, "\t%c %ld %0.6f %0.6f %0.6f %0.6f\n",
segs[i].type, roadbedColorRGB, segs[i].width,
- segs[i].u.c.radius,
+ fabs(segs[i].u.c.radius),
segs[i].u.c.center.x, segs[i].u.c.center.y )>0;
break;
case SEG_POLY:
diff --git a/app/bin/ctrain.c b/app/bin/ctrain.c
index d3eb00a..d480982 100644
--- a/app/bin/ctrain.c
+++ b/app/bin/ctrain.c
@@ -1,6 +1,5 @@
/** \file ctrain.c
* Functions related to running trains
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -25,37 +24,47 @@
#include <errno.h>
#endif
#include <ctype.h>
+#include <math.h>
+#include <string.h>
#define PRIVATE_EXTRADATA
-#include "track.h"
-#include "trackx.h"
-#include "ctrain.h"
+
#include "compound.h"
+#include "ctrain.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "trackx.h"
+#include "utility.h"
-EXPORT long programMode;
-EXPORT long maxCouplingSpeed = 100;
-EXPORT long hideTrainsInTunnels;
+long programMode;
+long maxCouplingSpeed = 100;
+long hideTrainsInTunnels;
extern int doDrawTurnoutPosition;
-extern void NextTurnoutPosition( track_p );
+extern void NextTurnoutPosition(track_p);
static TRKTYP_T T_CAR = -1;
typedef enum { ST_NotOnTrack, ST_StopManual, ST_EndOfTrack, ST_OpenTurnout, ST_NoRoom, ST_Crashed } trainStatus_e;
struct extraData {
- traverseTrack_t trvTrk;
- long state;
- carItem_p item;
- double speed;
- BOOL_T direction;
- BOOL_T autoReverse;
- trainStatus_e status;
- DIST_T distance;
- coOrd couplerPos[2];
- LAYER_T trkLayer;
- };
+ traverseTrack_t trvTrk;
+ long state;
+ carItem_p item;
+ double speed;
+ BOOL_T direction;
+ BOOL_T autoReverse;
+ trainStatus_e status;
+ DIST_T distance;
+ coOrd couplerPos[2];
+ unsigned int trkLayer;
+};
#define NOTALAYER (127)
#define CAR_STATE_IGNORED (1L<<17)
@@ -63,16 +72,14 @@ struct extraData {
#define CAR_STATE_LOCOISMASTER (1L<<19)
#define CAR_STATE_ONHIDENTRACK (1L<<20)
+#define COUPLERCONNECTIONANGLE 45.0
+#define CRASHSPEEDDECAY 5
#define IsOnTrack( XX ) ((XX)->trvTrk.trk!=NULL)
#define IsIgnored( XX ) (((XX)->state&CAR_STATE_IGNORED)!=0)
#define SetIgnored( XX ) (XX)->state |= CAR_STATE_IGNORED
#define ClrIgnored( XX ) (XX)->state &= ~CAR_STATE_IGNORED
-#ifdef LATER
-#define IsLocoMaster( XX ) (((XX)->state&CAR_STATE_LOCOISMASTER)!=0)
-#define SetLocoMaster( XX ) (XX)->state |= CAR_STATE_LOCOISMASTER
-#define ClrLocoMaster( XX ) (XX)->state &= ~CAR_STATE_LOCOISMASTER
-#endif
+
#define IsLocoMaster( XX ) CarItemIsLocoMaster((XX)->item)
#define SetLocoMaster( XX ) CarItemSetLocoMaster((XX)->item,TRUE)
#define ClrLocoMaster( XX ) CarItemSetLocoMaster((XX)->item,FALSE)
@@ -82,8 +89,8 @@ struct extraData {
static wButton_p newcarB;
-static void ControllerDialogSyncAll( void );
-static STATUS_T CmdTrain( wAction_t, coOrd );
+static void ControllerDialogSyncAll(void);
+static STATUS_T CmdTrain(wAction_t, coOrd);
static wMenu_p trainPopupM;
static wMenuPush_p trainPopupMI[8];
static track_p followTrain;
@@ -91,16 +98,16 @@ static coOrd followCenter;
static BOOL_T trainsTimeoutPending;
static enum { TRAINS_STOP, TRAINS_RUN, TRAINS_IDLE, TRAINS_PAUSE } trainsState;
static wIcon_p stopI, goI;
-static void RestartTrains( void );
-static void DrawAllCars( void );
-static void UncoupleCars( track_p, track_p );
-static void TrainTimeEndPause( void );
-static void TrainTimeStartPause( void );
+static void RestartTrains(void);
+static void DrawAllCars(void);
+static void UncoupleCars(track_p, track_p);
+static void TrainTimeEndPause(void);
+static void TrainTimeStartPause(void);
static int log_trainMove;
static int log_trainPlayback;
-static void PlaceCar( track_p );
+static void PlaceCar(track_p);
#define WALK_CARS_START( CAR, XX, DIR ) \
@@ -123,151 +130,175 @@ static void PlaceCar( track_p );
* Generic Commands
*/
-EXPORT void CarGetPos(
- track_p car,
- coOrd * posR,
- ANGLE_T * angleR )
+void CarGetPos(
+ track_p car,
+ coOrd * posR,
+ ANGLE_T * angleR)
{
- struct extraData * xx = GetTrkExtraData( car );
- if ( GetTrkType(car) != T_CAR )
- AbortProg( "getCarPos" );
- *posR = xx->trvTrk.pos;
- *angleR = xx->trvTrk.angle;
+ struct extraData * xx = GetTrkExtraData(car);
+
+ if (GetTrkType(car) != T_CAR) {
+ AbortProg("getCarPos");
+ }
+
+ *posR = xx->trvTrk.pos;
+ *angleR = xx->trvTrk.angle;
}
-EXPORT void CarSetVisible(
- track_p car )
+void CarSetVisible(
+ track_p car)
{
- struct extraData * xx;
- int dir;
- dir = 0;
- WALK_CARS_START( car, xx, dir )
- if ( GetTrkType(car) != T_CAR )
- AbortProg( "carSetVisible" );
- WALK_CARS_END( car, xx, dir )
- dir = 1-dir;
- WALK_CARS_START( car, xx, dir ) {
- xx->state &= ~(CAR_STATE_ONHIDENTRACK);
- xx->trkLayer = NOTALAYER;
- }
- WALK_CARS_END( car, xx, dir )
+ struct extraData * xx;
+ int dir;
+ dir = 0;
+ WALK_CARS_START(car, xx, dir)
+
+ if (GetTrkType(car) != T_CAR) {
+ AbortProg("carSetVisible");
+ }
+
+ WALK_CARS_END(car, xx, dir)
+ dir = 1-dir;
+ WALK_CARS_START(car, xx, dir) {
+ xx->state &= ~(CAR_STATE_ONHIDENTRACK);
+ xx->trkLayer = NOTALAYER;
+ }
+ WALK_CARS_END(car, xx, dir)
}
static struct {
- long index;
- coOrd pos;
- ANGLE_T angle;
- DIST_T length;
- DIST_T width;
- char desc[STR_SIZE];
- char number[STR_SIZE];
- } carData;
+ long index;
+ coOrd pos;
+ ANGLE_T angle;
+ DIST_T length;
+ DIST_T width;
+ char desc[STR_SIZE];
+ char number[STR_SIZE];
+} carData;
typedef enum { IT, PN, AN, LN, WD, DE, NM } carDesc_e;
static descData_t carDesc[] = {
-/*IT*/ { DESC_LONG, N_("Index"), &carData.index },
-/*PN*/ { DESC_POS, N_("Position"), &carData.pos },
-/*AN*/ { DESC_ANGLE, N_("Angle"), &carData.angle },
-/*LN*/ { DESC_DIM, N_("Length"), &carData.length },
-/*WD*/ { DESC_DIM, N_("Width"), &carData.width },
-/*DE*/ { DESC_STRING, N_("Description"), &carData.desc },
-/*NM*/ { DESC_STRING, N_("Rep Marks"), &carData.number },
- { DESC_NULL } };
+ /*IT*/ { DESC_LONG, N_("Index"), &carData.index },
+ /*PN*/ { DESC_POS, N_("Position"), &carData.pos },
+ /*AN*/ { DESC_ANGLE, N_("Angle"), &carData.angle },
+ /*LN*/ { DESC_DIM, N_("Length"), &carData.length },
+ /*WD*/ { DESC_DIM, N_("Width"), &carData.width },
+ /*DE*/ { DESC_STRING, N_("Description"), &carData.desc },
+ /*NM*/ { DESC_STRING, N_("Rep Marks"), &carData.number },
+ { DESC_NULL }
+};
static void UpdateCar(
- track_p trk,
- int inx,
- descData_p descUpd,
- BOOL_T needUndoStart )
+ track_p trk,
+ int inx,
+ descData_p descUpd,
+ BOOL_T needUndoStart)
{
- BOOL_T titleChanged;
- const char * cp;
- if ( inx == -1 ) {
- titleChanged = FALSE;
- cp = wStringGetValue( (wString_p)carDesc[NM].control0 );
- if ( cp && strcmp( carData.number, cp ) != 0 ) {
- titleChanged = TRUE;
- strcpy( carData.number, cp );
- }
- if ( !titleChanged )
- return;
- if ( needUndoStart )
- UndoStart( _("Change Track"), "Change Track" );
- UndoModify( trk );
- UndrawNewTrack( trk );
- DrawNewTrack( trk );
- return;
- }
- UndrawNewTrack( trk );
- switch (inx) {
- case NM:
- break;
- default:
- break;
- }
- DrawNewTrack( trk );
+ if (inx == -1) {
+ BOOL_T titleChanged;
+ const char * cp;
+ titleChanged = FALSE;
+ cp = wStringGetValue((wString_p)carDesc[NM].control0);
+
+ if (cp && strcmp(carData.number, cp) != 0) {
+ titleChanged = TRUE;
+ strcpy(carData.number, cp);
+ }
+
+ if (!titleChanged) {
+ return;
+ }
+
+ if (needUndoStart) {
+ UndoStart(_("Change Track"), "Change Track");
+ }
+
+ UndoModify(trk);
+ UndrawNewTrack(trk);
+ DrawNewTrack(trk);
+ return;
+ }
+
+ UndrawNewTrack(trk);
+
+ switch (inx) {
+ case NM:
+ break;
+
+ default:
+ break;
+ }
+
+ DrawNewTrack(trk);
}
static void DescribeCar(
- track_p trk,
- char * str,
- CSIZE_T len )
+ track_p trk,
+ char * str,
+ CSIZE_T len)
+{
+ struct extraData *xx = GetTrkExtraData(trk);
+ char * cp;
+ coOrd size;
+ CarItemSize(xx->item, &size);
+ carData.length = size.x;
+ carData.width = size.y;
+ cp = CarItemDescribe(xx->item, 0, &carData.index);
+ strcpy(carData.number, CarItemNumber(xx->item));
+ strncpy(str, cp, len);
+ carData.pos = xx->trvTrk.pos;
+ carData.angle = xx->trvTrk.angle;
+ cp = CarItemDescribe(xx->item, -1, NULL);
+ strncpy(carData.desc, cp, sizeof carData.desc);
+ carDesc[IT].mode =
+ carDesc[PN].mode =
+ carDesc[AN].mode =
+ carDesc[LN].mode =
+ carDesc[WD].mode = DESC_RO;
+ carDesc[DE].mode =
+ carDesc[NM].mode = DESC_RO;
+ DoDescribe(_("Car"), trk, carDesc, UpdateCar);
+}
+
+
+void FlipTraverseTrack(
+ traverseTrack_p trvTrk)
{
- struct extraData *xx = GetTrkExtraData(trk);
- char * cp;
- coOrd size;
-
- CarItemSize( xx->item, &size );
- carData.length = size.x;
- carData.width = size.y;
- cp = CarItemDescribe( xx->item, 0, &carData.index );
- strcpy( carData.number, CarItemNumber(xx->item) );
- strncpy( str, cp, len );
- carData.pos = xx->trvTrk.pos;
- carData.angle = xx->trvTrk.angle;
- cp = CarItemDescribe( xx->item, -1, NULL );
- strncpy( carData.desc, cp, sizeof carData.desc );
- carDesc[IT].mode =
- carDesc[PN].mode =
- carDesc[AN].mode =
- carDesc[LN].mode =
- carDesc[WD].mode = DESC_RO;
- carDesc[DE].mode =
- carDesc[NM].mode = DESC_RO;
- DoDescribe( _("Car"), trk, carDesc, UpdateCar );
+ trvTrk->angle = NormalizeAngle(trvTrk->angle + 180.0);
+
+ if (trvTrk->length > 0) {
+ trvTrk->dist = trvTrk->length - trvTrk->dist;
+ }
}
-EXPORT void FlipTraverseTrack(
- traverseTrack_p trvTrk )
+BOOL_T TraverseTrack2(
+ traverseTrack_p trvTrk0,
+ DIST_T dist0)
{
- trvTrk->angle = NormalizeAngle( trvTrk->angle + 180.0 );
- if ( trvTrk->length > 0 )
- trvTrk->dist = trvTrk->length - trvTrk->dist;
-}
+ traverseTrack_t trvTrk = *trvTrk0;
+ DIST_T dist = dist0;
+ if (dist0 < 0) {
+ dist = -dist;
+ FlipTraverseTrack(&trvTrk);
+ }
-EXPORT BOOL_T TraverseTrack2(
- traverseTrack_p trvTrk0,
- DIST_T dist0 )
-{
- traverseTrack_t trvTrk = *trvTrk0;
- DIST_T dist = dist0;
- if ( dist0 < 0 ) {
- dist = -dist;
- FlipTraverseTrack( &trvTrk );
- }
- if ( trvTrk.trk==NULL ||
- (!TraverseTrack(&trvTrk,&dist)) ||
- trvTrk.trk==NULL ||
- dist!=0.0 ) {
- Translate( &trvTrk.pos, trvTrk.pos, trvTrk.angle, dist );
- }
- if ( dist0 < 0 )
- FlipTraverseTrack( &trvTrk );
- *trvTrk0 = trvTrk;
- return TRUE;
+ if (trvTrk.trk==NULL ||
+ (!TraverseTrack(&trvTrk,&dist)) ||
+ trvTrk.trk==NULL ||
+ dist!=0.0) {
+ Translate(&trvTrk.pos, trvTrk.pos, trvTrk.angle, dist);
+
+ }
+
+ if (dist0 < 0) {
+ FlipTraverseTrack(&trvTrk);
+ }
+
+ *trvTrk0 = trvTrk;
+ return TRUE;
}
@@ -276,220 +307,238 @@ static BOOL_T drawCarEnable = TRUE;
static BOOL_T noCarDraw = FALSE;
static void DrawCar(
- track_p car,
- drawCmd_p d,
- wDrawColor color )
+ track_p car,
+ drawCmd_p d,
+ wDrawColor color)
{
- struct extraData * xx = GetTrkExtraData(car);
- int dir;
- vector_t coupler[2];
- track_p car1;
- struct extraData * xx1;
- int dir1;
-
- if ( drawCarEnable == FALSE )
- return;
- /*d = &tempD;*/
-/*
- if ( !IsVisible(xx) )
- return;
-*/
- if ( d == &mapD )
- return;
- if ( noCarDraw )
- return;
- if ( hideTrainsInTunnels &&
- ( (((xx->state&CAR_STATE_ONHIDENTRACK)!=0) && drawTunnel==0) ||
- (xx->trkLayer!=NOTALAYER && !GetLayerVisible(xx->trkLayer)) ) )
- return;
-
- for ( dir=0; dir<2; dir++ ) {
- coupler[dir].pos = xx->couplerPos[dir];
- if ( (car1 = GetTrkEndTrk(car,dir)) ) {
- xx1 = GetTrkExtraData(car1);
- dir1 = (GetTrkEndTrk(car1,0)==car)?0:1;
- coupler[dir].angle = FindAngle( xx->couplerPos[dir], xx1->couplerPos[dir1] );
- } else {
- coupler[dir].angle = NormalizeAngle(xx->trvTrk.angle+(dir==0?0.0:180.0)-15.0);
- }
- }
- CarItemDraw( d, xx->item, color, xx->direction, IsLocoMaster(xx), coupler );
+ struct extraData * xx = GetTrkExtraData(car);
+ int dir;
+ vector_t coupler[2];
+ struct extraData * xx1;
+ int dir1;
+
+ if (drawCarEnable == FALSE) {
+ return;
+ }
+
+ if (d == &mapD) {
+ return;
+ }
+
+ if (noCarDraw) {
+ return;
+ }
+
+ if (hideTrainsInTunnels &&
+ ((((xx->state&CAR_STATE_ONHIDENTRACK)!=0) && drawTunnel==0) ||
+ (xx->trkLayer!=NOTALAYER && !GetLayerVisible(xx->trkLayer)))) {
+ return;
+ }
+
+ for (dir=0; dir<2; dir++) {
+ track_p car1;
+ coupler[dir].pos = xx->couplerPos[dir];
+
+ if ((car1 = GetTrkEndTrk(car,dir))) {
+ xx1 = GetTrkExtraData(car1);
+ dir1 = (GetTrkEndTrk(car1,0)==car)?0:1;
+ coupler[dir].angle = FindAngle(xx->couplerPos[dir], xx1->couplerPos[dir1]);
+ } else {
+ coupler[dir].angle = NormalizeAngle(xx->trvTrk.angle+(dir==0?0.0:180.0)-15.0);
+ }
+ }
+
+ CarItemDraw(d, xx->item, color, xx->direction, IsLocoMaster(xx), coupler);
}
static DIST_T DistanceCar(
- track_p trk,
- coOrd * pos )
+ track_p trk,
+ coOrd * pos)
{
- struct extraData * xx = GetTrkExtraData(trk);
- DIST_T dist;
- coOrd pos1;
- coOrd size;
-
- xx = GetTrkExtraData(trk);
- if ( IsIgnored(xx) )
- return 10000.0;
-
- CarItemSize( xx->item, &size ); /* TODO assumes xx->trvTrk.pos is the car center */
- dist = FindDistance( *pos, xx->trvTrk.pos );
- if ( dist < size.x/2.0 ) {
- pos1 = *pos;
- Rotate( &pos1, xx->trvTrk.pos, -xx->trvTrk.angle );
- pos1.x += -xx->trvTrk.pos.x + size.y/2.0; /* TODO: why not size.x? */
- pos1.y += -xx->trvTrk.pos.y + size.x/2.0;
- if ( pos1.x >= 0 && pos1.x <= size.y &&
- pos1.y >= 0 && pos1.y <= size.x )
- dist = 0;
- }
- *pos = xx->trvTrk.pos;
- return dist;
-}
+ struct extraData * xx = GetTrkExtraData(trk);
+ DIST_T dist;
+ coOrd pos1;
+ coOrd size;
+ if (IsIgnored(xx)) {
+ return 10000.0;
+ }
-static void SetCarBoundingBox(
- track_p car )
-{
- struct extraData * xx = GetTrkExtraData(car);
- coOrd lo, hi, p[4];
- int inx;
- coOrd size;
-
-/* TODO: should be bounding box of all pieces aligned on track */
- CarItemSize( xx->item, &size ); /* TODO assumes xx->trvTrk.pos is the car center */
- Translate( &p[0], xx->trvTrk.pos, xx->trvTrk.angle, size.x/2.0 );
- Translate( &p[1], p[0], xx->trvTrk.angle+90, size.y/2.0 );
- Translate( &p[0], p[0], xx->trvTrk.angle-90, size.y/2.0 );
- Translate( &p[2], xx->trvTrk.pos, xx->trvTrk.angle+180, size.x/2.0 );
- Translate( &p[3], p[2], xx->trvTrk.angle+90, size.y/2.0 );
- Translate( &p[2], p[2], xx->trvTrk.angle-90, size.y/2.0 );
- lo = hi = p[0];
- for ( inx = 1; inx < 4; inx++ ) {
- if ( p[inx].x < lo.x )
- lo.x = p[inx].x;
- if ( p[inx].y < lo.y )
- lo.y = p[inx].y;
- if ( p[inx].x > hi.x )
- hi.x = p[inx].x;
- if ( p[inx].y > hi.y )
- hi.y = p[inx].y;
- }
- SetBoundingBox( car, hi, lo );
+ CarItemSize(xx->item,
+ &size); /* TODO assumes xx->trvTrk.pos is the car center */
+ dist = FindDistance(*pos, xx->trvTrk.pos);
+
+ if (dist < size.x/2.0) {
+ pos1 = *pos;
+ Rotate(&pos1, xx->trvTrk.pos, -xx->trvTrk.angle);
+ pos1.x += -xx->trvTrk.pos.x + size.y/2.0; /* TODO: why not size.x? */
+ pos1.y += -xx->trvTrk.pos.y + size.x/2.0;
+ if (pos1.x >= 0 && pos1.x <= size.y &&
+ pos1.y >= 0 && pos1.y <= size.x) {
+ dist = 0;
+ }
+ }
+
+ *pos = xx->trvTrk.pos;
+ return dist;
}
-EXPORT track_p NewCar(
- wIndex_t index,
- carItem_p item,
- coOrd pos,
- ANGLE_T angle )
+static void SetCarBoundingBox(
+ track_p car)
{
- track_p trk;
- struct extraData * xx;
-
- trk = NewTrack( index, T_CAR, 2, sizeof (*xx) );
- /*SetEndPts( trk, 0 );*/
- xx = GetTrkExtraData(trk);
- /*SetTrkVisible( trk, IsVisible(xx) );*/
- xx->item = item;
- xx->trvTrk.pos = pos;
- xx->trvTrk.angle = angle;
- xx->state = 0;
- SetCarBoundingBox( trk );
- CarItemSetTrack( item, trk );
- PlaceCar( trk );
- return trk;
+ struct extraData * xx = GetTrkExtraData(car);
+ coOrd lo, hi, p[4];
+ int inx;
+ coOrd size;
+ /* TODO: should be bounding box of all pieces aligned on track */
+ CarItemSize(xx->item,
+ &size); /* TODO assumes xx->trvTrk.pos is the car center */
+ Translate(&p[0], xx->trvTrk.pos, xx->trvTrk.angle, size.x/2.0);
+ Translate(&p[1], p[0], xx->trvTrk.angle+90, size.y/2.0);
+ Translate(&p[0], p[0], xx->trvTrk.angle-90, size.y/2.0);
+ Translate(&p[2], xx->trvTrk.pos, xx->trvTrk.angle+180, size.x/2.0);
+ Translate(&p[3], p[2], xx->trvTrk.angle+90, size.y/2.0);
+ Translate(&p[2], p[2], xx->trvTrk.angle-90, size.y/2.0);
+ lo = hi = p[0];
+
+ for (inx = 1; inx < 4; inx++) {
+ if (p[inx].x < lo.x) {
+ lo.x = p[inx].x;
+ }
+
+ if (p[inx].y < lo.y) {
+ lo.y = p[inx].y;
+ }
+
+ if (p[inx].x > hi.x) {
+ hi.x = p[inx].x;
+ }
+
+ if (p[inx].y > hi.y) {
+ hi.y = p[inx].y;
+ }
+ }
+
+ SetBoundingBox(car, hi, lo);
+}
+
+
+track_p NewCar(
+ wIndex_t index,
+ carItem_p item,
+ coOrd pos,
+ ANGLE_T angle)
+{
+ track_p trk;
+ struct extraData * xx;
+ trk = NewTrack(index, T_CAR, 2, sizeof(*xx));
+ /*SetEndPts( trk, 0 );*/
+ xx = GetTrkExtraData(trk);
+ /*SetTrkVisible( trk, IsVisible(xx) );*/
+ xx->item = item;
+ xx->trvTrk.pos = pos;
+ xx->trvTrk.angle = angle;
+ xx->state = 0;
+ SetCarBoundingBox(trk);
+ CarItemSetTrack(item, trk);
+ PlaceCar(trk);
+ return trk;
}
static void DeleteCar(
- track_p trk )
+ track_p trk)
{
- struct extraData * xx = GetTrkExtraData(trk);
- CarItemSetTrack( xx->item, NULL );
+ struct extraData * xx = GetTrkExtraData(trk);
+ CarItemSetTrack(xx->item, NULL);
}
static void ReadCar(
- char * line )
+ char * line)
{
- CarItemRead( line );
+ CarItemRead(line);
}
static BOOL_T WriteCar(
- track_p trk,
- FILE * f )
+ track_p trk,
+ FILE * f)
{
- BOOL_T rc = TRUE;
- return rc;
+ BOOL_T rc = TRUE;
+ return rc;
}
static void MoveCar(
- track_p car,
- coOrd pos )
+ track_p car,
+ coOrd pos)
{
- struct extraData *xx = GetTrkExtraData(car);
- xx->trvTrk.pos.x += pos.x;
- xx->trvTrk.pos.y += pos.y;
- xx->trvTrk.trk = NULL;
- PlaceCar( car );
- SetCarBoundingBox(car);
+ struct extraData *xx = GetTrkExtraData(car);
+ xx->trvTrk.pos.x += pos.x;
+ xx->trvTrk.pos.y += pos.y;
+ xx->trvTrk.trk = NULL;
+ PlaceCar(car);
+ SetCarBoundingBox(car);
}
static void RotateCar(
- track_p car,
- coOrd pos,
- ANGLE_T angle )
+ track_p car,
+ coOrd pos,
+ ANGLE_T angle)
{
- struct extraData *xx = GetTrkExtraData(car);
- Rotate( &xx->trvTrk.pos, pos, angle );
- xx->trvTrk.angle = NormalizeAngle( xx->trvTrk.angle + angle );
- xx->trvTrk.trk = NULL;
- PlaceCar( car );
- SetCarBoundingBox( car );
+ struct extraData *xx = GetTrkExtraData(car);
+ Rotate(&xx->trvTrk.pos, pos, angle);
+ xx->trvTrk.angle = NormalizeAngle(xx->trvTrk.angle + angle);
+ xx->trvTrk.trk = NULL;
+ PlaceCar(car);
+ SetCarBoundingBox(car);
}
-static BOOL_T QueryCar( track_p trk, int query )
+static BOOL_T QueryCar(track_p trk, int query)
{
- switch ( query ) {
- case Q_NODRAWENDPT:
- return TRUE;
- default:
- return FALSE;
- }
+ switch (query) {
+ case Q_NODRAWENDPT:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
}
static trackCmd_t carCmds = {
- "CAR ",
- DrawCar, /* draw */
- DistanceCar, /* distance */
- DescribeCar, /* describe */
- DeleteCar, /* delete */
- WriteCar, /* write */
- ReadCar, /* read */
- MoveCar, /* move */
- RotateCar, /* rotate */
- NULL, /* rescale */
- NULL, /* audit */
- NULL, /* getAngle */
- NULL, /* split */
- NULL, /* traverse */
- NULL, /* enumerate */
- NULL, /* redraw*/
- NULL, /* trim*/
- NULL, /* merge*/
- NULL, /* modify */
- NULL, /* getLength */
- NULL, /* getParams */
- NULL, /* moveEndPt */
- QueryCar, /* query */
- NULL, /* ungroup */
- NULL, /* flip */ };
+ "CAR ",
+ DrawCar, /* draw */
+ DistanceCar, /* distance */
+ DescribeCar, /* describe */
+ DeleteCar, /* delete */
+ WriteCar, /* write */
+ ReadCar, /* read */
+ MoveCar, /* move */
+ RotateCar, /* rotate */
+ NULL, /* rescale */
+ NULL, /* audit */
+ NULL, /* getAngle */
+ NULL, /* split */
+ NULL, /* traverse */
+ NULL, /* enumerate */
+ NULL, /* redraw*/
+ NULL, /* trim*/
+ NULL, /* merge*/
+ NULL, /* modify */
+ NULL, /* getLength */
+ NULL, /* getParams */
+ NULL, /* moveEndPt */
+ QueryCar, /* query */
+ NULL, /* ungroup */
+ NULL, /* flip */
+};
/*
*
@@ -505,36 +554,37 @@ static int numTrainDlg;
#define MAX_SPEED (100.0)
typedef struct {
- wWin_p win;
- wIndex_t inx;
- track_p train;
- long direction;
- long followMe;
- long autoReverse;
- coOrd pos;
- char posS[STR_SHORT_SIZE];
- DIST_T speed;
- char speedS[10];
- paramGroup_p trainPGp;
- } trainControlDlg_t, * trainControlDlg_p;
+ wWin_p win;
+ wIndex_t inx;
+ track_p train;
+ long direction;
+ long followMe;
+ long autoReverse;
+ coOrd pos;
+ char posS[STR_SHORT_SIZE];
+ DIST_T speed;
+ char speedS[10];
+ paramGroup_p trainPGp;
+} trainControlDlg_t, * trainControlDlg_p;
static trainControlDlg_t * curTrainDlg;
-static void SpeedRedraw( wDraw_p, void *, wPos_t, wPos_t );
-static void SpeedAction( wAction_t, coOrd );
-static void LocoListChangeEntry( track_p, track_p );
-static void CmdTrainExit( void * );
+static void SpeedRedraw(wDraw_p, void *, wPos_t, wPos_t);
+static void SpeedAction(wAction_t, coOrd);
+static void LocoListChangeEntry(track_p, track_p);
+static void CmdTrainExit(void *);
drawCmd_t speedD = {
- NULL,
- &screenDrawFuncs,
- 0,
- 1.0,
- 0.0,
- { 0.0, 0.0 },
- { 0.0, 0.0 },
- Pix2CoOrd,
- CoOrd2Pix };
+ NULL,
+ &screenDrawFuncs,
+ 0,
+ 1.0,
+ 0.0,
+ { 0.0, 0.0 },
+ { 0.0, 0.0 },
+ Pix2CoOrd,
+ CoOrd2Pix
+};
static paramDrawData_t speedParamData = { SLIDER_WIDTH, SLIDER_HEIGHT, SpeedRedraw, SpeedAction, &speedD };
#ifndef WINDOWS
static paramListData_t listData = { 3, 120 };
@@ -544,52 +594,56 @@ static char * trainAutoReverseLabels[] = { N_("Auto Reverse"), NULL };
static paramData_t trainPLs[] = {
#define I_LIST (0)
#ifdef WINDOWS
-/*0*/ { PD_DROPLIST, NULL, "list", PDO_NOPREF|PDO_NOPSHUPD, (void*)120, NULL, 0 },
+ /*0*/ { PD_DROPLIST, NULL, "list", PDO_NOPREF|PDO_NOPSHUPD, (void*)120, NULL, 0 },
#else
-/*0*/ { PD_LIST, NULL, "list", PDO_NOPREF|PDO_NOPSHUPD, &listData, NULL, 0 },
+ /*0*/ { PD_LIST, NULL, "list", PDO_NOPREF|PDO_NOPSHUPD, &listData, NULL, 0 },
#endif
#define I_STATUS (1)
- { PD_MESSAGE, NULL, NULL, 0, (void*)120 },
+ { PD_MESSAGE, NULL, NULL, 0, (void*)120 },
#define I_POS (2)
- { PD_MESSAGE, NULL, NULL, 0, (void*)120 },
+ { PD_MESSAGE, NULL, NULL, 0, (void*)120 },
#define I_SLIDER (3)
- { PD_DRAW, NULL, "speed", PDO_NOPSHUPD|PDO_DLGSETY, &speedParamData },
+ { PD_DRAW, NULL, "speed", PDO_NOPSHUPD|PDO_DLGSETY, &speedParamData },
#define I_DIST (4)
- { PD_STRING, NULL, "distance", PDO_DLGNEWCOLUMN, (void*)(100-SLIDER_WIDTH), NULL, BO_READONLY },
+ { PD_STRING, NULL, "distance", PDO_DLGNEWCOLUMN, (void*)(100-SLIDER_WIDTH), NULL, BO_READONLY },
#define I_ZERO (5)
- { PD_BUTTON, NULL, "zeroDistance", PDO_NOPSHUPD|PDO_NOPREF|PDO_DLGHORZ, NULL, NULL, BO_ICON },
+ { PD_BUTTON, NULL, "zeroDistance", PDO_NOPSHUPD|PDO_NOPREF|PDO_DLGHORZ, NULL, NULL, BO_ICON },
#define I_GOTO (6)
- { PD_BUTTON, NULL, "goto", PDO_NOPSHUPD|PDO_NOPREF|PDO_DLGWIDE, NULL, N_("Find") },
+ { PD_BUTTON, NULL, "goto", PDO_NOPSHUPD|PDO_NOPREF|PDO_DLGWIDE, NULL, N_("Find") },
#define I_FOLLOW (7)
- { PD_TOGGLE, NULL, "follow", PDO_NOPREF|PDO_DLGWIDE, trainFollowMeLabels, NULL, BC_HORZ|BC_NOBORDER },
+ { PD_TOGGLE, NULL, "follow", PDO_NOPREF|PDO_DLGWIDE, trainFollowMeLabels, NULL, BC_HORZ|BC_NOBORDER },
#define I_AUTORVRS (8)
- { PD_TOGGLE, NULL, "autoreverse", PDO_NOPREF, trainAutoReverseLabels, NULL, BC_HORZ|BC_NOBORDER },
+ { PD_TOGGLE, NULL, "autoreverse", PDO_NOPREF, trainAutoReverseLabels, NULL, BC_HORZ|BC_NOBORDER },
#define I_DIR (9)
- { PD_BUTTON, NULL, "direction", PDO_NOPREF|PDO_DLGWIDE, NULL, N_("Forward"), 0 },
+ { PD_BUTTON, NULL, "direction", PDO_NOPREF|PDO_DLGWIDE, NULL, N_("Forward"), 0 },
#define I_STOP (10)
- { PD_BUTTON, NULL, "stop", PDO_DLGWIDE, NULL, N_("Stop") },
+ { PD_BUTTON, NULL, "stop", PDO_DLGWIDE, NULL, N_("Stop") },
#define I_SPEED (11)
- { PD_MESSAGE, NULL, NULL, PDO_DLGIGNOREX, (void *)120 } };
+ { PD_MESSAGE, NULL, NULL, PDO_DLGIGNOREX, (void *)120 }
+};
static paramGroup_t trainPG = { "train", 0, trainPLs, sizeof trainPLs/sizeof trainPLs[0] };
typedef struct {
- track_p loco;
- BOOL_T running;
- } locoList_t;
+ track_p loco;
+ BOOL_T running;
+} locoList_t;
dynArr_t locoList_da;
#define locoList(N) DYNARR_N( locoList_t, locoList_da, N )
static wIndex_t FindLoco(
- track_p loco )
+ track_p loco)
{
- wIndex_t inx;
- for ( inx = 0; inx<locoList_da.cnt; inx++ ) {
- if ( locoList(inx).loco == loco )
- return inx;
- }
- return -1;
+ wIndex_t inx;
+
+ for (inx = 0; inx<locoList_da.cnt; inx++) {
+ if (locoList(inx).loco == loco) {
+ return inx;
+ }
+ }
+
+ return -1;
}
/**
@@ -603,488 +657,591 @@ static wIndex_t FindLoco(
*/
static void SpeedRedraw(
- wDraw_p d,
- void * context,
- wPos_t w,
- wPos_t h )
+ wDraw_p d,
+ void * context,
+ wPos_t w,
+ wPos_t h)
{
- wPos_t y, pts[4][2];
- trainControlDlg_p dlg = (trainControlDlg_p)context;
- struct extraData * xx;
- wDrawColor drawColor;
-
- wDrawClear( d );
- if ( dlg == NULL || dlg->train == NULL ) return;
- xx = GetTrkExtraData( dlg->train );
- if ( xx->speed > MAX_SPEED )
- xx->speed = MAX_SPEED;
- if ( xx->speed < 0 )
- xx->speed = 0;
- y = (wPos_t)(xx->speed/MAX_SPEED*((SLIDER_HEIGHT-SLIDER_THICKNESS))+SLIDER_THICKNESS/2);
-
- drawColor = wDrawFindColor( wRGB( 160, 160, 160) );
- pts[0][1] = pts[1][1] = y-SLIDER_THICKNESS/2;
- pts[2][1] = pts[3][1] = y+SLIDER_THICKNESS/2;
- pts[0][0] = pts[3][0] = 0;
- pts[1][0] = pts[2][0] = SLIDER_WIDTH;
- wDrawFilledPolygon( d, pts, 4, drawColor, 0 );
-
- drawColor = wDrawFindColor( wRGB( 220, 220, 220) );
- pts[0][1] = pts[1][1] = y+SLIDER_THICKNESS/2;
- pts[2][1] = pts[3][1] = y;
- pts[0][0] = pts[3][0] = 0;
- pts[1][0] = pts[2][0] = SLIDER_WIDTH;
- wDrawFilledPolygon( d, pts, 4, drawColor, 0 );
-
- wDrawLine( d, 0, y, SLIDER_WIDTH, y, 1, wDrawLineSolid, drawColorRed, 0 );
- wDrawLine( d, 0, y+SLIDER_THICKNESS/2, SLIDER_WIDTH, y+SLIDER_THICKNESS/2, 1, wDrawLineSolid, drawColorBlack, 0 );
- wDrawLine( d, 0, y-SLIDER_THICKNESS/2, SLIDER_WIDTH, y-SLIDER_THICKNESS/2, 1, wDrawLineSolid, drawColorBlack, 0 );
-
- sprintf( dlg->speedS, "%3d %s", (int)(units==UNITS_ENGLISH?xx->speed:xx->speed*1.6), (units==UNITS_ENGLISH?"mph":"km/h") );
- ParamLoadMessage( dlg->trainPGp, I_SPEED, dlg->speedS );
- LOG( log_trainPlayback, 3, ( "Speed = %d\n", (int)xx->speed ) );
+ wPos_t y, pts[4][2];
+ trainControlDlg_p dlg = (trainControlDlg_p)context;
+ struct extraData * xx;
+ wDrawColor drawColor;
+ wDrawClear(d);
+
+ if (dlg == NULL || dlg->train == NULL) {
+ return;
+ }
+
+ xx = GetTrkExtraData(dlg->train);
+
+ if (xx->speed > MAX_SPEED) {
+ xx->speed = MAX_SPEED;
+ }
+
+ if (xx->speed < 0) {
+ xx->speed = 0;
+ }
+
+ y = (wPos_t)(xx->speed/MAX_SPEED*((SLIDER_HEIGHT-SLIDER_THICKNESS))
+ +SLIDER_THICKNESS/2);
+ drawColor = wDrawFindColor(wRGB(160, 160, 160));
+ pts[0][1] = pts[1][1] = y-SLIDER_THICKNESS/2;
+ pts[2][1] = pts[3][1] = y+SLIDER_THICKNESS/2;
+ pts[0][0] = pts[3][0] = 0;
+ pts[1][0] = pts[2][0] = SLIDER_WIDTH;
+ wDrawFilledPolygon(d, pts, 4, drawColor, 0);
+ drawColor = wDrawFindColor(wRGB(220, 220, 220));
+ pts[0][1] = pts[1][1] = y+SLIDER_THICKNESS/2;
+ pts[2][1] = pts[3][1] = y;
+ pts[0][0] = pts[3][0] = 0;
+ pts[1][0] = pts[2][0] = SLIDER_WIDTH;
+ wDrawFilledPolygon(d, pts, 4, drawColor, 0);
+ wDrawLine(d, 0, y, SLIDER_WIDTH, y, 1, wDrawLineSolid, drawColorRed, 0);
+ wDrawLine(d, 0, y+SLIDER_THICKNESS/2, SLIDER_WIDTH, y+SLIDER_THICKNESS/2, 1,
+ wDrawLineSolid, drawColorBlack, 0);
+ wDrawLine(d, 0, y-SLIDER_THICKNESS/2, SLIDER_WIDTH, y-SLIDER_THICKNESS/2, 1,
+ wDrawLineSolid, drawColorBlack, 0);
+ sprintf(dlg->speedS, "%3d %s",
+ (int)(units==UNITS_ENGLISH?xx->speed:xx->speed*1.6),
+ (units==UNITS_ENGLISH?"mph":"km/h"));
+ ParamLoadMessage(dlg->trainPGp, I_SPEED, dlg->speedS);
+ LOG(log_trainPlayback, 3, ("Speed = %d\n", (int)xx->speed));
}
static void SpeedAction(
- wAction_t action,
- coOrd pos )
+ wAction_t action,
+ coOrd pos)
{
- /*trainControlDlg_p dlg = (trainControlDlg_p)wDrawGetContext(d);*/
- trainControlDlg_p dlg = curTrainDlg;
- struct extraData * xx;
- FLOAT_T speed;
- BOOL_T startStop;
- if ( dlg == NULL || dlg->train == NULL )
- return;
- xx = GetTrkExtraData( dlg->train );
- switch ( action ) {
- case C_DOWN:
- InfoMessage( "" );
- case C_MOVE:
- case C_UP:
- TrainTimeEndPause();
- if ( IsOnTrack(xx) ) {
- speed = ((FLOAT_T)((pos.y*speedD.dpi)-SLIDER_THICKNESS/2))/(SLIDER_HEIGHT-SLIDER_THICKNESS)*MAX_SPEED;
- } else {
- speed = 0;
- }
- if ( speed > MAX_SPEED )
- speed = MAX_SPEED;
- if ( speed < 0 )
- speed = 0;
- startStop = (xx->speed == 0) != (speed == 0);
- xx->speed = speed;
- SpeedRedraw( (wDraw_p)dlg->trainPGp->paramPtr[I_SLIDER].control, dlg, SLIDER_WIDTH, SLIDER_HEIGHT );
- if ( startStop ) {
- if ( xx->speed == 0 )
- xx->status = ST_StopManual;
- LocoListChangeEntry( dlg->train, dlg->train );
- }
- TrainTimeStartPause();
- if ( trainsState == TRAINS_IDLE )
- RestartTrains();
- break;
- default:
- break;
- }
-}
+ trainControlDlg_p dlg = curTrainDlg;
+ struct extraData * xx;
+ FLOAT_T speed;
+ BOOL_T startStop;
+ if (dlg == NULL || dlg->train == NULL) {
+ return;
+ }
-static void ControllerDialogSync(
- trainControlDlg_p dlg )
-{
- struct extraData * xx=NULL;
- wIndex_t inx;
- BOOL_T dir;
- BOOL_T followMe;
- BOOL_T autoReverse;
- DIST_T speed;
- coOrd pos;
- char * statusMsg;
- long format;
-
- if ( dlg == NULL ) return;
-
- inx = wListGetIndex( (wList_p)dlg->trainPGp->paramPtr[I_LIST].control );
- if ( dlg->train ) {
- if ( inx >= 0 && inx < locoList_da.cnt && dlg->train && dlg->train != locoList(inx).loco ) {
- inx = FindLoco( dlg->train );
- if ( inx >= 0 ) {
- wListSetIndex( (wList_p)dlg->trainPGp->paramPtr[I_LIST].control, inx );
- }
- }
- } else {
- wListSetIndex( (wList_p)dlg->trainPGp->paramPtr[I_LIST].control, -1 );
- }
+ xx = GetTrkExtraData(dlg->train);
- if ( dlg->train ) {
- xx = GetTrkExtraData(dlg->train);
- dir = xx->direction==0?0:1;
- speed = xx->speed;
- pos = xx->trvTrk.pos;
- followMe = followTrain == dlg->train;
- autoReverse = xx->autoReverse;
- if ( xx->trvTrk.trk == NULL ) {
- if ( xx->status == ST_Crashed )
- statusMsg = _("Crashed");
- else
- statusMsg = _("Not on Track");
- } else if ( xx->speed > 0 ) {
- if ( trainsState == TRAINS_STOP )
- statusMsg = _("Trains Paused");
- else
- statusMsg = _("Running");
- } else {
- switch (xx->status ) {
- case ST_EndOfTrack:
- statusMsg = _("End of Track");
- break;
- case ST_OpenTurnout:
- statusMsg = _("Open Turnout");
- break;
- case ST_StopManual:
- statusMsg = _("Manual Stop");
- break;
- case ST_NoRoom:
- statusMsg = _("No Room");
- break;
- case ST_Crashed:
- statusMsg = _("Crashed");
- break;
- default:
- statusMsg = _("Unknown Status");
- break;
- }
- }
- ParamLoadMessage( dlg->trainPGp, I_STATUS, statusMsg );
- } else {
- dir = 0;
- followMe = FALSE;
- autoReverse = FALSE;
- ParamLoadMessage( dlg->trainPGp, I_STATUS, _("No trains") );
- }
- if ( dlg->followMe != followMe ) {
- dlg->followMe = followMe;
- ParamLoadControl( dlg->trainPGp, I_FOLLOW );
- }
- if ( dlg->autoReverse != autoReverse ) {
- dlg->autoReverse = autoReverse;
- ParamLoadControl( dlg->trainPGp, I_AUTORVRS );
- }
- if ( dlg->direction != dir ) {
- dlg->direction = dir;
- wButtonSetLabel( (wButton_p)dlg->trainPGp->paramPtr[I_DIR].control, (dlg->direction?_("Reverse"):_("Forward")) );
- }
- if ( dlg->train ) {
- if ( dlg->posS[0] == '\0' ||
- dlg->pos.x != xx->trvTrk.pos.x ||
- dlg->pos.y != xx->trvTrk.pos.y ) {
- dlg->pos = xx->trvTrk.pos;
- format = GetDistanceFormat();
- format &= ~DISTFMT_DECS;
- sprintf( dlg->posS, "X:%s Y:%s",
- FormatDistanceEx( xx->trvTrk.pos.x, format ),
- FormatDistanceEx( xx->trvTrk.pos.y, format ) );
- ParamLoadMessage( dlg->trainPGp, I_POS, dlg->posS );
- }
- if ( dlg->speed != xx->speed ) {
- dlg->speed = xx->speed;
- sprintf( dlg->speedS, "%3d", (int)(units==UNITS_ENGLISH?xx->speed:xx->speed*1.6) );
- ParamLoadMessage( dlg->trainPGp, I_SPEED, dlg->speedS );
- SpeedRedraw( (wDraw_p)dlg->trainPGp->paramPtr[I_SLIDER].control, dlg, SLIDER_WIDTH, SLIDER_HEIGHT );
- }
- ParamLoadMessage( dlg->trainPGp, I_DIST, FormatDistance(xx->distance) );
- } else {
- if ( dlg->posS[0] != '\0' ) {
- dlg->posS[0] = '\0';
- ParamLoadMessage( dlg->trainPGp, I_POS, dlg->posS );
- }
- if ( dlg->speed >= 0 ) {
- dlg->speed = -1;
- dlg->speedS[0] = '\0';
- ParamLoadMessage( dlg->trainPGp, I_SPEED, dlg->speedS );
- wDrawClear( (wDraw_p)dlg->trainPGp->paramPtr[I_SLIDER].control );
- }
- ParamLoadMessage( dlg->trainPGp, I_DIST, "" );
- }
+ switch (action) {
+ case C_DOWN:
+ InfoMessage("");
+
+ case C_MOVE:
+ case C_UP:
+ TrainTimeEndPause();
+
+ if (IsOnTrack(xx)) {
+ speed = ((FLOAT_T)((pos.y*speedD.dpi)-SLIDER_THICKNESS/2))/
+ (SLIDER_HEIGHT-SLIDER_THICKNESS)*MAX_SPEED;
+ } else {
+ speed = 0;
+ }
+
+ if (speed > MAX_SPEED) {
+ speed = MAX_SPEED;
+ }
+
+ if (speed < 0) {
+ speed = 0;
+ }
+
+ startStop = (xx->speed == 0) != (speed == 0);
+ xx->speed = speed;
+ SpeedRedraw((wDraw_p)dlg->trainPGp->paramPtr[I_SLIDER].control, dlg,
+ SLIDER_WIDTH, SLIDER_HEIGHT);
+
+ if (startStop) {
+ if (xx->speed == 0) {
+ xx->status = ST_StopManual;
+ }
+
+ LocoListChangeEntry(dlg->train, dlg->train);
+ }
+
+ TrainTimeStartPause();
+
+ if (trainsState == TRAINS_IDLE) {
+ RestartTrains();
+ }
+
+ break;
+
+ default:
+ break;
+ }
}
-static void ControllerDialogSyncAll( void )
+static void ControllerDialogSync(
+ trainControlDlg_p dlg)
+{
+ struct extraData * xx=NULL;
+ wIndex_t inx;
+ BOOL_T dir;
+ BOOL_T followMe;
+ BOOL_T autoReverse;
+ coOrd pos;
+
+ if (dlg == NULL) {
+ return;
+ }
+
+ inx = wListGetIndex((wList_p)dlg->trainPGp->paramPtr[I_LIST].control);
+
+ if (dlg->train) {
+ if (inx >= 0 && inx < locoList_da.cnt && dlg->train &&
+ dlg->train != locoList(inx).loco) {
+ inx = FindLoco(dlg->train);
+
+ if (inx >= 0) {
+ wListSetIndex((wList_p)dlg->trainPGp->paramPtr[I_LIST].control, inx);
+ }
+ }
+ } else {
+ wListSetIndex((wList_p)dlg->trainPGp->paramPtr[I_LIST].control, -1);
+ }
+
+ if (dlg->train) {
+ char * statusMsg;
+ DIST_T speed;
+ xx = GetTrkExtraData(dlg->train);
+ dir = xx->direction==0?0:1;
+ speed = xx->speed;
+ pos = xx->trvTrk.pos;
+ followMe = followTrain == dlg->train;
+ autoReverse = xx->autoReverse;
+
+ if (xx->trvTrk.trk == NULL) {
+ if (xx->status == ST_Crashed) {
+ statusMsg = _("Crashed");
+ } else {
+ statusMsg = _("Not on Track");
+ }
+ } else if (xx->speed > 0) {
+ if (trainsState == TRAINS_STOP) {
+ statusMsg = _("Trains Paused");
+ } else {
+ statusMsg = _("Running");
+ }
+ } else {
+ switch (xx->status) {
+ case ST_EndOfTrack:
+ statusMsg = _("End of Track");
+ break;
+
+ case ST_OpenTurnout:
+ statusMsg = _("Open Turnout");
+ break;
+
+ case ST_StopManual:
+ statusMsg = _("Manual Stop");
+ break;
+
+ case ST_NoRoom:
+ statusMsg = _("No Room");
+ break;
+
+ case ST_Crashed:
+ statusMsg = _("Crashed");
+ break;
+
+ default:
+ statusMsg = _("Unknown Status");
+ break;
+ }
+ }
+
+ ParamLoadMessage(dlg->trainPGp, I_STATUS, statusMsg);
+ } else {
+ dir = 0;
+ followMe = FALSE;
+ autoReverse = FALSE;
+ ParamLoadMessage(dlg->trainPGp, I_STATUS, _("No trains"));
+ }
+
+ if (dlg->followMe != followMe) {
+ dlg->followMe = followMe;
+ ParamLoadControl(dlg->trainPGp, I_FOLLOW);
+ }
+
+ if (dlg->autoReverse != autoReverse) {
+ dlg->autoReverse = autoReverse;
+ ParamLoadControl(dlg->trainPGp, I_AUTORVRS);
+ }
+
+ if (dlg->direction != dir) {
+ dlg->direction = dir;
+ wButtonSetLabel((wButton_p)dlg->trainPGp->paramPtr[I_DIR].control,
+ (dlg->direction?_("Reverse"):_("Forward")));
+ }
+
+ if (dlg->train) {
+ if (dlg->posS[0] == '\0' ||
+ dlg->pos.x != xx->trvTrk.pos.x ||
+ dlg->pos.y != xx->trvTrk.pos.y) {
+ long format;
+ dlg->pos = xx->trvTrk.pos;
+ format = GetDistanceFormat();
+ format &= ~DISTFMT_DECS;
+ sprintf(dlg->posS, "X:%s Y:%s",
+ FormatDistanceEx(xx->trvTrk.pos.x, format),
+ FormatDistanceEx(xx->trvTrk.pos.y, format));
+ ParamLoadMessage(dlg->trainPGp, I_POS, dlg->posS);
+ }
+
+ if (dlg->speed != xx->speed) {
+ dlg->speed = xx->speed;
+ sprintf(dlg->speedS, "%3d",
+ (int)(units==UNITS_ENGLISH?xx->speed:xx->speed*1.6));
+ ParamLoadMessage(dlg->trainPGp, I_SPEED, dlg->speedS);
+ SpeedRedraw((wDraw_p)dlg->trainPGp->paramPtr[I_SLIDER].control, dlg,
+ SLIDER_WIDTH, SLIDER_HEIGHT);
+ }
+
+ ParamLoadMessage(dlg->trainPGp, I_DIST, FormatDistance(xx->distance));
+ } else {
+ if (dlg->posS[0] != '\0') {
+ dlg->posS[0] = '\0';
+ ParamLoadMessage(dlg->trainPGp, I_POS, dlg->posS);
+ }
+
+ if (dlg->speed >= 0) {
+ dlg->speed = -1;
+ dlg->speedS[0] = '\0';
+ ParamLoadMessage(dlg->trainPGp, I_SPEED, dlg->speedS);
+ wDrawClear((wDraw_p)dlg->trainPGp->paramPtr[I_SLIDER].control);
+ }
+
+ ParamLoadMessage(dlg->trainPGp, I_DIST, "");
+ }
+}
+
+
+static void ControllerDialogSyncAll(void)
{
- if ( curTrainDlg )
- ControllerDialogSync( curTrainDlg );
+ if (curTrainDlg) {
+ ControllerDialogSync(curTrainDlg);
+ }
}
static void LocoListChangeEntry(
- track_p oldLoco,
- track_p newLoco )
+ track_p oldLoco,
+ track_p newLoco)
{
- wIndex_t inx = -1;
- struct extraData * xx;
-
- if ( curTrainDlg == NULL )
- return;
- if ( oldLoco && (inx=FindLoco(oldLoco))>=0 ) {
- if ( newLoco ) {
- xx = GetTrkExtraData(newLoco);
- locoList(inx).loco = newLoco;
- xx = GetTrkExtraData(newLoco);
- locoList(inx).running = IsOnTrack(xx) && xx->speed > 0;
- wListSetValues( (wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control, inx, CarItemNumber(xx->item), locoList(inx).running?goI:stopI, newLoco );
- } else {
- wListDelete( (wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control, inx );
- for ( ; inx<locoList_da.cnt-1; inx++ )
- locoList(inx) = locoList(inx+1);
- locoList_da.cnt -= 1;
- if ( inx >= locoList_da.cnt )
- inx--;
- }
- } else if ( newLoco ){
- inx = locoList_da.cnt;
- DYNARR_APPEND( locoList_t, locoList_da, 10 );
- locoList(inx).loco = newLoco;
- xx = GetTrkExtraData(newLoco);
- locoList(inx).running = IsOnTrack(xx) && xx->speed > 0;
- wListAddValue( (wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control, CarItemNumber(xx->item), locoList(inx).running?goI:stopI, newLoco );
- }
- if ( curTrainDlg->train == oldLoco ) {
- if ( newLoco || locoList_da.cnt <= 0 ) {
- curTrainDlg->train = newLoco;
- } else {
- curTrainDlg->train = wListGetItemContext( (wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control, inx );
- }
- }
- ControllerDialogSync( curTrainDlg );
-}
+ wIndex_t inx = -1;
+ struct extraData * xx;
+
+ if (curTrainDlg == NULL) {
+ return;
+ }
+
+ if (oldLoco && (inx=FindLoco(oldLoco))>=0) {
+ if (newLoco) {
+ locoList(inx).loco = newLoco;
+ xx = GetTrkExtraData(newLoco);
+ locoList(inx).running = IsOnTrack(xx) && xx->speed > 0;
+ wListSetValues((wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control, inx,
+ CarItemNumber(xx->item), locoList(inx).running?goI:stopI, newLoco);
+ } else {
+ wListDelete((wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control, inx);
+
+ for (; inx<locoList_da.cnt-1; inx++) {
+ locoList(inx) = locoList(inx+1);
+ }
+
+ locoList_da.cnt -= 1;
+
+ if (inx >= locoList_da.cnt) {
+ inx--;
+ }
+ }
+ } else if (newLoco) {
+ inx = locoList_da.cnt;
+ DYNARR_APPEND(locoList_t, locoList_da, 10);
+ locoList(inx).loco = newLoco;
+ xx = GetTrkExtraData(newLoco);
+ locoList(inx).running = IsOnTrack(xx) && xx->speed > 0;
+ wListAddValue((wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control,
+ CarItemNumber(xx->item), locoList(inx).running?goI:stopI, newLoco);
+ }
+
+ if (curTrainDlg->train == oldLoco) {
+ if (newLoco || locoList_da.cnt <= 0) {
+ curTrainDlg->train = newLoco;
+ } else {
+ curTrainDlg->train = wListGetItemContext((wList_p)
+ curTrainDlg->trainPGp->paramPtr[I_LIST].control, inx);
+ }
+ }
+
+ ControllerDialogSync(curTrainDlg);
+}
+
+
+static void LocoListInit(void)
+{
+ track_p train;
+ struct extraData * xx;
+ locoList_da.cnt = 0;
+ for (train=NULL; TrackIterate(&train);) {
+ if (GetTrkType(train) != T_CAR) {
+ continue;
+ }
-static void LocoListInit( void )
-{
- track_p train;
- struct extraData * xx;
-
- locoList_da.cnt = 0;
- for ( train=NULL; TrackIterate( &train ); ) {
- if ( GetTrkType(train) != T_CAR ) continue;
- xx = GetTrkExtraData(train);
- if ( !CarItemIsLoco(xx->item) ) continue;
- if ( !IsLocoMaster(xx) ) continue;
- LocoListChangeEntry( NULL, train );
- }
-}
+ xx = GetTrkExtraData(train);
+ if (!CarItemIsLoco(xx->item)) {
+ continue;
+ }
-#ifdef LATER
-static void LoadTrainDlgIndex(
- trainControlDlg_p dlg )
-{
- track_p car;
- struct extraData * xx;
-
- wListClear( (wList_p)dlg->trainPGp->paramPtr[I_LIST].control );
- for ( car=NULL; TrackIterate( &car ); ) {
- if ( GetTrkType(car) != T_CAR ) continue;
- xx = GetTrkExtraData(car);
- if ( !CarItemIsLoco(xx->item) ) continue;
- if ( !IsLocoMaster(xx) ) continue;
- wListAddValue( (wList_p)dlg->trainPGp->paramPtr[I_LIST].control, CarItemNumber(xx->item), xx->speed>0?goI:stopI, car );
- }
- TrainDialogSetIndex( dlg );
- ControllerDialogSync( curTrainDlg );
+ if (!IsLocoMaster(xx)) {
+ continue;
+ }
+
+ LocoListChangeEntry(NULL, train);
+ }
}
-#endif
static void SetCurTrain(
- track_p train )
+ track_p train)
{
- curTrainDlg->train = train;
- ControllerDialogSync( curTrainDlg );
+ curTrainDlg->train = train;
+ ControllerDialogSync(curTrainDlg);
}
static void StopTrain(
- track_p train,
- trainStatus_e status )
+ track_p train,
+ trainStatus_e status)
{
- struct extraData * xx;
-
- if ( train == NULL )
- return;
- xx = GetTrkExtraData(train);
- xx->speed = 0;
- xx->status = status;
- LocoListChangeEntry( train, train );
+ struct extraData * xx;
+
+ if (train == NULL) {
+ return;
+ }
+
+ xx = GetTrkExtraData(train);
+ xx->speed = 0;
+ xx->status = status;
+ LocoListChangeEntry(train, train);
}
static void MoveMainWindow(
- coOrd pos,
- ANGLE_T angle )
+ coOrd pos,
+ ANGLE_T angle)
{
- DIST_T dist;
- static DIST_T factor = 0.5;
- ANGLE_T angle1 = angle, angle2;
- if ( angle1 > 180.0)
- angle1 = 360.0 - angle1;
- if ( angle1 > 90.0)
- angle1 = 180.0 - angle1;
- angle2 = R2D(atan2(mainD.size.x,mainD.size.y));
- if ( angle1 < angle2 )
- dist = mainD.size.y/2.0/cos(D2R(angle1));
- else
- dist = mainD.size.x/2.0/cos(D2R(90.0-angle1));
- dist *= factor;
- Translate( &pos, pos, angle, dist );
- DrawMapBoundingBox( FALSE );
- mainCenter = pos;
- mainD.orig.x = pos.x-mainD.size.x/2;;
- mainD.orig.y = pos.y-mainD.size.y/2;;
- MainRedraw();
- DrawMapBoundingBox( TRUE );
+ DIST_T dist;
+ static DIST_T factor = 0.5;
+ ANGLE_T angle1 = angle, angle2;
+
+ if (angle1 > 180.0) {
+ angle1 = 360.0 - angle1;
+ }
+
+ if (angle1 > 90.0) {
+ angle1 = 180.0 - angle1;
+ }
+
+ angle2 = R2D(atan2(mainD.size.x,mainD.size.y));
+
+ if (angle1 < angle2) {
+ dist = mainD.size.y/2.0/cos(D2R(angle1));
+ } else {
+ dist = mainD.size.x/2.0/cos(D2R(90.0-angle1));
+ }
+
+ dist *= factor;
+ Translate(&pos, pos, angle, dist);
+ //DrawMapBoundingBox(FALSE);
+ mainCenter = pos;
+ mainD.orig.x = pos.x-mainD.size.x/2;;
+ mainD.orig.y = pos.y-mainD.size.y/2;;
+ MainRedraw();
+ MapRedraw();
+ //DrawMapBoundingBox(TRUE);
}
static void SetTrainDirection(
- track_p train )
+ track_p train)
{
- struct extraData *xx, *xx0=GetTrkExtraData(train);
- int dir, dir0;
- track_p car;
-
- car = train;
- for ( dir0 = 0; dir0 < 2; dir0++ ) {
- dir = dir0;
- WALK_CARS_START( car, xx, dir )
- if ( car != train ) {
- if ( CarItemIsLoco(xx->item) ) {
- xx->direction = (dir==dir0?xx0->direction:!xx0->direction);
- }
- }
- WALK_CARS_END( car, xx, dir )
- }
-}
+ struct extraData *xx, *xx0=GetTrkExtraData(train);
+ int dir0;
+ track_p car;
+ car = train;
+ for (dir0 = 0; dir0 < 2; dir0++) {
+ int dir;
+ dir = dir0;
+ WALK_CARS_START(car, xx, dir)
-static void ControllerDialogUpdate(
- paramGroup_p pg,
- int inx,
- void * valueP )
-{
- trainControlDlg_p dlg = curTrainDlg;
- track_p train;
- struct extraData * xx;
-
- if ( dlg == NULL )
- return;
-
- TrainTimeEndPause();
- switch (inx) {
- case I_LIST:
- train = (track_p)wListGetItemContext( (wList_p)pg->paramPtr[inx].control, (wIndex_t)*(long*)valueP );
- if ( train == NULL ) return;
- dlg->train = train;
- ControllerDialogSync( dlg );
- break;
- case I_ZERO:
- if ( dlg->train == NULL ) return;
- TrainTimeEndPause();
- xx = GetTrkExtraData( dlg->train );
- xx->distance = 0.0;
- ParamLoadMessage( dlg->trainPGp, I_DIST, FormatDistance(xx->distance) );
- ParamLoadControl( curTrainDlg->trainPGp, I_DIST );
- TrainTimeStartPause();
- break;
- case I_GOTO:
- if ( dlg->train == NULL ) return;
- TrainTimeEndPause();
- xx = GetTrkExtraData( dlg->train );
- followTrain = NULL;
- dlg->followMe = FALSE;
- ParamLoadControl( curTrainDlg->trainPGp, I_FOLLOW );
- CarSetVisible( dlg->train );
- MoveMainWindow( xx->trvTrk.pos, xx->trvTrk.angle );
- TrainTimeStartPause();
- break;
- case I_FOLLOW:
- if ( dlg->train == NULL ) return;
- if ( *(long*)valueP ) {
- followTrain = dlg->train;
- xx = GetTrkExtraData(dlg->train);
- if ( OFF_MAIND( xx->trvTrk.pos, xx->trvTrk.pos ) ) {
- MoveMainWindow( xx->trvTrk.pos, xx->trvTrk.angle );
- }
- followCenter = mainCenter;
- } else {
- followTrain = NULL;
- }
- break;
- case I_AUTORVRS:
- if ( dlg->train == NULL ) return;
- xx = GetTrkExtraData(dlg->train);
- xx->autoReverse = *(long*)valueP!=0;
- break;
- case I_DIR:
- if ( dlg->train == NULL ) return;
- xx = GetTrkExtraData(dlg->train);
- dlg->direction = xx->direction = !xx->direction;
- wButtonSetLabel( (wButton_p)pg->paramPtr[I_DIR].control, (dlg->direction?_("Reverse"):_("Forward")) );
- SetTrainDirection( dlg->train );
- DrawAllCars();
- break;
- case I_STOP:
- if ( dlg->train == NULL ) return;
- TrainTimeEndPause();
- StopTrain( dlg->train, ST_StopManual );
- TrainTimeStartPause();
- break;
- case -1:
- /* Close window */
- CmdTrainExit( NULL );
- break;
- }
- /*ControllerDialogSync( dlg );*/
- TrainTimeStartPause();
+ if (car != train) {
+ if (CarItemIsLoco(xx->item)) {
+ xx->direction = (dir==dir0?xx0->direction:!xx0->direction);
+ }
+ }
+
+ WALK_CARS_END(car, xx, dir)
+ }
}
-static trainControlDlg_p CreateTrainControlDlg( void )
+static void ControllerDialogUpdate(
+ paramGroup_p pg,
+ int inx,
+ void * valueP)
{
- trainControlDlg_p dlg;
- char * title;
- paramData_p PLp;
- dlg = (trainControlDlg_p)MyMalloc( sizeof *dlg );
-#ifdef LATER
- PLp = (paramData_p)MyMalloc( sizeof trainPLs );
- memcpy( PLp, trainPLs, sizeof trainPLs );
-#endif
- PLp = trainPLs;
- dlg->posS[0] = '\0';
- dlg->speedS[0] = '\0';
- PLp[I_LIST].valueP = &dlg->inx;
- PLp[I_LIST].context = dlg;
- PLp[I_POS].valueP = &dlg->posS;
- PLp[I_POS].context = dlg;
- /*PLp[I_GOTO].valueP = NULL;*/
- PLp[I_GOTO].context = dlg;
- PLp[I_SLIDER].context = dlg;
- PLp[I_SPEED].valueP = &dlg->speedS;
- PLp[I_SPEED].context = dlg;
- PLp[I_DIR].context = dlg;
- /*PLp[I_STOP].valueP = NULL;*/
- PLp[I_STOP].context = dlg;
- PLp[I_FOLLOW].valueP = &dlg->followMe;
- PLp[I_FOLLOW].context = dlg;
- PLp[I_AUTORVRS].valueP = &dlg->autoReverse;
- PLp[I_AUTORVRS].context = dlg;
- title = MyStrdup( _("Train Control XXX") );
- sprintf( title, _("Train Control %d"), ++numTrainDlg );
- dlg->trainPGp = &trainPG;
- dlg->win = ParamCreateDialog( dlg->trainPGp, _("Train Control"), NULL, NULL, NULL, FALSE, NULL, 0, ControllerDialogUpdate );
- return dlg;
+ trainControlDlg_p dlg = curTrainDlg;
+ track_p train;
+ struct extraData * xx;
+
+ if (dlg == NULL) {
+ return;
+ }
+
+ TrainTimeEndPause();
+
+ switch (inx) {
+ case I_LIST:
+ train = (track_p)wListGetItemContext((wList_p)pg->paramPtr[inx].control,
+ (wIndex_t)*(long*)valueP);
+
+ if (train == NULL) {
+ return;
+ }
+
+ dlg->train = train;
+ ControllerDialogSync(dlg);
+ break;
+
+ case I_ZERO:
+ if (dlg->train == NULL) {
+ return;
+ }
+
+ TrainTimeEndPause();
+ xx = GetTrkExtraData(dlg->train);
+ xx->distance = 0.0;
+ ParamLoadMessage(dlg->trainPGp, I_DIST, FormatDistance(xx->distance));
+ ParamLoadControl(curTrainDlg->trainPGp, I_DIST);
+ TrainTimeStartPause();
+ break;
+
+ case I_GOTO:
+ if (dlg->train == NULL) {
+ return;
+ }
+
+ TrainTimeEndPause();
+ xx = GetTrkExtraData(dlg->train);
+ followTrain = NULL;
+ dlg->followMe = FALSE;
+ ParamLoadControl(curTrainDlg->trainPGp, I_FOLLOW);
+ CarSetVisible(dlg->train);
+ MoveMainWindow(xx->trvTrk.pos, xx->trvTrk.angle);
+ TrainTimeStartPause();
+ break;
+
+ case I_FOLLOW:
+ if (dlg->train == NULL) {
+ return;
+ }
+
+ if (*(long*)valueP) {
+ followTrain = dlg->train;
+ xx = GetTrkExtraData(dlg->train);
+
+ if (OFF_MAIND(xx->trvTrk.pos, xx->trvTrk.pos)) {
+ MoveMainWindow(xx->trvTrk.pos, xx->trvTrk.angle);
+ }
+
+ followCenter = mainCenter;
+ } else {
+ followTrain = NULL;
+ }
+
+ break;
+
+ case I_AUTORVRS:
+ if (dlg->train == NULL) {
+ return;
+ }
+
+ xx = GetTrkExtraData(dlg->train);
+ xx->autoReverse = *(long*)valueP!=0;
+ break;
+
+ case I_DIR:
+ if (dlg->train == NULL) {
+ return;
+ }
+
+ xx = GetTrkExtraData(dlg->train);
+ dlg->direction = xx->direction = !xx->direction;
+ wButtonSetLabel((wButton_p)pg->paramPtr[I_DIR].control,
+ (dlg->direction?_("Reverse"):_("Forward")));
+ SetTrainDirection(dlg->train);
+ DrawAllCars();
+ break;
+
+ case I_STOP:
+ if (dlg->train == NULL) {
+ return;
+ }
+
+ TrainTimeEndPause();
+ StopTrain(dlg->train, ST_StopManual);
+ TrainTimeStartPause();
+ break;
+
+ case -1:
+ /* Close window */
+ CmdTrainExit(NULL);
+ break;
+ }
+
+ /*ControllerDialogSync( dlg );*/
+ TrainTimeStartPause();
+}
+
+
+static trainControlDlg_p CreateTrainControlDlg(void)
+{
+ trainControlDlg_p dlg;
+ char * title;
+ paramData_p PLp;
+ dlg = (trainControlDlg_p)MyMalloc(sizeof *dlg);
+ PLp = trainPLs;
+ dlg->posS[0] = '\0';
+ dlg->speedS[0] = '\0';
+ PLp[I_LIST].valueP = &dlg->inx;
+ PLp[I_LIST].context = dlg;
+ PLp[I_POS].valueP = &dlg->posS;
+ PLp[I_POS].context = dlg;
+ /*PLp[I_GOTO].valueP = NULL;*/
+ PLp[I_GOTO].context = dlg;
+ PLp[I_SLIDER].context = dlg;
+ PLp[I_SPEED].valueP = &dlg->speedS;
+ PLp[I_SPEED].context = dlg;
+ PLp[I_DIR].context = dlg;
+ /*PLp[I_STOP].valueP = NULL;*/
+ PLp[I_STOP].context = dlg;
+ PLp[I_FOLLOW].valueP = &dlg->followMe;
+ PLp[I_FOLLOW].context = dlg;
+ PLp[I_AUTORVRS].valueP = &dlg->autoReverse;
+ PLp[I_AUTORVRS].context = dlg;
+ title = MyStrdup(_("Train Control XXX"));
+ sprintf(title, _("Train Control %d"), ++numTrainDlg);
+ dlg->trainPGp = &trainPG;
+ dlg->win = ParamCreateDialog(dlg->trainPGp, _("Train Control"), NULL, NULL,
+ NULL, FALSE, NULL, 0, ControllerDialogUpdate);
+ return dlg;
}
@@ -1094,920 +1251,1141 @@ static trainControlDlg_p CreateTrainControlDlg( void )
*/
static struct {
- STATE_T state;
- coOrd pos0;
- } Dtrain;
+ STATE_T state;
+ coOrd pos0;
+} Dtrain;
-EXPORT long trainPause = 200;
+long trainPause = 200;
static track_p followTrain = NULL;
-/*static int suppressTrainRedraw = 0;*/
-static long setTimeD;
-
-
-
-#ifdef MEMCHECK
-static BOOL_T drawAllCarsDisable;
-static void * top1, * top2;
-static long drawCounter;
-#endif
-static void DrawAllCars( void )
+static void DrawAllCars(void)
{
- track_p car;
- struct extraData * xx;
- coOrd size, lo, hi;
- BOOL_T drawCarEnable1 = drawCarEnable;
-#ifdef MEMCHECK
-drawCounter++;
-top1 = Sbrk( 0 );
-if ( top1 != top2 ) {
- fprintf( stderr, "incr by %ld at %ld\n", (char*)top1-(char*)top2, drawCounter );
- top2 = top1;
-}
-#endif
- drawCarEnable = TRUE;
- wDrawDelayUpdate( mainD.d, TRUE );
- wDrawRestoreImage( mainD.d );
- DrawMarkers();
- DrawPositionIndicators();
- for ( car=NULL; TrackIterate(&car); ) {
- if ( GetTrkType(car) == T_CAR ) {
- xx = GetTrkExtraData(car);
- CarItemSize( xx->item, &size ); /* TODO assumes xx->trvTrk.pos is the car center */
- lo.x = xx->trvTrk.pos.x - size.x/2.0;
- lo.y = xx->trvTrk.pos.y - size.x/2.0;
- hi.x = lo.x + size.x;
- hi.y = lo.y + size.x;
- if ( !OFF_MAIND( lo, hi ) )
- DrawCar( car, &mainD, wDrawColorBlack );
- }
- }
- wDrawDelayUpdate( mainD.d, FALSE );
- drawCarEnable = drawCarEnable1;
+ track_p car;
+ struct extraData * xx;
+ coOrd size, lo, hi;
+ BOOL_T drawCarEnable1 = drawCarEnable;
+ drawCarEnable = TRUE;
+ wDrawDelayUpdate(mainD.d, TRUE);
+ wDrawRestoreImage(mainD.d);
+ DrawMarkers();
+ DrawPositionIndicators();
+
+ for (car=NULL; TrackIterate(&car);) {
+ if (GetTrkType(car) == T_CAR) {
+ xx = GetTrkExtraData(car);
+ CarItemSize(xx->item,
+ &size); /* TODO assumes xx->trvTrk.pos is the car center */
+ lo.x = xx->trvTrk.pos.x - size.x/2.0;
+ lo.y = xx->trvTrk.pos.y - size.x/2.0;
+ hi.x = lo.x + size.x;
+ hi.y = lo.y + size.x;
+
+ if (!OFF_MAIND(lo, hi)) {
+ DrawCar(car, &mainD, wDrawColorBlack);
+ }
+ }
+ }
+
+ wDrawDelayUpdate(mainD.d, FALSE);
+ drawCarEnable = drawCarEnable1;
}
static DIST_T GetTrainLength2(
- track_p * car0,
- BOOL_T * dir )
+ track_p * car0,
+ BOOL_T * dir)
{
- DIST_T length = 0, carLength;
- struct extraData * xx;
-
- WALK_CARS_START ( *car0, xx, *dir )
- carLength = CarItemCoupledLength( xx->item );
- if ( length == 0 )
- length = carLength/2.0; /* TODO assumes xx->trvTrk.pos is the car center */
- else
- length += carLength;
- WALK_CARS_END ( *car0, xx, *dir )
- return length;
+ DIST_T length = 0, carLength;
+ struct extraData * xx;
+ WALK_CARS_START(*car0, xx, *dir)
+ carLength = CarItemCoupledLength(xx->item);
+
+ if (length == 0) {
+ length = carLength/2.0; /* TODO assumes xx->trvTrk.pos is the car center */
+ } else {
+ length += carLength;
+ }
+
+ WALK_CARS_END(*car0, xx, *dir)
+ return length;
}
static DIST_T GetTrainLength(
- track_p car0,
- BOOL_T dir )
+ track_p car0,
+ BOOL_T dir)
{
- return GetTrainLength2( &car0, &dir );
+ return GetTrainLength2(&car0, &dir);
}
static void PlaceCar(
- track_p car )
+ track_p car)
{
- struct extraData *xx = GetTrkExtraData(car);
- DIST_T dists[2];
- int dir;
-
- CarItemPlace( xx->item, &xx->trvTrk, dists );
-
- for ( dir=0; dir<2; dir++ )
- xx->couplerPos[dir] = CarItemFindCouplerMountPoint( xx->item, xx->trvTrk, dir );
-
- car->endPt[0].angle = xx->trvTrk.angle;
- Translate( &car->endPt[0].pos, xx->trvTrk.pos, car->endPt[0].angle, dists[0] );
- car->endPt[1].angle = NormalizeAngle( xx->trvTrk.angle + 180.0 );
- Translate( &car->endPt[1].pos, xx->trvTrk.pos, car->endPt[1].angle, dists[1] );
-LOG( log_trainMove, 4, ( "%s @ [%0.3f,%0.3f] A%0.3f\n", CarItemNumber(xx->item), xx->trvTrk.pos.x, xx->trvTrk.pos.y, xx->trvTrk.angle ) )
- SetCarBoundingBox( car );
- xx->state &= ~(CAR_STATE_ONHIDENTRACK);
- xx->trkLayer = NOTALAYER;
- if ( xx->trvTrk.trk ) {
- if ( !GetTrkVisible(xx->trvTrk.trk) )
- xx->state |= CAR_STATE_ONHIDENTRACK;
- xx->trkLayer = GetTrkLayer(xx->trvTrk.trk);
- }
+ struct extraData *xx = GetTrkExtraData(car);
+ DIST_T dists[2];
+ int dir;
+ CarItemPlace(xx->item, &xx->trvTrk, dists);
+
+ for (dir=0; dir<2; dir++) {
+ xx->couplerPos[dir] = CarItemFindCouplerMountPoint(xx->item, xx->trvTrk, dir);
+ }
+
+ car->endPt[0].angle = xx->trvTrk.angle;
+ Translate(&car->endPt[0].pos, xx->trvTrk.pos, car->endPt[0].angle, dists[0]);
+ car->endPt[1].angle = NormalizeAngle(xx->trvTrk.angle + 180.0);
+ Translate(&car->endPt[1].pos, xx->trvTrk.pos, car->endPt[1].angle, dists[1]);
+ LOG(log_trainMove, 4, ("%s @ [%0.3f,%0.3f] A%0.3f\n", CarItemNumber(xx->item),
+ xx->trvTrk.pos.x, xx->trvTrk.pos.y, xx->trvTrk.angle))
+ SetCarBoundingBox(car);
+ xx->state &= ~(CAR_STATE_ONHIDENTRACK);
+ xx->trkLayer = NOTALAYER;
+
+ if (xx->trvTrk.trk) {
+ if (!GetTrkVisible(xx->trvTrk.trk)) {
+ xx->state |= CAR_STATE_ONHIDENTRACK;
+ }
+
+ xx->trkLayer = GetTrkLayer(xx->trvTrk.trk);
+ }
}
static track_p FindCar(
- coOrd * pos )
+ coOrd * pos)
{
- coOrd pos0, pos1;
- track_p trk, trk1;
- DIST_T dist1 = 100000, dist;
- struct extraData * xx;
-
- trk1 = NULL;
- for ( trk=NULL; TrackIterate(&trk); ) {
- if ( GetTrkType(trk) == T_CAR ) {
- xx = GetTrkExtraData(trk);
- if ( IsIgnored(xx) )
- continue;
- pos0 = *pos;
- dist = DistanceCar( trk, &pos0 );
- if ( dist < dist1 ) {
- dist1 = dist;
- trk1 = trk;
- pos1 = pos0;
- }
- }
- }
- if ( dist1 < 10 ) {
- *pos = pos1;
- return trk1;
- } else {
- return NULL;
- }
+ coOrd pos0, pos1;
+ track_p trk, trk1;
+ DIST_T dist1 = 100000, dist;
+ struct extraData * xx;
+ trk1 = NULL;
+
+ for (trk=NULL; TrackIterate(&trk);) {
+ if (GetTrkType(trk) == T_CAR) {
+ xx = GetTrkExtraData(trk);
+
+ if (IsIgnored(xx)) {
+ continue;
+ }
+
+ pos0 = *pos;
+ dist = DistanceCar(trk, &pos0);
+
+ if (dist < dist1) {
+ dist1 = dist;
+ trk1 = trk;
+ pos1 = pos0;
+ }
+ }
+ }
+
+ if (dist1 < 10) {
+ *pos = pos1;
+ return trk1;
+ } else {
+ return NULL;
+ }
}
static track_p FindMasterLoco(
- track_p train,
- int * dirR )
+ track_p train,
+ int * dirR)
{
- track_p car0;
- struct extraData *xx0;
- int dir, dir0;
-
- for ( dir = 0; dir<2; dir++ ) {
- car0 = train;
- dir0 = dir;
- WALK_CARS_START( car0, xx0, dir0 )
- if ( CarItemIsLoco(xx0->item) && IsLocoMaster(xx0) ) {
- if ( dirR ) *dirR = 1-dir0;
- return car0;
- }
- WALK_CARS_END( car0, xx0, dir0 )
- }
- return NULL;
+ struct extraData *xx0;
+ int dir;
+
+ for (dir = 0; dir<2; dir++) {
+ track_p car0;
+ int dir0;
+ car0 = train;
+ dir0 = dir;
+ WALK_CARS_START(car0, xx0, dir0)
+
+ if (CarItemIsLoco(xx0->item) && IsLocoMaster(xx0)) {
+ if (dirR) {
+ *dirR = 1-dir0;
+ }
+
+ return car0;
+ }
+
+ WALK_CARS_END(car0, xx0, dir0)
+ }
+
+ return NULL;
}
static track_p PickMasterLoco(
- track_p car,
- int dir )
+ track_p car,
+ int dir)
{
- track_p loco=NULL;
- struct extraData *xx;
-
- WALK_CARS_START( car, xx, dir )
- if ( CarItemIsLoco(xx->item) ) {
- if ( IsLocoMaster(xx) )
- return car;
- if ( loco == NULL ) loco = car;
- }
- WALK_CARS_END( car, xx, dir )
- if ( loco == NULL )
- return NULL;
- xx = GetTrkExtraData(loco);
- SetLocoMaster(xx);
- xx->speed = 0;
- LOG( log_trainMove, 1, ( "%s becomes master\n", CarItemNumber(xx->item) ) )
- return loco;
+ track_p loco=NULL;
+ struct extraData *xx;
+ WALK_CARS_START(car, xx, dir)
+
+ if (CarItemIsLoco(xx->item)) {
+ if (IsLocoMaster(xx)) {
+ return car;
+ }
+
+ if (loco == NULL) {
+ loco = car;
+ }
+ }
+
+ WALK_CARS_END(car, xx, dir)
+
+ if (loco == NULL) {
+ return NULL;
+ }
+
+ xx = GetTrkExtraData(loco);
+ SetLocoMaster(xx);
+ xx->speed = 0;
+ LOG(log_trainMove, 1, ("%s becomes master\n", CarItemNumber(xx->item)))
+ return loco;
}
static void UncoupleCars(
- track_p car1,
- track_p car2 )
+ track_p car1,
+ track_p car2)
{
- struct extraData * xx1, * xx2;
- track_p loco, loco1, loco2;
- int dir1, dir2;
-
- xx1 = GetTrkExtraData(car1);
- xx2 = GetTrkExtraData(car2);
- if ( GetTrkEndTrk(car1,0) == car2 ) {
- dir1 = 0;
- } else if ( GetTrkEndTrk(car1,1) == car2 ) {
- dir1 = 1;
- } else {
- ErrorMessage( "uncoupleCars - not coupled" );
- return;
- }
- if ( GetTrkEndTrk(car2,0) == car1 ) {
- dir2 = 0;
- } else if ( GetTrkEndTrk(car2,1) == car1 ) {
- dir2 = 1;
- } else {
- ErrorMessage( "uncoupleCars - not coupled" );
- return;
- }
- loco = FindMasterLoco( car1, NULL );
- car1->endPt[dir1].track = NULL;
- car2->endPt[dir2].track = NULL;
- /*DisconnectTracks( car1, dir1, car2, dir2 );*/
- if ( loco ) {
- loco1 = PickMasterLoco( car1, 1-dir1 );
- if ( loco1 != loco )
- LocoListChangeEntry( NULL, loco1 );
- loco2 = PickMasterLoco( car2, 1-dir2 );
- if ( loco2 != loco )
- LocoListChangeEntry( NULL, loco2 );
- }
+ track_p loco;
+ int dir1, dir2;
+
+ if (GetTrkEndTrk(car1,0) == car2) {
+ dir1 = 0;
+ } else if (GetTrkEndTrk(car1,1) == car2) {
+ dir1 = 1;
+ } else {
+ ErrorMessage("uncoupleCars - not coupled");
+ return;
+ }
+
+ if (GetTrkEndTrk(car2,0) == car1) {
+ dir2 = 0;
+ } else if (GetTrkEndTrk(car2,1) == car1) {
+ dir2 = 1;
+ } else {
+ ErrorMessage("uncoupleCars - not coupled");
+ return;
+ }
+
+ loco = FindMasterLoco(car1, NULL);
+ car1->endPt[dir1].track = NULL;
+ car2->endPt[dir2].track = NULL;
+
+ if (loco) {
+ track_p loco1, loco2;
+ loco1 = PickMasterLoco(car1, 1-dir1);
+
+ if (loco1 != loco) {
+ LocoListChangeEntry(NULL, loco1);
+ }
+
+ loco2 = PickMasterLoco(car2, 1-dir2);
+
+ if (loco2 != loco) {
+ LocoListChangeEntry(NULL, loco2);
+ }
+ }
}
static void CoupleCars(
- track_p car1,
- int dir1,
- track_p car2,
- int dir2 )
+ track_p car1,
+ int dir1,
+ track_p car2,
+ int dir2)
{
- struct extraData * xx1, * xx2;
- track_p loco1, loco2;
- track_p car;
- int dir;
-
- xx1 = GetTrkExtraData(car1);
- xx2 = GetTrkExtraData(car2);
- if ( GetTrkEndTrk(car1,dir1) != NULL || GetTrkEndTrk(car2,dir2) != NULL ) {
- LOG( log_trainMove, 1, ( "coupleCars - already coupled\n" ) )
- return;
- }
- car = car1;
- dir = 1-dir1;
- WALK_CARS_START( car, xx1, dir )
- if ( car == car2 ) {
- LOG( log_trainMove, 1, ( "coupleCars - already coupled\n" ) )
- ErrorMessage( "Car coupling loop" );
- return;
- }
- WALK_CARS_END( car, xx1, dir )
- car = car2;
- dir = 1-dir2;
- WALK_CARS_START( car, xx2, dir )
- if ( car == car1 ) {
- LOG( log_trainMove, 1, ( "coupleCars - already coupled\n" ) )
- ErrorMessage( "Car coupling loop" );
- return;
- }
- WALK_CARS_END( car, xx1, dir )
- loco1 = FindMasterLoco( car1, NULL );
- loco2 = FindMasterLoco( car2, NULL );
- car1->endPt[dir1].track = car2;
- car2->endPt[dir2].track = car1;
- /*ConnectTracks( car1, dir1, car2, dir2 );*/
-if ( logTable(log_trainMove).level >= 2 ) {
-LogPrintf( "Coupling %s[%d] ", CarItemNumber(xx1->item), dir1 );
-LogPrintf( " and %s[%d]\n", CarItemNumber(xx2->item), dir2 );
-}
- if ( ( loco1 != NULL && loco2 != NULL ) ) {
- xx1 = GetTrkExtraData( loco1 );
- xx2 = GetTrkExtraData( loco2 );
- if ( xx1->speed == 0 ) {
- ClrLocoMaster(xx1);
- LOG( log_trainMove, 2, ( "%s loses master\n", CarItemNumber(xx1->item) ) )
- if ( followTrain == loco1 )
- followTrain = loco2;
- LocoListChangeEntry( loco1, NULL );
- loco1 = loco2;
- } else {
- ClrLocoMaster(xx2);
- xx1->speed = (xx1->speed + xx2->speed)/2.0;
- if ( xx1->speed < 0 )
- xx1->speed = 0;
- if ( xx1->speed > 100 )
- xx1->speed = 100;
- LOG( log_trainMove, 2, ( "%s loses master\n", CarItemNumber(xx2->item) ) )
- if ( followTrain == loco2 )
- followTrain = loco1;
- LocoListChangeEntry( loco2, NULL );
- }
- SetTrainDirection( loco1 );
- }
+ struct extraData * xx1, * xx2;
+ track_p loco1, loco2;
+ track_p car;
+ int dir;
+ xx1 = GetTrkExtraData(car1);
+ xx2 = GetTrkExtraData(car2);
+
+ if (GetTrkEndTrk(car1,dir1) != NULL || GetTrkEndTrk(car2,dir2) != NULL) {
+ LOG(log_trainMove, 1, ("coupleCars - already coupled\n"))
+ return;
+ }
+
+ car = car1;
+ dir = 1-dir1;
+ WALK_CARS_START(car, xx1, dir)
+
+ if (car == car2) {
+ LOG(log_trainMove, 1, ("coupleCars - already coupled\n"))
+ ErrorMessage("Car coupling loop");
+ return;
+ }
+
+ WALK_CARS_END(car, xx1, dir)
+ car = car2;
+ dir = 1-dir2;
+ WALK_CARS_START(car, xx2, dir)
+
+ if (car == car1) {
+ LOG(log_trainMove, 1, ("coupleCars - already coupled\n"))
+ ErrorMessage("Car coupling loop");
+ return;
+ }
+
+ WALK_CARS_END(car, xx1, dir)
+ loco1 = FindMasterLoco(car1, NULL);
+ loco2 = FindMasterLoco(car2, NULL);
+ car1->endPt[dir1].track = car2;
+ car2->endPt[dir2].track = car1;
+
+ /*ConnectTracks( car1, dir1, car2, dir2 );*/
+ if (logTable(log_trainMove).level >= 2) {
+ LogPrintf("Coupling %s[%d] ", CarItemNumber(xx1->item), dir1);
+ LogPrintf(" and %s[%d]\n", CarItemNumber(xx2->item), dir2);
+ }
+
+ if ((loco1 != NULL && loco2 != NULL)) {
+ xx1 = GetTrkExtraData(loco1);
+ xx2 = GetTrkExtraData(loco2);
+
+ if (xx1->speed == 0) {
+ ClrLocoMaster(xx1);
+ LOG(log_trainMove, 2, ("%s loses master\n", CarItemNumber(xx1->item)))
+
+ if (followTrain == loco1) {
+ followTrain = loco2;
+ }
+
+ LocoListChangeEntry(loco1, NULL);
+ loco1 = loco2;
+ } else {
+ ClrLocoMaster(xx2);
+ xx1->speed = (xx1->speed + xx2->speed)/2.0;
+
+ if (xx1->speed < 0) {
+ xx1->speed = 0;
+ }
+
+ if (xx1->speed > 100) {
+ xx1->speed = 100;
+ }
+
+ LOG(log_trainMove, 2, ("%s loses master\n", CarItemNumber(xx2->item)))
+
+ if (followTrain == loco2) {
+ followTrain = loco1;
+ }
+
+ LocoListChangeEntry(loco2, NULL);
+ }
+
+ SetTrainDirection(loco1);
+ }
}
-long crashSpeedDecay=5;
+
long crashDistFactor=60;
static void PlaceCars(
- track_p car0,
- int dir0,
- long crashSpeed,
- BOOL_T crashFlip )
+ track_p car0,
+ int dir0,
+ long crashSpeed,
+ BOOL_T crashFlip)
{
- struct extraData *xx0 = GetTrkExtraData(car0), *xx;
- int dir;
- traverseTrack_t trvTrk;
- DIST_T length, dist, length1;
- track_p car_curr;
- DIST_T flipflop = 1;
-
- if ( crashFlip )
- flipflop = -1;
- dir = dir0;
- trvTrk = xx0->trvTrk;
- if ( dir0 )
- FlipTraverseTrack( &trvTrk );
- length = CarItemCoupledLength(xx0->item)/2.0;
- car_curr = car0;
- ClrIgnored( xx0 );
- WALK_CARS_START ( car_curr, xx, dir )
- if ( car_curr != car0 ) {
- ClrIgnored( xx );
- length1 = CarItemCoupledLength(xx->item)/2.0;
- dist = length + length1;
- crashSpeed = crashSpeed*crashSpeedDecay/10;
- if ( crashSpeed > 0 )
- dist -= dist * crashSpeed/crashDistFactor;
- TraverseTrack2( &trvTrk, dist );
- xx->trvTrk = trvTrk;
- if ( crashSpeed > 0 ) {
- xx->trvTrk.angle = NormalizeAngle( xx->trvTrk.angle + flipflop*crashSpeed );
- xx->trvTrk.trk = NULL;
- }
- flipflop = -flipflop;
- if ( dir != 0 )
- FlipTraverseTrack( &xx->trvTrk );
- PlaceCar( car_curr );
- length = length1;
- }
- WALK_CARS_END ( car_curr, xx, dir )
+ struct extraData *xx0 = GetTrkExtraData(car0), *xx;
+ int dir;
+ traverseTrack_t trvTrk;
+ DIST_T length;
+ track_p car_curr;
+ DIST_T flipflop = 1;
+
+ if (crashFlip) {
+ flipflop = -1;
+ }
+
+ dir = dir0;
+ trvTrk = xx0->trvTrk;
+
+ if (dir0) {
+ FlipTraverseTrack(&trvTrk);
+ }
+
+ length = CarItemCoupledLength(xx0->item)/2.0;
+ car_curr = car0;
+ ClrIgnored(xx0);
+ WALK_CARS_START(car_curr, xx, dir)
+
+ if (car_curr != car0) {
+ DIST_T dist, length1;
+ ClrIgnored(xx);
+ length1 = CarItemCoupledLength(xx->item)/2.0;
+ dist = length + length1;
+ crashSpeed = crashSpeed*CRASHSPEEDDECAY/10;
+
+ if (crashSpeed > 0) {
+ dist -= dist * crashSpeed/crashDistFactor;
+ }
+
+ TraverseTrack2(&trvTrk, dist);
+ xx->trvTrk = trvTrk;
+
+ if (crashSpeed > 0) {
+ xx->trvTrk.angle = NormalizeAngle(xx->trvTrk.angle + flipflop*crashSpeed);
+ xx->trvTrk.trk = NULL;
+ }
+
+ flipflop = -flipflop;
+
+ if (dir != 0) {
+ FlipTraverseTrack(&xx->trvTrk);
+ }
+
+ PlaceCar(car_curr);
+ length = length1;
+ }
+
+ WALK_CARS_END(car_curr, xx, dir)
}
static void CrashTrain(
- track_p car,
- int dir,
- traverseTrack_p trvTrkP,
- long speed,
- BOOL_T flip )
+ track_p car,
+ int dir,
+ traverseTrack_p trvTrkP,
+ long speed,
+ BOOL_T flip)
{
- track_p loco;
- struct extraData *xx;
+ track_p loco;
+ struct extraData *xx;
+ loco = FindMasterLoco(car,NULL);
- loco = FindMasterLoco(car,NULL);
- if ( loco != NULL ) {
- StopTrain( loco, ST_Crashed );
- }
- xx = GetTrkExtraData(car);
- xx->trvTrk = *trvTrkP;
- if ( dir )
- FlipTraverseTrack( &xx->trvTrk );
- PlaceCars( car, 1-dir, speed, flip );
- if ( flip )
- speed = - speed;
- xx->trvTrk.angle = NormalizeAngle( xx->trvTrk.angle - speed );
- xx->trvTrk.trk = NULL;
- PlaceCar( car );
+ if (loco != NULL) {
+ StopTrain(loco, ST_Crashed);
+ }
+
+ xx = GetTrkExtraData(car);
+ xx->trvTrk = *trvTrkP;
+
+ if (dir) {
+ FlipTraverseTrack(&xx->trvTrk);
+ }
+
+ PlaceCars(car, 1-dir, speed, flip);
+
+ if (flip) {
+ speed = - speed;
+ }
+
+ xx->trvTrk.angle = NormalizeAngle(xx->trvTrk.angle - speed);
+ xx->trvTrk.trk = NULL;
+ PlaceCar(car);
}
-static FLOAT_T couplerConnAngle = 45.0;
static BOOL_T CheckCoupling(
- track_p car0,
- int dir00,
- BOOL_T doCheckCrash )
+ track_p car0,
+ int dir00,
+ BOOL_T doCheckCrash)
{
- track_p car1, loco1;
- struct extraData *xx0, *xx1;
- coOrd pos1;
- DIST_T dist0, distc, dist=100000.0;
- int dir0, dir1, dirl;
- ANGLE_T angle;
- traverseTrack_t trvTrk0, trvTrk1;
- long speed, speed0, speed1;
-
- xx0 = xx1 = GetTrkExtraData(car0);
- /* find length of train from loco to start and end */
- dir0 = dir00;
- dist0 = GetTrainLength2( &car0, &dir0 );
-
- trvTrk0 = xx0->trvTrk;
- if ( dir00 )
- FlipTraverseTrack( &trvTrk0 );
- TraverseTrack2( &trvTrk0, dist0 );
- pos1 = trvTrk0.pos;
- car1 = FindCar( &pos1 );
- if ( !car1 )
- return TRUE;
- xx1 = GetTrkExtraData(car1);
- if ( !IsOnTrack(xx1) )
- return TRUE;
- /* determine which EP of the found car to couple to */
- angle = NormalizeAngle( trvTrk0.angle-xx1->trvTrk.angle );
- if ( angle > 90 && angle < 270 ) {
- dir1 = 0;
- angle = NormalizeAngle( angle+180 );
- } else {
- dir1 = 1;
- }
- /* already coupled? */
- if ( GetTrkEndTrk(car1,dir1) != NULL )
- return TRUE;
- /* are we close to aligned? */
- if ( angle > couplerConnAngle && angle < 360.0-couplerConnAngle )
- return TRUE;
- /* find pos of found car's coupler, and dist btw couplers */
- distc = CarItemCoupledLength(xx1->item);
- Translate( &pos1, xx1->trvTrk.pos, xx1->trvTrk.angle+(dir1?180.0:0.0), distc/2.0 );
- dist = FindDistance( trvTrk0.pos, pos1 );
- if ( dist < trackGauge/10 )
- return TRUE;
- /* not real close: are we overlapped? */
- angle = FindAngle( trvTrk0.pos, pos1 );
- angle = NormalizeAngle( angle - trvTrk0.angle );
- if ( angle < 90 || angle > 270 )
- return TRUE;
- /* are we beyond the end of the found car? */
- if ( dist > distc )
- return TRUE;
- /* are we on the same track? */
- trvTrk1 = xx1->trvTrk;
- if ( dir1 )
- FlipTraverseTrack( &trvTrk1 );
- TraverseTrack2( &trvTrk1, distc/2.0-dist );
- if ( trvTrk1.trk != trvTrk0.trk )
- return TRUE;
- if ( doCheckCrash ) {
- speed0 = (long)xx0->speed;
- if ( (xx0->direction==0) != (dir00==0) )
- speed0 = - speed0;
- loco1 = FindMasterLoco( car1, &dirl );
- xx1 = NULL;
- if ( loco1 ) {
- xx1 = GetTrkExtraData(loco1);
- speed1 = (long)xx1->speed;
- if ( car1 == loco1 ) {
- dirl = IsAligned( xx1->trvTrk.angle, FindAngle( trvTrk0.pos, xx1->trvTrk.pos ) )?1:0;
- }
- if ( (xx1->direction==1) != (dirl==1) )
- speed1 = -speed1;
- } else {
- speed1 = 0;
- }
- speed = (long)labs( speed0 + speed1 );
- LOG( log_trainMove, 2, ( "coupling speed=%ld\n", speed ) )
- if ( speed > maxCouplingSpeed ) {
- CrashTrain( car0, dir0, &trvTrk0, speed, FALSE );
- CrashTrain( car1, dir1, &trvTrk1, speed, TRUE );
- return FALSE;
- }
- }
- if ( dir00 )
- dist = -dist;
- TraverseTrack2( &xx0->trvTrk, dist );
- CoupleCars( car0, dir0, car1, dir1 );
-LOG( log_trainMove, 3, ( " -> %0.3f\n", dist ) )
- return TRUE;
-}
+ track_p car1;
+ struct extraData *xx0, *xx1;
+ coOrd pos1;
+ DIST_T dist0, distc, dist=100000.0;
+ int dir0, dir1, dirl;
+ ANGLE_T angle;
+ traverseTrack_t trvTrk0, trvTrk1;
+ xx0 = xx1 = GetTrkExtraData(car0);
+ /* find length of train from loco to start and end */
+ dir0 = dir00;
+ dist0 = GetTrainLength2(&car0, &dir0);
+ trvTrk0 = xx0->trvTrk;
+
+ if (dir00) {
+ FlipTraverseTrack(&trvTrk0);
+ }
+
+ TraverseTrack2(&trvTrk0, dist0);
+ pos1 = trvTrk0.pos;
+ car1 = FindCar(&pos1);
+
+ if (!car1) {
+ return TRUE;
+ }
+
+ xx1 = GetTrkExtraData(car1);
+
+ if (!IsOnTrack(xx1)) {
+ return TRUE;
+ }
+
+ /* determine which EP of the found car to couple to */
+ angle = NormalizeAngle(trvTrk0.angle-xx1->trvTrk.angle);
+
+ if (angle > 90 && angle < 270) {
+ dir1 = 0;
+ angle = NormalizeAngle(angle+180);
+ } else {
+ dir1 = 1;
+ }
+
+ /* already coupled? */
+ if (GetTrkEndTrk(car1,dir1) != NULL) {
+ return TRUE;
+ }
+
+ /* are we close to aligned? */
+ if (angle > COUPLERCONNECTIONANGLE && angle < 360.0-COUPLERCONNECTIONANGLE) {
+ return TRUE;
+ }
+
+ /* find pos of found car's coupler, and dist btw couplers */
+ distc = CarItemCoupledLength(xx1->item);
+ Translate(&pos1, xx1->trvTrk.pos, xx1->trvTrk.angle+(dir1?180.0:0.0),
+ distc/2.0);
+ dist = FindDistance(trvTrk0.pos, pos1);
+
+ if (dist < trackGauge/10) {
+ return TRUE;
+ }
+
+ /* not real close: are we overlapped? */
+ angle = FindAngle(trvTrk0.pos, pos1);
+ angle = NormalizeAngle(angle - trvTrk0.angle);
+
+ if (angle < 90 || angle > 270) {
+ return TRUE;
+ }
+
+ /* are we beyond the end of the found car? */
+ if (dist > distc) {
+ return TRUE;
+ }
+
+ /* are we on the same track? */
+ trvTrk1 = xx1->trvTrk;
+
+ if (dir1) {
+ FlipTraverseTrack(&trvTrk1);
+ }
+
+ TraverseTrack2(&trvTrk1, distc/2.0-dist);
+
+ if (trvTrk1.trk != trvTrk0.trk) {
+ return TRUE;
+ }
+
+ if (doCheckCrash) {
+ track_p loco1;
+ long speed, speed0, speed1;
+ speed0 = (long)xx0->speed;
+
+ if ((xx0->direction==0) != (dir00==0)) {
+ speed0 = - speed0;
+ }
+
+ loco1 = FindMasterLoco(car1, &dirl);
+ xx1 = NULL;
+
+ if (loco1) {
+ xx1 = GetTrkExtraData(loco1);
+ speed1 = (long)xx1->speed;
+
+ if (car1 == loco1) {
+ dirl = IsAligned(xx1->trvTrk.angle, FindAngle(trvTrk0.pos,
+ xx1->trvTrk.pos))?1:0;
+ }
+
+ if ((xx1->direction==1) != (dirl==1)) {
+ speed1 = -speed1;
+ }
+ } else {
+ speed1 = 0;
+ }
+ speed = labs(speed0 + speed1);
+ LOG(log_trainMove, 2, ("coupling speed=%ld\n", speed))
-static void PlaceTrain(
- track_p car0,
- BOOL_T doCheckCrash,
- BOOL_T doCheckCoupling )
-{
- track_p car_curr;
- struct extraData *xx0, *xx;
- int dir0, dir;
-
- xx0 = GetTrkExtraData(car0);
-
- LOG( log_trainMove, 2, ( " placeTrain: %s [%0.3f %0.3f] A%0.3f", CarItemNumber(xx0->item), xx0->trvTrk.pos.x, xx0->trvTrk.pos.y, xx0->trvTrk.angle ) )
-
- car_curr = car0;
- for ( dir0=0; dir0<2; dir0++ ) {
- car_curr = car0;
- dir = dir0;
- xx = xx0;
- WALK_CARS_START( car_curr, xx, dir )
- SetIgnored(xx);
- WALK_CARS_END( car_curr, xx, dir );
- }
+ if (speed > maxCouplingSpeed) {
+ CrashTrain(car0, dir0, &trvTrk0, speed, FALSE);
+ CrashTrain(car1, dir1, &trvTrk1, speed, TRUE);
+ return FALSE;
+ }
+ }
- /* check for coupling to other cars */
- if ( doCheckCoupling ) {
- if ( xx0->trvTrk.trk )
- if ( !CheckCoupling( car0, 0, doCheckCrash ) )
- return;
- if ( xx0->trvTrk.trk )
- if ( !CheckCoupling( car0, 1, doCheckCrash ) )
- return;
- }
+ if (dir00) {
+ dist = -dist;
+ }
+
+ TraverseTrack2(&xx0->trvTrk, dist);
+ CoupleCars(car0, dir0, car1, dir1);
+ LOG(log_trainMove, 3, (" -> %0.3f\n", dist))
+ return TRUE;
+}
- PlaceCar( car0 );
- for ( dir0=0; dir0<2; dir0++ )
- PlaceCars( car0, dir0, 0, FALSE );
+static void PlaceTrain(
+ track_p car0,
+ BOOL_T doCheckCrash,
+ BOOL_T doCheckCoupling)
+{
+ track_p car_curr;
+ struct extraData *xx0;
+ int dir0;
+ xx0 = GetTrkExtraData(car0);
+ LOG(log_trainMove, 2, (" placeTrain: %s [%0.3f %0.3f] A%0.3f",
+ CarItemNumber(xx0->item), xx0->trvTrk.pos.x, xx0->trvTrk.pos.y,
+ xx0->trvTrk.angle))
+ car_curr = car0;
+
+ for (dir0=0; dir0<2; dir0++) {
+ int dir;
+ struct extraData *xx;
+ car_curr = car0;
+ dir = dir0;
+ xx = xx0;
+ WALK_CARS_START(car_curr, xx, dir)
+ SetIgnored(xx);
+ WALK_CARS_END(car_curr, xx, dir);
+ }
+
+ /* check for coupling to other cars */
+ if (doCheckCoupling) {
+ if (xx0->trvTrk.trk)
+ if (!CheckCoupling(car0, 0, doCheckCrash)) {
+ return;
+ }
+
+ if (xx0->trvTrk.trk)
+ if (!CheckCoupling(car0, 1, doCheckCrash)) {
+ return;
+ }
+ }
+
+ PlaceCar(car0);
+
+ for (dir0=0; dir0<2; dir0++) {
+ PlaceCars(car0, dir0, 0, FALSE);
+ }
}
static void PlaceTrainInit(
- track_p car0,
- track_p trk0,
- coOrd pos0,
- ANGLE_T angle0,
- BOOL_T doCheckCoupling )
+ track_p car0,
+ track_p trk0,
+ coOrd pos0,
+ ANGLE_T angle0,
+ BOOL_T doCheckCoupling)
{
- struct extraData * xx = GetTrkExtraData(car0);
- xx->trvTrk.trk = trk0;
- xx->trvTrk.dist = xx->trvTrk.length = -1;
- xx->trvTrk.pos = pos0;
- xx->trvTrk.angle = angle0;
- PlaceTrain( car0, FALSE, doCheckCoupling );
+ struct extraData * xx = GetTrkExtraData(car0);
+ xx->trvTrk.trk = trk0;
+ xx->trvTrk.dist = xx->trvTrk.length = -1;
+ xx->trvTrk.pos = pos0;
+ xx->trvTrk.angle = angle0;
+ PlaceTrain(car0, FALSE, doCheckCoupling);
}
static void FlipTrain(
- track_p train )
+ track_p train)
{
- DIST_T d0, d1;
- struct extraData * xx;
-
- if ( train == NULL )
- return;
- d0 = GetTrainLength( train, 0 );
- d1 = GetTrainLength( train, 1 );
- xx = GetTrkExtraData(train);
- TraverseTrack2( &xx->trvTrk, d0-d1 );
- FlipTraverseTrack( &xx->trvTrk );
- xx->trvTrk.length = -1;
- PlaceTrain( train, FALSE, TRUE );
+ DIST_T d0, d1;
+ struct extraData * xx;
+
+ if (train == NULL) {
+ return;
+ }
+
+ d0 = GetTrainLength(train, 0);
+ d1 = GetTrainLength(train, 1);
+ xx = GetTrkExtraData(train);
+ TraverseTrack2(&xx->trvTrk, d0-d1);
+ FlipTraverseTrack(&xx->trvTrk);
+ xx->trvTrk.length = -1;
+ PlaceTrain(train, FALSE, TRUE);
}
static BOOL_T MoveTrain(
- track_p train,
- long timeD )
+ track_p train,
+ long timeD)
{
- DIST_T ips, dist0, dist1;
- struct extraData *xx, *xx1;
- traverseTrack_t trvTrk;
- DIST_T length;
- track_p car1;
- int dir1;
- int measured; /* make sure the distance is only measured once per train */
-
- if ( train == NULL )
- return FALSE;
- xx = GetTrkExtraData(train);
- if ( xx->speed <= 0 )
- return FALSE;
-
- if ( setTimeD )
- timeD = setTimeD;
- ips = ((xx->speed*5280.0*12.0)/(60.0*60.0*GetScaleRatio(curScaleInx)));
- dist0 = ips * timeD/1000.0;
- length = GetTrainLength( train, xx->direction );
- dist1 = length + dist0;
- trvTrk = xx->trvTrk;
- if ( trvTrk.trk == NULL ) {
- return FALSE;
- }
- LOG( log_trainMove, 1, ( "moveTrain: %s t%ld->%0.3f S%0.3f D%d [%0.3f %0.3f] A%0.3f T%d\n",
- CarItemNumber(xx->item), timeD, dist0, xx->speed, xx->direction, xx->trvTrk.pos.x, xx->trvTrk.pos.y, xx->trvTrk.angle, xx->trvTrk.trk?GetTrkIndex(xx->trvTrk.trk):-1 ) )
- if ( xx->direction )
- FlipTraverseTrack( &trvTrk );
- TraverseTrack( &trvTrk, &dist1 );
- if ( dist1 > 0.0 ) {
- if ( dist1 > dist0 ) {
- /*ErrorMessage( "%s no room: L%0.3f D%0.3f", CarItemNumber(xx->item), length, dist1 );*/
- StopTrain( train, ST_NoRoom );
- return FALSE;
- } else {
- dist0 -= dist1;
- LOG( log_trainMove, 1, ( " %s STOP D%d [%0.3f %0.3f] A%0.3f D%0.3f\n",
- CarItemNumber(xx->item), xx->direction, xx->trvTrk.pos.x, xx->trvTrk.pos.y, xx->trvTrk.angle, dist0 ) )
- }
- /*ErrorMessage( "%s stopped at End Of Track", CarItemNumber(xx->item) );*/
- if ( xx->autoReverse ) {
- xx->direction = !xx->direction;
- SetTrainDirection( train );
- } else {
- if ( xx->speed > maxCouplingSpeed ) {
- car1 = train;
- dir1 = xx->direction;
- GetTrainLength2( &car1, &dir1 );
- CrashTrain( car1, dir1, &trvTrk, (long)xx->speed, FALSE );
- return TRUE;
- } else {
- StopTrain( train, trvTrk.trk?ST_OpenTurnout:ST_EndOfTrack );
- }
- }
- }
- trvTrk = xx->trvTrk;
- TraverseTrack2( &xx->trvTrk, xx->direction==0?dist0:-dist0 );
- car1 = train;
- dir1 = 0;
- GetTrainLength2( &car1, &dir1 );
- dir1 = 1-dir1;
-
- measured = FALSE;
- WALK_CARS_START( car1, xx1, dir1 );
- if ( CarItemIsLoco(xx1->item) && !measured ) {
- xx->distance += dist0;
- measured = TRUE;
- }
- WALK_CARS_END( car1, xx1, dir1 );
-
- if ( train == followTrain ) {
- if ( followCenter.x != mainCenter.x ||
- followCenter.y != mainCenter.y ) {
- if ( curTrainDlg->train == followTrain ) {
- curTrainDlg->followMe = FALSE;
- ParamLoadControl( curTrainDlg->trainPGp, I_FOLLOW );
- }
- followTrain = NULL;
- } else if ( OFF_MAIND( xx->trvTrk.pos, xx->trvTrk.pos ) ) {
- MoveMainWindow( xx->trvTrk.pos, NormalizeAngle(xx->trvTrk.angle+(xx->direction?180.0:0.0)) );
- followCenter = mainCenter;
- }
- }
- PlaceTrain( train, TRUE, TRUE );
- return TRUE;
-}
+ DIST_T ips, dist0, dist1;
+ struct extraData *xx, *xx1;
+ traverseTrack_t trvTrk;
+ DIST_T length;
+ track_p car1;
+ int dir1;
+ int measured; /* make sure the distance is only measured once per train */
+
+ if (train == NULL) {
+ return FALSE;
+ }
+
+ xx = GetTrkExtraData(train);
+
+ if (xx->speed <= 0) {
+ return FALSE;
+ }
+
+ ips = ((xx->speed*5280.0*12.0)/(60.0*60.0*GetScaleRatio(GetLayoutCurScale())));
+ dist0 = ips * timeD/1000.0;
+ length = GetTrainLength(train, xx->direction);
+ dist1 = length + dist0;
+ trvTrk = xx->trvTrk;
+
+ if (trvTrk.trk == NULL) {
+ return FALSE;
+ }
+
+ LOG(log_trainMove, 1,
+ ("moveTrain: %s t%ld->%0.3f S%0.3f D%d [%0.3f %0.3f] A%0.3f T%d\n",
+ CarItemNumber(xx->item), timeD, dist0, xx->speed, xx->direction,
+ xx->trvTrk.pos.x, xx->trvTrk.pos.y, xx->trvTrk.angle,
+ xx->trvTrk.trk?GetTrkIndex(xx->trvTrk.trk):-1))
+
+ if (xx->direction) {
+ FlipTraverseTrack(&trvTrk);
+ }
+
+ TraverseTrack(&trvTrk, &dist1);
+
+ if (dist1 > 0.0) {
+ if (dist1 > dist0) {
+ /*ErrorMessage( "%s no room: L%0.3f D%0.3f", CarItemNumber(xx->item), length, dist1 );*/
+ StopTrain(train, ST_NoRoom);
+ return FALSE;
+ } else {
+ dist0 -= dist1;
+ LOG(log_trainMove, 1, (" %s STOP D%d [%0.3f %0.3f] A%0.3f D%0.3f\n",
+ CarItemNumber(xx->item), xx->direction, xx->trvTrk.pos.x, xx->trvTrk.pos.y,
+ xx->trvTrk.angle, dist0))
+ }
+
+ /*ErrorMessage( "%s stopped at End Of Track", CarItemNumber(xx->item) );*/
+ if (xx->autoReverse) {
+ xx->direction = !xx->direction;
+ SetTrainDirection(train);
+ } else {
+ if (xx->speed > maxCouplingSpeed) {
+ car1 = train;
+ dir1 = xx->direction;
+ GetTrainLength2(&car1, &dir1);
+ CrashTrain(car1, dir1, &trvTrk, (long)xx->speed, FALSE);
+ return TRUE;
+ } else {
+ if (trvTrk.trk && trvTrk.trk->endCnt > 1) //Test for null track after Traverse
+ StopTrain(train, ST_OpenTurnout );
+ else
+ StopTrain(train, ST_EndOfTrack);
+ return (FALSE);
+ }
+ }
+ }
+
+ trvTrk = xx->trvTrk;
+ TraverseTrack2(&xx->trvTrk, xx->direction==0?dist0:-dist0);
+ car1 = train;
+ dir1 = 0;
+ GetTrainLength2(&car1, &dir1);
+ dir1 = 1-dir1;
+ measured = FALSE;
+ WALK_CARS_START(car1, xx1, dir1);
+
+ if (CarItemIsLoco(xx1->item) && !measured) {
+ xx->distance += dist0;
+ measured = TRUE;
+ }
+
+ WALK_CARS_END(car1, xx1, dir1);
+
+ if (train == followTrain) {
+ if (followCenter.x != mainCenter.x ||
+ followCenter.y != mainCenter.y) {
+ if (curTrainDlg->train == followTrain) {
+ curTrainDlg->followMe = FALSE;
+ ParamLoadControl(curTrainDlg->trainPGp, I_FOLLOW);
+ }
+
+ followTrain = NULL;
+ } else if (OFF_MAIND(xx->trvTrk.pos, xx->trvTrk.pos)) {
+ MoveMainWindow(xx->trvTrk.pos,
+ NormalizeAngle(xx->trvTrk.angle+(xx->direction?180.0:0.0)));
+ followCenter = mainCenter;
+ }
+ }
+
+ PlaceTrain(train, TRUE, TRUE);
+ return TRUE;
+}
+
+
+static BOOL_T MoveTrains(long timeD)
+{
+ BOOL_T trains_moved = FALSE;
+ track_p train;
+ struct extraData * xx;
+ for (train=NULL; TrackIterate(&train);) {
+ if (GetTrkType(train) != T_CAR) {
+ continue;
+ }
-static BOOL_T MoveTrains( long timeD )
-{
- BOOL_T trains_moved = FALSE;
- track_p train;
- struct extraData * xx;
-
- for ( train=NULL; TrackIterate( &train ); ) {
- if ( GetTrkType(train) != T_CAR ) continue;
- xx = GetTrkExtraData(train);
- if ( !CarItemIsLoco(xx->item) ) continue;
- if ( !IsLocoMaster(xx) ) continue;
- if ( xx->speed == 0 ) continue;
- trains_moved |= MoveTrain( train, timeD );
- }
+ xx = GetTrkExtraData(train);
+
+ if (!CarItemIsLoco(xx->item)) {
+ continue;
+ }
+
+ if (!IsLocoMaster(xx)) {
+ continue;
+ }
- ControllerDialogSyncAll();
+ if (xx->speed == 0) {
+ continue;
+ }
- DrawAllCars();
+ trains_moved |= MoveTrain(train, timeD);
+ }
- return trains_moved;
+ ControllerDialogSyncAll();
+ DrawAllCars();
+ return trains_moved;
}
-static void MoveTrainsLoop( void )
+static void MoveTrainsLoop(void)
{
- long time1, timeD;
- static long time0 = 0;
+ long time1, timeD;
+ static long time0 = 0;
+ trainsTimeoutPending = FALSE;
- trainsTimeoutPending = FALSE;
- if ( trainsState != TRAINS_RUN ) {
- time0 = 0;
- return;
- }
- if ( time0 == 0 )
- time0 = wGetTimer();
- time1 = wGetTimer();
- timeD = time1-time0;
- time0 = time1;
- if ( timeD > 1000 )
- timeD = 1000;
- if ( MoveTrains( timeD ) ) {
- wAlarm( trainPause, MoveTrainsLoop );
- trainsTimeoutPending = TRUE;
- } else {
- time0 = 0;
- trainsState = TRAINS_IDLE;
- TrainTimeEndPause();
- }
+ if (trainsState != TRAINS_RUN) {
+ time0 = 0;
+ return;
+ }
+
+ if (time0 == 0) {
+ time0 = wGetTimer();
+ }
+
+ time1 = wGetTimer();
+ timeD = time1-time0;
+ time0 = time1;
+
+ if (timeD > 1000) {
+ timeD = 1000;
+ }
+
+ if (MoveTrains(timeD)) {
+ wAlarm(trainPause, MoveTrainsLoop);
+ trainsTimeoutPending = TRUE;
+ } else {
+ time0 = 0;
+ trainsState = TRAINS_IDLE;
+ TrainTimeEndPause();
+ }
}
-static void RestartTrains( void )
+static void RestartTrains(void)
{
- if ( trainsState != TRAINS_RUN )
- TrainTimeStartPause();
- trainsState = TRAINS_RUN;
- if ( !trainsTimeoutPending )
- MoveTrainsLoop();
+ if (trainsState != TRAINS_RUN) {
+ TrainTimeStartPause();
+ }
+
+ trainsState = TRAINS_RUN;
+
+ if (!trainsTimeoutPending) {
+ MoveTrainsLoop();
+ }
}
static long trainTime0 = 0;
static long playbackTrainPause = 0;
static drawCmd_t trainMovieD = {
- NULL,
- &screenDrawFuncs,
- 0,
- 16.0,
- 0,
- {0,0}, {1,1},
- Pix2CoOrd, CoOrd2Pix };
+ NULL,
+ &screenDrawFuncs,
+ 0,
+ 16.0,
+ 0,
+ {0,0}, {1,1},
+ Pix2CoOrd, CoOrd2Pix
+};
static long trainMovieFrameDelay;
static long trainMovieFrameNext;
-static void TrainTimeEndPause( void )
+static void TrainTimeEndPause(void)
{
- if ( recordF ) {
- if (trainTime0 != 0 ) {
- long delay;
- delay = wGetTimer()-trainTime0;
- if ( delay > 0 )
- fprintf( recordF, "TRAINPAUSE %ld\n", delay );
- }
- trainTime0 = 0;
- }
+ if (recordF) {
+ if (trainTime0 != 0) {
+ long delay;
+ delay = wGetTimer()-trainTime0;
+
+ if (delay > 0) {
+ fprintf(recordF, "TRAINPAUSE %ld\n", delay);
+ }
+ }
+
+ trainTime0 = 0;
+ }
}
-static void TrainTimeStartPause( void )
+static void TrainTimeStartPause(void)
{
- if ( trainTime0 == 0 )
- trainTime0 = wGetTimer();
+ if (trainTime0 == 0) {
+ trainTime0 = wGetTimer();
+ }
}
-static BOOL_T TrainTimeDoPause( char * line )
+static BOOL_T TrainTimeDoPause(char * line)
{
- BOOL_T drawCarEnable2;
- playbackTrainPause = atol( line );
-LOG( log_trainPlayback, 1, ( "DoPause %ld\n", playbackTrainPause ) );
- trainsState = TRAINS_RUN;
- if ( trainMovieFrameDelay > 0 ) {
- drawCarEnable2 = drawCarEnable; drawCarEnable = TRUE;
- TakeSnapshot( &trainMovieD );
- drawCarEnable = drawCarEnable2;
-LOG( log_trainPlayback, 1, ( "SNAP 0\n" ) );
- trainMovieFrameNext = trainMovieFrameDelay;
- }
- /*MoveTrains();*/
- while ( playbackTrainPause > 0 ) {
- if ( playbackTrainPause > trainPause ) {
- wPause( trainPause );
- MoveTrains( trainPause );
- playbackTrainPause -= trainPause;
- if ( trainMovieFrameDelay > 0 )
- trainMovieFrameNext -= trainPause;
- } else {
- wPause( playbackTrainPause );
- MoveTrains( playbackTrainPause );
- if ( trainMovieFrameDelay > 0 )
- trainMovieFrameNext -= playbackTrainPause;
- playbackTrainPause = 0;
- }
- if ( trainMovieFrameDelay > 0 &&
- trainMovieFrameNext <= 0 ) {
- drawCarEnable2 = drawCarEnable; drawCarEnable = TRUE;
- TakeSnapshot( &trainMovieD );
- drawCarEnable = drawCarEnable2;
-LOG( log_trainPlayback, 1, ( "SNAP %ld\n", trainMovieFrameNext ) );
- trainMovieFrameNext = trainMovieFrameDelay;
- }
- }
- return TRUE;
-}
+ BOOL_T drawCarEnable2;
+ playbackTrainPause = atol(line);
+ LOG(log_trainPlayback, 1, ("DoPause %ld\n", playbackTrainPause));
+ trainsState = TRAINS_RUN;
+
+ if (trainMovieFrameDelay > 0) {
+ drawCarEnable2 = drawCarEnable;
+ drawCarEnable = TRUE;
+ TakeSnapshot(&trainMovieD);
+ drawCarEnable = drawCarEnable2;
+ LOG(log_trainPlayback, 1, ("SNAP 0\n"));
+ trainMovieFrameNext = trainMovieFrameDelay;
+ }
+
+ /*MoveTrains();*/
+ while (playbackTrainPause > 0) {
+ if (playbackTrainPause > trainPause) {
+ wPause(trainPause);
+ MoveTrains(trainPause);
+ playbackTrainPause -= trainPause;
+
+ if (trainMovieFrameDelay > 0) {
+ trainMovieFrameNext -= trainPause;
+ }
+ } else {
+ wPause(playbackTrainPause);
+ MoveTrains(playbackTrainPause);
+
+ if (trainMovieFrameDelay > 0) {
+ trainMovieFrameNext -= playbackTrainPause;
+ }
+
+ playbackTrainPause = 0;
+ }
+
+ if (trainMovieFrameDelay > 0 &&
+ trainMovieFrameNext <= 0) {
+ drawCarEnable2 = drawCarEnable;
+ drawCarEnable = TRUE;
+ TakeSnapshot(&trainMovieD);
+ drawCarEnable = drawCarEnable2;
+ LOG(log_trainPlayback, 1, ("SNAP %ld\n", trainMovieFrameNext));
+ trainMovieFrameNext = trainMovieFrameDelay;
+ }
+ }
+
+ return TRUE;
+}
+
+
+static BOOL_T TrainDoMovie(char * line)
+{
+ /* on/off, scale, orig, size */
+ long fps;
+ if (trainMovieD.dpi == 0) {
+ trainMovieD.dpi = mainD.dpi;
+ }
-static BOOL_T TrainDoMovie( char * line )
-{
- /* on/off, scale, orig, size */
- long fps;
- if ( trainMovieD.dpi == 0 )
- trainMovieD.dpi = mainD.dpi;
- if ( !GetArgs( line, "lfpp", &fps, &trainMovieD.scale, &trainMovieD.orig, &trainMovieD.size ) )
- return FALSE;
- if ( fps > 0 ) {
- trainMovieFrameDelay = 1000/fps;
- } else {
- trainMovieFrameDelay = 0;
- }
- trainMovieFrameNext = 0;
- return TRUE;
+ if (!GetArgs(line, "lfpp", &fps, &trainMovieD.scale, &trainMovieD.orig,
+ &trainMovieD.size)) {
+ return FALSE;
+ }
+
+ if (fps > 0) {
+ trainMovieFrameDelay = 1000/fps;
+ } else {
+ trainMovieFrameDelay = 0;
+ }
+
+ trainMovieFrameNext = 0;
+ return TRUE;
}
-EXPORT void AttachTrains( void )
+void AttachTrains(void)
{
- track_p car;
- track_p loco;
- struct extraData * xx;
- coOrd pos;
- track_p trk;
- ANGLE_T angle;
- EPINX_T ep0, ep1;
- int dir;
-
- for ( car=NULL; TrackIterate( &car ); ) {
- ClrTrkBits( car, TB_CARATTACHED );
- if ( GetTrkType(car) != T_CAR )
- continue;
- xx = GetTrkExtraData(car);
- ClrProcessed(xx);
- }
- for ( car=NULL; TrackIterate( &car ); ) {
- if ( GetTrkType(car) != T_CAR )
- continue;
- xx = GetTrkExtraData(car);
- if ( IsProcessed(xx) )
- continue;
- loco = FindMasterLoco( car, NULL );
- if ( loco != NULL )
- xx = GetTrkExtraData(loco);
- else
- loco = car;
- pos = xx->trvTrk.pos;
- if ( xx->status == ST_Crashed )
- continue;
- TRK_ITERATE(trk) {
- if ( trk == xx->trvTrk.trk )
- break;
- }
- if ( trk!=NULL && !QueryTrack( trk, Q_ISTRACK ) )
- trk = NULL;
- if ( trk==NULL || GetTrkDistance(trk,pos)>trackGauge*2.0 )
- trk = OnTrack2( &pos, FALSE, TRUE, FALSE );
- if ( trk!=NULL ) {
- /*if ( trk == xx->trvTrk.trk )
- continue;*/
- angle = GetAngleAtPoint( trk, pos, &ep0, &ep1 );
- if ( NormalizeAngle( xx->trvTrk.angle-angle+90 ) > 180 )
- angle = NormalizeAngle(angle+180);
- PlaceTrainInit( loco, trk, pos, angle, TRUE );
- } else {
- PlaceTrainInit( loco, NULL, xx->trvTrk.pos, xx->trvTrk.angle, FALSE );
- }
- dir = 0;
- WALK_CARS_START( loco, xx, dir )
- WALK_CARS_END( loco, xx, dir )
- dir = 1-dir;
- WALK_CARS_START( loco, xx, dir )
- SetProcessed(xx);
- if ( xx->trvTrk.trk ) {
- SetTrkBits( xx->trvTrk.trk, TB_CARATTACHED );
- xx->status = ST_StopManual;
- } else {
- xx->status = ST_NotOnTrack;
- }
- WALK_CARS_END( loco, xx, dir )
- }
- for ( car=NULL; TrackIterate( &car ); ) {
- if ( GetTrkType(car) != T_CAR )
- continue;
- xx = GetTrkExtraData(car);
- ClrProcessed(xx);
- }
-}
+ track_p car;
+ track_p loco;
+ struct extraData * xx;
+ coOrd pos;
+ track_p trk;
+ ANGLE_T angle;
+ EPINX_T ep0, ep1;
+ int dir;
+
+ for (car=NULL; TrackIterate(&car);) {
+ ClrTrkBits(car, TB_CARATTACHED);
+
+ if (GetTrkType(car) != T_CAR) {
+ continue;
+ }
+
+ xx = GetTrkExtraData(car);
+ ClrProcessed(xx);
+ }
+
+ for (car=NULL; TrackIterate(&car);) {
+ if (GetTrkType(car) != T_CAR) {
+ continue;
+ }
+
+ xx = GetTrkExtraData(car);
+
+ if (IsProcessed(xx)) {
+ continue;
+ }
+
+ loco = FindMasterLoco(car, NULL);
+
+ if (loco != NULL) {
+ xx = GetTrkExtraData(loco);
+ } else {
+ loco = car;
+ }
+
+ pos = xx->trvTrk.pos;
+
+ if (xx->status == ST_Crashed) {
+ continue;
+ }
+
+ TRK_ITERATE(trk) {
+ if (trk == xx->trvTrk.trk) {
+ break;
+ }
+ }
+
+ if (trk!=NULL && !QueryTrack(trk, Q_ISTRACK)) {
+ trk = NULL;
+ }
+ if (trk==NULL || GetTrkDistance(trk,&pos)>trackGauge*2.0) {
+ trk = OnTrack2(&pos, FALSE, TRUE, FALSE, NULL);
+ }
+
+ if (trk!=NULL) {
+ /*if ( trk == xx->trvTrk.trk )
+ continue;*/
+ angle = GetAngleAtPoint(trk, pos, &ep0, &ep1);
+
+ if (NormalizeAngle(xx->trvTrk.angle-angle+90) > 180) {
+ angle = NormalizeAngle(angle+180);
+ }
+
+ PlaceTrainInit(loco, trk, pos, angle, TRUE);
+ } else {
+ PlaceTrainInit(loco, NULL, xx->trvTrk.pos, xx->trvTrk.angle, FALSE);
+ }
+
+ dir = 0;
+ WALK_CARS_START(loco, xx, dir)
+ WALK_CARS_END(loco, xx, dir)
+ dir = 1-dir;
+ WALK_CARS_START(loco, xx, dir)
+ SetProcessed(xx);
+
+ if (xx->trvTrk.trk) {
+ SetTrkBits(xx->trvTrk.trk, TB_CARATTACHED);
+ xx->status = ST_StopManual;
+ } else {
+ xx->status = ST_NotOnTrack;
+ }
+
+ WALK_CARS_END(loco, xx, dir)
+ }
+
+ for (car=NULL; TrackIterate(&car);) {
+ if (GetTrkType(car) != T_CAR) {
+ continue;
+ }
+
+ xx = GetTrkExtraData(car);
+ ClrProcessed(xx);
+ }
+}
+
+
+static void UpdateTrainAttachment(void)
+{
+ track_p trk;
+ struct extraData * xx;
+ for (trk=NULL; TrackIterate(&trk);) {
+ ClrTrkBits(trk, TB_CARATTACHED);
+ }
-static void UpdateTrainAttachment( void )
-{
- track_p trk;
- struct extraData * xx;
- for ( trk=NULL; TrackIterate( &trk ); ) {
- ClrTrkBits( trk, TB_CARATTACHED );
- }
- for ( trk=NULL; TrackIterate( &trk ); ) {
- if ( GetTrkType(trk) == T_CAR ) {
- xx = GetTrkExtraData(trk);
- if ( xx->trvTrk.trk != NULL )
- SetTrkBits( xx->trvTrk.trk, TB_CARATTACHED );
- }
- }
+ for (trk=NULL; TrackIterate(&trk);) {
+ if (GetTrkType(trk) == T_CAR) {
+ xx = GetTrkExtraData(trk);
+
+ if (xx->trvTrk.trk != NULL) {
+ SetTrkBits(xx->trvTrk.trk, TB_CARATTACHED);
+ }
+ }
+ }
}
static BOOL_T TrainOnMovableTrack(
- track_p trk,
- track_p *trainR )
+ track_p trk,
+ track_p *trainR)
{
- track_p train;
- struct extraData * xx;
- int dir;
-
- for ( train=NULL; TrackIterate(&train); ) {
- if ( GetTrkType(train) != T_CAR )
- continue;
- xx = GetTrkExtraData(train);
- if ( IsOnTrack(xx) ) {
- if ( xx->trvTrk.trk == trk )
- break;
- }
- }
- *trainR = train;
- if ( train == NULL ) {
- return TRUE;
- }
- dir = 0;
- WALK_CARS_START( train, xx, dir )
- WALK_CARS_END( train, xx, dir )
- dir = 1-dir;
- WALK_CARS_START( train, xx, dir )
- if ( xx->trvTrk.trk != trk ) {
- ErrorMessage( MSG_CANT_MOVE_UNDER_TRAIN );
- return FALSE;
- }
- WALK_CARS_END( train, xx, dir )
- train = FindMasterLoco( train, NULL );
- if ( train != NULL )
- *trainR = train;
- return TRUE;
+ track_p train;
+ struct extraData * xx;
+ int dir;
+
+ for (train=NULL; TrackIterate(&train);) {
+ if (GetTrkType(train) != T_CAR) {
+ continue;
+ }
+
+ xx = GetTrkExtraData(train);
+
+ if (IsOnTrack(xx)) {
+ if (xx->trvTrk.trk == trk) {
+ break;
+ }
+ }
+ }
+
+ *trainR = train;
+
+ if (train == NULL) {
+ return TRUE;
+ }
+
+ dir = 0;
+ WALK_CARS_START(train, xx, dir)
+ WALK_CARS_END(train, xx, dir)
+ dir = 1-dir;
+ WALK_CARS_START(train, xx, dir)
+
+ if (xx->trvTrk.trk != trk) {
+ ErrorMessage(MSG_CANT_MOVE_UNDER_TRAIN);
+ return FALSE;
+ }
+
+ WALK_CARS_END(train, xx, dir)
+ train = FindMasterLoco(train, NULL);
+
+ if (train != NULL) {
+ *trainR = train;
+ }
+
+ return TRUE;
}
/*
@@ -2026,320 +2404,358 @@ static track_p trainFuncCar;
static coOrd trainFuncPos;
static wButton_p trainPauseB;
-#ifdef LATER
-static char * newCarLabels[3] = { N_("Road"), N_("Number"), NULL };
-#endif
-
-static STATUS_T CmdTrain( wAction_t action, coOrd pos )
+static STATUS_T CmdTrain(wAction_t action, coOrd pos)
{
- track_p trk0, trk1;
- static track_p currCar;
- coOrd pos0, pos1;
- static coOrd delta;
- ANGLE_T angle1;
- EPINX_T ep0, ep1;
- int dir;
- struct extraData * xx=NULL;
- DIST_T dist;
- wPos_t w, h;
-
- switch (action) {
-
- case C_START:
- /*UndoStart( "Trains", "Trains" );*/
- UndoSuspend();
- programMode = MODE_TRAIN;
- drawCarEnable = FALSE;
- doDrawTurnoutPosition = 1;
- DoChangeNotification( CHANGE_PARAMS|CHANGE_TOOLBAR );
- if ( CarAvailableCount() <= 0 ) {
- if ( NoticeMessage( MSG_NO_CARS, _("Yes"), _("No") ) > 0 ) {
- DoCarDlg();
- DoChangeNotification( CHANGE_PARAMS );
- }
- }
- EnableCommands();
- if ( curTrainDlg == NULL )
- curTrainDlg = CreateTrainControlDlg();
- curTrainDlg->train = NULL;
-#ifdef LATER
- if ( trainW == NULL )
- trainW = ParamCreateDialog( MakeWindowTitle(_("Train")), NULL, trainPGp );
- ParamLoadControls( trainPGp );
- wListClear( (wList_p)trainPLs[0].control );
-#endif
- wListClear( (wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control );
- Dtrain.state = 0;
- trk0 = NULL;
- tempSegs_da.cnt = 0;
- DYNARR_SET( trkSeg_t, tempSegs_da, 8 );
- /*MainRedraw();*/
- /*wDrawSaveImage( mainD.d );*/
- /*trainEnable = FALSE;*/
- RestartTrains();
- wButtonSetLabel( trainPauseB, (char*)goI );
- trainTime0 = 0;
- AttachTrains();
- DrawAllCars();
- curTrainDlg->train = NULL;
- curTrainDlg->speed = -1;
- wDrawClear( (wDraw_p)curTrainDlg->trainPGp->paramPtr[I_SLIDER].control );
- LocoListInit();
- ControllerDialogSync( curTrainDlg );
- wShow( curTrainDlg->win );
- wControlShow( (wControl_p)newcarB, (toolbarSet&(1<<BG_HOTBAR)) == 0 );
- currCarItemPtr = NULL;
- return C_CONTINUE;
-
- case C_TEXT:
- if ( Dtrain.state == 0 )
- return C_CONTINUE;
- else
- return C_CONTINUE;
-
- case C_DOWN:
- /*trainEnable = FALSE;*/
- InfoMessage( "" );
- if ( trainsState == TRAINS_RUN ) {
- trainsState = TRAINS_PAUSE;
- TrainTimeEndPause();
- }
- pos0 = pos;
- if ( currCarItemPtr != NULL ) {
-#ifdef LATER
- ParamLoadData( &newCarPG );
-#endif
- currCar = NewCar( -1, currCarItemPtr, zero, 0.0 );
- CarItemUpdate( currCarItemPtr );
- HotBarCancel();
- if ( currCar == NULL ) {
- LOG1( log_error, ( "Train: currCar became NULL 1\n" ) )
- return C_CONTINUE;
- }
- xx = GetTrkExtraData(currCar);
- dist = CarItemCoupledLength(xx->item)/2.0;
- Translate( &pos, xx->trvTrk.pos, xx->trvTrk.angle, dist );
- SetTrkEndPoint( currCar, 0, pos, xx->trvTrk.angle );
- Translate( &pos, xx->trvTrk.pos, xx->trvTrk.angle+180.0, dist );
- SetTrkEndPoint( currCar, 1, pos, NormalizeAngle(xx->trvTrk.angle+180.0) );
- /*xx->state |= (xx->item->options&CAR_DESC_BITS);*/
- ClrLocoMaster(xx);
- if ( CarItemIsLoco(xx->item) ) {
- SetLocoMaster(xx);
- LocoListChangeEntry( NULL, currCar );
- if ( currCar == NULL ) {
- LOG1( log_error, ( "Train: currCar became NULL 2\n" ) )
- return C_CONTINUE;
- }
- }
-#ifdef LATER
- wPrefSetString( "Car Road Name", xx->ITEM->title, newCarRoad );
- number = strtol( CarItemNumber(xx->item), &cp, 10 );
- if ( cp == NULL || *cp != 0 )
- number = -1;
- wPrefSetInteger( "Car Number", xx->ITEM->title, number );
-#endif
- if( (trk0 = OnTrack( &pos0, FALSE, TRUE ) ) ) {
- xx->trvTrk.angle = GetAngleAtPoint( trk0, pos0, &ep0, &ep1 );
- if ( NormalizeAngle( FindAngle( pos, pos0 ) - xx->trvTrk.angle ) > 180.0 )
- xx->trvTrk.angle = NormalizeAngle( xx->trvTrk.angle + 180 );
- xx->status = ST_StopManual;
- } else {
- xx->trvTrk.angle = 90;
- }
- PlaceTrainInit( currCar, trk0, pos0, xx->trvTrk.angle, (MyGetKeyState()&WKEY_SHIFT) == 0 );
- /*DrawCars( &tempD, currCar, TRUE );*/
- } else {
- currCar = FindCar( &pos );
- delta.x = pos.x - pos0.x;
- delta.y = pos.y - pos0.y;
- if ( logTable(log_trainMove).level >= 1 ) {
- if ( currCar ) {
- xx = GetTrkExtraData(currCar);
- LogPrintf( "selected %s\n", CarItemNumber(xx->item) );
- for ( dir=0; dir<2; dir++ ) {
- int dir1 = dir;
- track_p car1 = currCar;
- struct extraData * xx1 = GetTrkExtraData(car1);
- LogPrintf( "dir=%d\n", dir1 );
- WALK_CARS_START( car1, xx1, dir1 )
- LogPrintf( " %s [%0.3f,%d]\n", CarItemNumber(xx1->item), xx1->trvTrk.angle, dir1 );
- WALK_CARS_END( car1, xx1, dir1 )
- }
- }
- }
- }
- if ( currCar == NULL )
- return C_CONTINUE;
- trk0 = FindMasterLoco( currCar, NULL );
- if ( trk0 )
- SetCurTrain( trk0 );
- DrawAllCars();
- return C_CONTINUE;
-
- case C_MOVE:
- if ( currCar == NULL )
- return C_CONTINUE;
- pos.x += delta.x;
- pos.y += delta.y;
- pos0 = pos;
- /*DrawCars( &tempD, currCar, FALSE );*/
- xx = GetTrkExtraData(currCar);
- trk0 = OnTrack( &pos0, FALSE, TRUE );
- if ( /*currCarItemPtr != NULL &&*/ trk0 ) {
- angle1 = GetAngleAtPoint( trk0, pos0, &ep0, &ep1 );
- if ( currCarItemPtr != NULL ) {
- if ( NormalizeAngle( FindAngle( pos, pos0 ) - angle1 ) > 180.0 )
- angle1 = NormalizeAngle( angle1 + 180 );
- } else {
- if ( NormalizeAngle( xx->trvTrk.angle - angle1 + 90.0 ) > 180.0 )
- angle1 = NormalizeAngle( angle1 + 180 );
- }
- xx->trvTrk.angle = angle1;
- }
- tempSegs_da.cnt = 1;
- PlaceTrainInit( currCar, trk0, pos0, xx->trvTrk.angle, (MyGetKeyState()&WKEY_SHIFT) == 0 );
- ControllerDialogSync( curTrainDlg );
- DrawAllCars();
- return C_CONTINUE;
-
-
- case C_UP:
- if ( currCar != NULL ) {
- trk0 = FindMasterLoco( currCar, NULL );
- if ( trk0 ) {
- xx = GetTrkExtraData( trk0 );
- if ( !IsOnTrack(xx) || xx->speed <= 0 )
- StopTrain( trk0, ST_StopManual );
- }
- Dtrain.state = 1;
- /*MainRedraw();*/
- ControllerDialogSync( curTrainDlg );
- }
- DrawAllCars();
- InfoSubstituteControls( NULL, NULL );
- currCar = trk0 = NULL;
- currCarItemPtr = NULL;
- /*trainEnable = TRUE;*/
- if ( trainsState == TRAINS_PAUSE ) {
- RestartTrains();
- }
- return C_CONTINUE;
-
- case C_LCLICK:
- if ( MyGetKeyState() & WKEY_SHIFT ) {
- pos0 = pos;
- programMode = MODE_DESIGN;
- if ( (trk0=OnTrack(&pos,FALSE,TRUE)) &&
- QueryTrack( trk0, Q_CAN_NEXT_POSITION ) &&
- TrainOnMovableTrack( trk0, &trk1) ) {
- if ( trk1 ) {
- xx = GetTrkExtraData(trk1);
- pos1 = xx->trvTrk.pos;
- angle1 = xx->trvTrk.angle;
- } else {
- pos1 = pos0;
- angle1 = 0;
- }
- AdvancePositionIndicator( trk0, pos0, &pos1, &angle1 );
- if ( trk1 ) {
- xx->trvTrk.pos = pos1;
- xx->trvTrk.angle = angle1;
- PlaceTrain( trk1, FALSE, TRUE );
- DrawAllCars();
- }
- }
- programMode = MODE_TRAIN;
- trk0 = NULL;
+ track_p trk0, trk1;
+ static track_p currCar;
+ coOrd pos0, pos1;
+ static coOrd delta;
+ ANGLE_T angle1;
+ EPINX_T ep0, ep1;
+ int dir;
+ struct extraData * xx=NULL;
+ wPos_t w, h;
+
+ switch (action) {
+ case C_START:
+ /*UndoStart( "Trains", "Trains" );*/
+ UndoSuspend();
+ programMode = MODE_TRAIN;
+ drawCarEnable = FALSE;
+ doDrawTurnoutPosition = 1;
+ DoChangeNotification(CHANGE_PARAMS|CHANGE_TOOLBAR);
+
+ if (CarAvailableCount() <= 0) {
+ if (NoticeMessage(MSG_NO_CARS, _("Yes"), _("No")) > 0) {
+ DoCarDlg();
+ DoChangeNotification(CHANGE_PARAMS);
+ }
+ }
+
+ EnableCommands();
+
+ if (curTrainDlg == NULL) {
+ curTrainDlg = CreateTrainControlDlg();
+ }
+
+ curTrainDlg->train = NULL;
+ wListClear((wList_p)curTrainDlg->trainPGp->paramPtr[I_LIST].control);
+ Dtrain.state = 0;
+ trk0 = NULL;
+ tempSegs_da.cnt = 0;
+ DYNARR_SET(trkSeg_t, tempSegs_da, 8);
+ RestartTrains();
+ wButtonSetLabel(trainPauseB, (char*)goI);
+ trainTime0 = 0;
+ AttachTrains();
+ DrawAllCars();
+ curTrainDlg->train = NULL;
+ curTrainDlg->speed = -1;
+ wDrawClear((wDraw_p)curTrainDlg->trainPGp->paramPtr[I_SLIDER].control);
+ LocoListInit();
+ ControllerDialogSync(curTrainDlg);
+ wShow(curTrainDlg->win);
+ wControlShow((wControl_p)newcarB, (toolbarSet&(1<<BG_HOTBAR)) == 0);
+ currCarItemPtr = NULL;
+ return C_CONTINUE;
+
+ case C_TEXT:
+ if (Dtrain.state == 0) {
+ return C_CONTINUE;
+ } else {
+ return C_CONTINUE;
+ }
+
+ case C_DOWN:
+ /*trainEnable = FALSE;*/
+ InfoMessage("");
+
+ if (trainsState == TRAINS_RUN) {
+ trainsState = TRAINS_PAUSE;
+ TrainTimeEndPause();
+ }
+
+ pos0 = pos;
+
+ if (currCarItemPtr != NULL) {
+ DIST_T dist;
+ currCar = NewCar(-1, currCarItemPtr, zero, 0.0);
+ CarItemUpdate(currCarItemPtr);
+ HotBarCancel();
+
+ if (currCar == NULL) {
+ LOG1(log_error, ("Train: currCar became NULL 1\n"))
+ return C_CONTINUE;
+ }
+
+ xx = GetTrkExtraData(currCar);
+ dist = CarItemCoupledLength(xx->item)/2.0;
+ Translate(&pos, xx->trvTrk.pos, xx->trvTrk.angle, dist);
+ SetTrkEndPoint(currCar, 0, pos, xx->trvTrk.angle);
+ Translate(&pos, xx->trvTrk.pos, xx->trvTrk.angle+180.0, dist);
+ SetTrkEndPoint(currCar, 1, pos, NormalizeAngle(xx->trvTrk.angle+180.0));
+ /*xx->state |= (xx->item->options&CAR_DESC_BITS);*/
+ ClrLocoMaster(xx);
+
+ if (CarItemIsLoco(xx->item)) {
+ SetLocoMaster(xx);
+ LocoListChangeEntry(NULL, currCar);
+ }
+
+ if ((trk0 = OnTrack(&pos0, FALSE, TRUE))) {
+ xx->trvTrk.angle = GetAngleAtPoint(trk0, pos0, &ep0, &ep1);
+
+ if (NormalizeAngle(FindAngle(pos, pos0) - xx->trvTrk.angle) > 180.0) {
+ xx->trvTrk.angle = NormalizeAngle(xx->trvTrk.angle + 180);
+ }
+
+ xx->status = ST_StopManual;
+ } else {
+ xx->trvTrk.angle = 90;
+ }
+
+ PlaceTrainInit(currCar, trk0, pos0, xx->trvTrk.angle,
+ (MyGetKeyState()&WKEY_SHIFT) == 0);
+ /*DrawCars( &tempD, currCar, TRUE );*/
+ } else {
+ currCar = FindCar(&pos);
+ delta.x = pos.x - pos0.x;
+ delta.y = pos.y - pos0.y;
+
+ if (logTable(log_trainMove).level >= 1) {
+ if (currCar) {
+ xx = GetTrkExtraData(currCar);
+ LogPrintf("selected %s\n", CarItemNumber(xx->item));
+
+ for (dir=0; dir<2; dir++) {
+ int dir1 = dir;
+ track_p car1 = currCar;
+ struct extraData * xx1 = GetTrkExtraData(car1);
+ LogPrintf("dir=%d\n", dir1);
+ WALK_CARS_START(car1, xx1, dir1)
+ LogPrintf(" %s [%0.3f,%d]\n", CarItemNumber(xx1->item), xx1->trvTrk.angle,
+ dir1);
+ WALK_CARS_END(car1, xx1, dir1)
+ }
+ }
+ }
+ }
+
+ if (currCar == NULL) {
+ return C_CONTINUE;
+ }
+
+ trk0 = FindMasterLoco(currCar, NULL);
+
+ if (trk0) {
+ SetCurTrain(trk0);
+ }
+
+ DrawAllCars();
+ return C_CONTINUE;
+
+ case C_MOVE:
+ if (currCar == NULL) {
+ return C_CONTINUE;
+ }
+
+ pos.x += delta.x;
+ pos.y += delta.y;
+ pos0 = pos;
+ /*DrawCars( &tempD, currCar, FALSE );*/
+ xx = GetTrkExtraData(currCar);
+ trk0 = OnTrack(&pos0, FALSE, TRUE);
+
+ if (/*currCarItemPtr != NULL &&*/ trk0) {
+ angle1 = GetAngleAtPoint(trk0, pos0, &ep0, &ep1);
+
+ if (currCarItemPtr != NULL) {
+ if (NormalizeAngle(FindAngle(pos, pos0) - angle1) > 180.0) {
+ angle1 = NormalizeAngle(angle1 + 180);
+ }
+ } else {
+ if (NormalizeAngle(xx->trvTrk.angle - angle1 + 90.0) > 180.0) {
+ angle1 = NormalizeAngle(angle1 + 180);
+ }
+ }
+
+ xx->trvTrk.angle = angle1;
+ }
+
+ tempSegs_da.cnt = 1;
+ PlaceTrainInit(currCar, trk0, pos0, xx->trvTrk.angle,
+ (MyGetKeyState()&WKEY_SHIFT) == 0);
+ ControllerDialogSync(curTrainDlg);
+ DrawAllCars();
+ return C_CONTINUE;
+
+ case C_UP:
+ if (currCar != NULL) {
+ trk0 = FindMasterLoco(currCar, NULL);
+
+ if (trk0) {
+ xx = GetTrkExtraData(trk0);
+
+ if (!IsOnTrack(xx) || xx->speed <= 0) {
+ StopTrain(trk0, ST_StopManual);
+ }
+ }
+
+ Dtrain.state = 1;
+ /*MainRedraw();*/
+ ControllerDialogSync(curTrainDlg);
+ }
+
+ DrawAllCars();
+ InfoSubstituteControls(NULL, NULL);
+ currCar = trk0 = NULL;
+ currCarItemPtr = NULL;
+
+ /*trainEnable = TRUE;*/
+ if (trainsState == TRAINS_PAUSE) {
+ RestartTrains();
+ }
+
+ return C_CONTINUE;
+
+ case C_LCLICK:
+ if (MyGetKeyState() & WKEY_SHIFT) {
+ pos0 = pos;
+ programMode = MODE_DESIGN;
+
+ if ((trk0=OnTrack(&pos,FALSE,TRUE)) &&
+ QueryTrack(trk0, Q_CAN_NEXT_POSITION) &&
+ TrainOnMovableTrack(trk0, &trk1)) {
+ if (trk1) {
+ xx = GetTrkExtraData(trk1);
+ pos1 = xx->trvTrk.pos;
+ angle1 = xx->trvTrk.angle;
+ } else {
+ pos1 = pos0;
+ angle1 = 0;
+ }
+
+ AdvancePositionIndicator(trk0, pos0, &pos1, &angle1);
+
+ if (trk1) {
+ xx->trvTrk.pos = pos1;
+ xx->trvTrk.angle = angle1;
+ PlaceTrain(trk1, FALSE, TRUE);
+ DrawAllCars();
+ }
+ }
+
+ programMode = MODE_TRAIN;
+ trk0 = NULL;
MainRedraw(); //Make sure track is redrawn after switch thrown
- } else {
- trk0 = FindCar( &pos );
- if ( trk0 == NULL )
- return C_CONTINUE;
- trk0 = FindMasterLoco( trk0, NULL );
- if ( trk0 == NULL )
- return C_CONTINUE;
- SetCurTrain( trk0 );
- }
- return C_CONTINUE;
-
- case C_RCLICK:
- trainFuncPos = pos;
- trainFuncCar = FindCar( &pos );
- if ( trainFuncCar == NULL ||
- GetTrkType(trainFuncCar) != T_CAR )
- return C_CONTINUE;
- xx = GetTrkExtraData( trainFuncCar );
- trk0 = FindMasterLoco(trainFuncCar,NULL);
- dir = IsAligned( xx->trvTrk.angle, FindAngle(xx->trvTrk.pos,trainFuncPos) ) ? 0 : 1;
- wMenuPushEnable( trainPopupMI[DO_UNCOUPLE], GetTrkEndTrk( trainFuncCar, dir )!=NULL );
- wMenuPushEnable( trainPopupMI[DO_MUMASTER], CarItemIsLoco(xx->item) && !IsLocoMaster(xx) );
- if ( trk0 ) xx = GetTrkExtraData(trk0);
- wMenuPushEnable( trainPopupMI[DO_CHANGEDIR], trk0!=NULL );
- wMenuPushEnable( trainPopupMI[DO_STOP], trk0!=NULL && xx->speed>0 );
- /*trainEnable = FALSE;*/
-#ifdef LATER
- if ( trainsState == TRAINS_RUN )
- trainsState = TRAINS_PAUSE;
-#endif
- trk0 = FindMasterLoco( trainFuncCar, NULL );
- if ( trk0 )
- SetCurTrain( trk0 );
- if ( !inPlayback )
- wMenuPopupShow( trainPopupM );
- return C_CONTINUE;
-
- case C_REDRAW:
-#ifdef LATER
- if (Dtrain.state == 1 && !suppressTrainRedraw) {
- mainD.funcs->options = wDrawOptTemp;
- mainD.funcs->options = 0;
- }
-#endif
- wDrawSaveImage(mainD.d);
- DrawAllCars();
- wWinGetSize( mainW, &w, &h );
- w -= wControlGetPosX( newCarControls[0] ) + 4;
- if ( w > 20 )
- wListSetSize( (wList_p)newCarControls[0], w, wControlGetHeight( newCarControls[0] ) );
- return C_CONTINUE;
-
- case C_CANCEL:
- /*trainEnable = FALSE;*/
- trainsState = TRAINS_STOP;
- TrainTimeEndPause();
- LOG( log_trainMove, 1, ( "Train Cancel\n" ) )
- Dtrain.state = 0;
- doDrawTurnoutPosition = 0;
- drawCarEnable = TRUE;
- programMode = MODE_DESIGN;
- UpdateTrainAttachment();
- UndoResume();
- DoChangeNotification( CHANGE_PARAMS|CHANGE_TOOLBAR );
- if ( curTrainDlg->win )
- wHide( curTrainDlg->win );
- MainRedraw();
- curTrainDlg->train = NULL;
- return C_CONTINUE;
-
-
- case C_CONFIRM:
- /*trainEnable = FALSE;*/
- if ( trainsState != TRAINS_STOP ) {
- trainsState = TRAINS_STOP;
- wButtonSetLabel( trainPauseB, (char*)stopI );
- TrainTimeEndPause();
- }
- currCar = NULL;
- currCarItemPtr = NULL;
- HotBarCancel();
- InfoSubstituteControls( NULL, NULL );
- return C_TERMINATE;
-
- }
-
- return C_CONTINUE;
-
+ MapRedraw();
+ } else {
+ trk0 = FindCar(&pos);
+
+ if (trk0 == NULL) {
+ return C_CONTINUE;
+ }
+
+ trk0 = FindMasterLoco(trk0, NULL);
+
+ if (trk0 == NULL) {
+ return C_CONTINUE;
+ }
+
+ SetCurTrain(trk0);
+ }
+
+ return C_CONTINUE;
+
+ case C_RCLICK:
+ trainFuncPos = pos;
+ trainFuncCar = FindCar(&pos);
+
+ if (trainFuncCar == NULL ||
+ GetTrkType(trainFuncCar) != T_CAR) {
+ return C_CONTINUE;
+ }
+
+ xx = GetTrkExtraData(trainFuncCar);
+ trk0 = FindMasterLoco(trainFuncCar,NULL);
+ dir = IsAligned(xx->trvTrk.angle, FindAngle(xx->trvTrk.pos,
+ trainFuncPos)) ? 0 : 1;
+ wMenuPushEnable(trainPopupMI[DO_UNCOUPLE], GetTrkEndTrk(trainFuncCar,
+ dir)!=NULL);
+ wMenuPushEnable(trainPopupMI[DO_MUMASTER], CarItemIsLoco(xx->item) &&
+ !IsLocoMaster(xx));
+
+ if (trk0) {
+ xx = GetTrkExtraData(trk0);
+ }
+
+ wMenuPushEnable(trainPopupMI[DO_CHANGEDIR], trk0!=NULL);
+ wMenuPushEnable(trainPopupMI[DO_STOP], trk0!=NULL && xx->speed>0);
+ /*trainEnable = FALSE;*/
+ trk0 = FindMasterLoco(trainFuncCar, NULL);
+
+ if (trk0) {
+ SetCurTrain(trk0);
+ }
+
+ if (!inPlayback) {
+ wMenuPopupShow(trainPopupM);
+ }
+
+ return C_CONTINUE;
+
+ case C_REDRAW:
+ wDrawSaveImage(mainD.d);
+ DrawAllCars();
+ wWinGetSize(mainW, &w, &h);
+ w -= wControlGetPosX(newCarControls[0]) + 4;
+
+ if (w > 20) {
+ wListSetSize((wList_p)newCarControls[0], w,
+ wControlGetHeight(newCarControls[0]));
+ }
+
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ /*trainEnable = FALSE;*/
+ trainsState = TRAINS_STOP;
+ TrainTimeEndPause();
+ LOG(log_trainMove, 1, ("Train Cancel\n"))
+ Dtrain.state = 0;
+ doDrawTurnoutPosition = 0;
+ drawCarEnable = TRUE;
+ programMode = MODE_DESIGN;
+ UpdateTrainAttachment();
+ UndoResume();
+ DoChangeNotification(CHANGE_PARAMS|CHANGE_TOOLBAR);
+
+ if (curTrainDlg->win) {
+ wHide(curTrainDlg->win);
+ }
+
+ MainRedraw();
+ MapRedraw();
+ curTrainDlg->train = NULL;
+ return C_CONTINUE;
+
+ case C_CONFIRM:
+
+ /*trainEnable = FALSE;*/
+ if (trainsState != TRAINS_STOP) {
+ trainsState = TRAINS_STOP;
+ wButtonSetLabel(trainPauseB, (char*)stopI);
+ TrainTimeEndPause();
+ }
+
+ currCar = NULL;
+ currCarItemPtr = NULL;
+ HotBarCancel();
+ InfoSubstituteControls(NULL, NULL);
+ return C_TERMINATE;
+ }
+
+ return C_CONTINUE;
}
@@ -2347,11 +2763,11 @@ static STATUS_T CmdTrain( wAction_t action, coOrd pos )
*
*/
-EXPORT STATUS_T CmdCarDescAction(
- wAction_t action,
- coOrd pos )
+STATUS_T CmdCarDescAction(
+ wAction_t action,
+ coOrd pos)
{
- return CmdTrain( action, pos );
+ return CmdTrain(action, pos);
}
#include "bitmaps/train.xpm"
@@ -2362,225 +2778,269 @@ EXPORT STATUS_T CmdCarDescAction(
#include "bitmaps/ballred.xpm"
-static void CmdTrainStopGo( void * junk )
+static void CmdTrainStopGo(void * junk)
{
- wIcon_p icon;
- if ( trainsState == TRAINS_STOP ) {
- icon = goI;
- RestartTrains();
- } else {
- trainsState = TRAINS_STOP;
- icon = stopI;
- TrainTimeEndPause();
- }
- ControllerDialogSync( curTrainDlg );
- wButtonSetLabel( trainPauseB, (char*)icon );
- if ( recordF )
- fprintf( recordF, "TRAINSTOPGO %s\n", trainsState==TRAINS_STOP?"STOP":"GO" );
+ wIcon_p icon;
+
+ if (trainsState == TRAINS_STOP) {
+ icon = goI;
+ RestartTrains();
+ } else {
+ trainsState = TRAINS_STOP;
+ icon = stopI;
+ TrainTimeEndPause();
+ }
+
+ ControllerDialogSync(curTrainDlg);
+ wButtonSetLabel(trainPauseB, (char*)icon);
+
+ if (recordF) {
+ fprintf(recordF, "TRAINSTOPGO %s\n", trainsState==TRAINS_STOP?"STOP":"GO");
+ }
}
-static BOOL_T TrainStopGoPlayback( char * line )
+static BOOL_T TrainStopGoPlayback(char * line)
{
- while (*line && isspace((unsigned char)*line) ) line++;
- if ( (strcasecmp( line, "STOP" ) == 0) != (trainsState == TRAINS_STOP) )
- CmdTrainStopGo(NULL);
- return TRUE;
+ while (*line && isspace((unsigned char)*line)) {
+ line++;
+ }
+
+ if ((strcasecmp(line, "STOP") == 0) != (trainsState == TRAINS_STOP)) {
+ CmdTrainStopGo(NULL);
+ }
+
+ return TRUE;
}
-static void CmdTrainExit( void * junk )
+static void CmdTrainExit(void * junk)
{
- Reset();
- InfoSubstituteControls( NULL, NULL );
- MainRedraw();
+ Reset();
+ InfoSubstituteControls(NULL, NULL);
+ MainRedraw();
+ MapRedraw();
}
static void TrainFunc(
- void * action )
+ void * action)
{
- struct extraData * xx, *xx1;
- ANGLE_T angle;
- int dir;
- track_p loco;
- track_p temp0, temp1;
- coOrd pos0, pos1;
- ANGLE_T angle0, angle1;
- EPINX_T ep0=-1, ep1=-1;
-
- if ( trainFuncCar == NULL ) {
- fprintf( stderr, "trainFunc: trainFuncCar==NULL\n" );
- return;
- }
+ struct extraData * xx, *xx1;
+ ANGLE_T angle;
+ int dir;
+ track_p loco;
+ track_p temp0, temp1;
+ coOrd pos0, pos1;
+ ANGLE_T angle0, angle1;
+ EPINX_T ep0=-1, ep1=-1;
+
+ if (trainFuncCar == NULL) {
+ fprintf(stderr, "trainFunc: trainFuncCar==NULL\n");
+ return;
+ }
+
+ xx = GetTrkExtraData(trainFuncCar);
+ angle = FindAngle(xx->trvTrk.pos, trainFuncPos);
+ angle = NormalizeAngle(angle-xx->trvTrk.angle);
+ dir = (angle>90&&angle<270);
+
+ switch ((int)(long)action) {
+ case DO_UNCOUPLE:
+ if (GetTrkEndTrk(trainFuncCar,dir)) {
+ UncoupleCars(trainFuncCar, GetTrkEndTrk(trainFuncCar,dir));
+ }
+
+ break;
+
+ case DO_FLIPCAR:
+ temp0 = GetTrkEndTrk(trainFuncCar,0);
+ pos0 = GetTrkEndPos(trainFuncCar,0);
+ angle0 = GetTrkEndAngle(trainFuncCar,0);
+ temp1 = GetTrkEndTrk(trainFuncCar,1);
+ pos1 = GetTrkEndPos(trainFuncCar,1);
+ angle1 = GetTrkEndAngle(trainFuncCar,1);
+
+ if (temp0) {
+ ep0 = GetEndPtConnectedToMe(temp0,trainFuncCar);
+ trainFuncCar->endPt[0].track = NULL;
+ temp0->endPt[ep0].track = NULL;
+ }
+
+ if (temp1) {
+ ep1 = GetEndPtConnectedToMe(temp1,trainFuncCar);
+ trainFuncCar->endPt[1].track = NULL;
+ temp1->endPt[ep1].track = NULL;
+ }
+
+ xx->direction = !xx->direction;
+ FlipTraverseTrack(&xx->trvTrk);
+ SetTrkEndPoint(trainFuncCar, 0, pos1, angle1);
+ SetTrkEndPoint(trainFuncCar, 1, pos0, angle0);
+
+ if (temp0) {
+ trainFuncCar->endPt[1].track = temp0;
+ temp0->endPt[ep0].track = trainFuncCar;
+ }
+
+ if (temp1) {
+ trainFuncCar->endPt[0].track = temp1;
+ temp1->endPt[ep1].track = trainFuncCar;
+ }
+
+ ControllerDialogSync(curTrainDlg);
+ PlaceCar(trainFuncCar);
+ break;
+
+ case DO_FLIPTRAIN:
+ FlipTrain(trainFuncCar);
+ /*PlaceTrain( trainFuncCar, xx->trk, xx->trvTrk.pos, xx->trvTrk.angle );*/
+ break;
+
+ case DO_DELCAR:
+ for (dir=0; dir<2; dir++)
+ if (GetTrkEndTrk(trainFuncCar,dir)) {
+ UncoupleCars(trainFuncCar, GetTrkEndTrk(trainFuncCar,dir));
+ }
+
+ if (CarItemIsLoco(xx->item)) {
+ LocoListChangeEntry(trainFuncCar, NULL);
+ }
+
+ trainFuncCar->deleted = TRUE;
+ /*DeleteTrack( trainFuncCar, FALSE );*/
+ CarItemUpdate(xx->item);
+ HotBarCancel();
+ InfoSubstituteControls(NULL, NULL);
+ break;
+
+ case DO_DELTRAIN:
+ dir = 0;
+ loco = FindMasterLoco(trainFuncCar, NULL);
+ WALK_CARS_START(trainFuncCar, xx, dir)
+ WALK_CARS_END(trainFuncCar, xx, dir)
+ dir = 1-dir;
+ temp0 = NULL;
+ WALK_CARS_START(trainFuncCar, xx, dir)
+
+ if (temp0) {
+ xx1 = GetTrkExtraData(temp0);
+ temp0->deleted = TRUE;
+ /*DeleteTrack( temp0, FALSE );*/
+ CarItemUpdate(xx1->item);
+ }
+
+ temp0 = trainFuncCar;
+ WALK_CARS_END(trainFuncCar, xx, dir)
+
+ if (temp0) {
+ xx1 = GetTrkExtraData(temp0);
+ temp0->deleted = TRUE;
+ /*DeleteTrack( temp0, FALSE );*/
+ CarItemUpdate(xx1->item);
+ }
+
+ if (loco) {
+ LocoListChangeEntry(loco, NULL);
+ }
+
+ HotBarCancel();
+ InfoSubstituteControls(NULL, NULL);
+ break;
+
+ case DO_MUMASTER:
+ if (CarItemIsLoco(xx->item)) {
+ loco = FindMasterLoco(trainFuncCar, NULL);
+
+ if (loco != trainFuncCar) {
+ SetLocoMaster(xx);
+ LOG(log_trainMove, 1, ("%s gets master\n", CarItemNumber(xx->item)))
+
+ if (loco) {
+ xx1 = GetTrkExtraData(loco);
+ ClrLocoMaster(xx1);
+ LOG(log_trainMove, 1, ("%s looses master\n", CarItemNumber(xx1->item)))
+ xx->speed = xx1->speed;
+ xx1->speed = 0;
+ }
+
+ LocoListChangeEntry(loco, trainFuncCar);
+ }
+ }
+
+ break;
+
+ case DO_CHANGEDIR:
+ loco = FindMasterLoco(trainFuncCar, NULL);
+
+ if (loco) {
+ xx = GetTrkExtraData(loco);
+ xx->direction = !xx->direction;
+ SetTrainDirection(loco);
+ ControllerDialogSync(curTrainDlg);
+ }
+
+ break;
+
+ case DO_STOP:
+ loco = FindMasterLoco(trainFuncCar, NULL);
+
+ if (loco) {
+ StopTrain(loco, ST_StopManual);
+ ControllerDialogSync(curTrainDlg);
+ }
+
+ break;
+ }
- xx = GetTrkExtraData(trainFuncCar);
- angle = FindAngle( xx->trvTrk.pos, trainFuncPos );
- angle = NormalizeAngle( angle-xx->trvTrk.angle );
- dir = (angle>90&&angle<270);
-
- switch ((int)(long)action) {
- case DO_UNCOUPLE:
- if ( GetTrkEndTrk(trainFuncCar,dir) )
- UncoupleCars( trainFuncCar, GetTrkEndTrk(trainFuncCar,dir) );
- break;
- case DO_FLIPCAR:
- temp0 = GetTrkEndTrk(trainFuncCar,0);
- pos0 = GetTrkEndPos(trainFuncCar,0);
- angle0 = GetTrkEndAngle(trainFuncCar,0);
- temp1 = GetTrkEndTrk(trainFuncCar,1);
- pos1 = GetTrkEndPos(trainFuncCar,1);
- angle1 = GetTrkEndAngle(trainFuncCar,1);
- if ( temp0 ) {
- ep0 = GetEndPtConnectedToMe(temp0,trainFuncCar);
- trainFuncCar->endPt[0].track = NULL;
- temp0->endPt[ep0].track = NULL;
- }
- if ( temp1 ) {
- ep1 = GetEndPtConnectedToMe(temp1,trainFuncCar);
- trainFuncCar->endPt[1].track = NULL;
- temp1->endPt[ep1].track = NULL;
- }
- xx->direction = !xx->direction;
- FlipTraverseTrack( &xx->trvTrk );
- SetTrkEndPoint( trainFuncCar, 0, pos1, angle1 );
- SetTrkEndPoint( trainFuncCar, 1, pos0, angle0 );
- if ( temp0 ) {
- trainFuncCar->endPt[1].track = temp0;
- temp0->endPt[ep0].track = trainFuncCar;
- }
- if ( temp1 ) {
- trainFuncCar->endPt[0].track = temp1;
- temp1->endPt[ep1].track = trainFuncCar;
- }
- ControllerDialogSync( curTrainDlg );
- PlaceCar( trainFuncCar );
- break;
- case DO_FLIPTRAIN:
- FlipTrain( trainFuncCar );
- /*PlaceTrain( trainFuncCar, xx->trk, xx->trvTrk.pos, xx->trvTrk.angle );*/
- break;
- case DO_DELCAR:
- for ( dir=0; dir<2; dir++ )
- if ( GetTrkEndTrk(trainFuncCar,dir) )
- UncoupleCars( trainFuncCar, GetTrkEndTrk(trainFuncCar,dir) );
- if ( CarItemIsLoco(xx->item) )
- LocoListChangeEntry( trainFuncCar, NULL );
- trainFuncCar->deleted = TRUE;
- /*DeleteTrack( trainFuncCar, FALSE );*/
- CarItemUpdate( xx->item );
- HotBarCancel();
- InfoSubstituteControls( NULL, NULL );
- break;
- case DO_DELTRAIN:
- dir = 0;
- loco = FindMasterLoco( trainFuncCar, NULL );
- WALK_CARS_START( trainFuncCar, xx, dir )
- WALK_CARS_END( trainFuncCar, xx, dir )
- dir = 1-dir;
- temp0 = NULL;
- WALK_CARS_START( trainFuncCar, xx, dir )
- if ( temp0 ) {
- xx1 = GetTrkExtraData(temp0);
- temp0->deleted = TRUE;
- /*DeleteTrack( temp0, FALSE );*/
- CarItemUpdate( xx1->item );
- }
- temp0 = trainFuncCar;
- WALK_CARS_END( trainFuncCar, xx, dir )
- if ( temp0 ) {
- xx1 = GetTrkExtraData(temp0);
- temp0->deleted = TRUE;
- /*DeleteTrack( temp0, FALSE );*/
- CarItemUpdate( xx1->item );
- }
- if ( loco )
- LocoListChangeEntry( loco, NULL );
- HotBarCancel();
- InfoSubstituteControls( NULL, NULL );
- break;
- case DO_MUMASTER:
- if ( CarItemIsLoco(xx->item) ) {
- loco = FindMasterLoco( trainFuncCar, NULL );
- if ( loco != trainFuncCar ) {
- SetLocoMaster(xx);
- LOG( log_trainMove, 1, ( "%s gets master\n", CarItemNumber(xx->item) ) )
- if ( loco ) {
- xx1 = GetTrkExtraData( loco );
- ClrLocoMaster(xx1);
- LOG( log_trainMove, 1, ( "%s looses master\n", CarItemNumber(xx1->item) ) )
- xx->speed = xx1->speed;
- xx1->speed = 0;
- }
- LocoListChangeEntry( loco, trainFuncCar );
- }
- }
- break;
- case DO_CHANGEDIR:
- loco = FindMasterLoco( trainFuncCar, NULL );
- if ( loco ) {
- xx = GetTrkExtraData(loco);
- xx->direction = !xx->direction;
- SetTrainDirection(loco);
- ControllerDialogSync( curTrainDlg );
- }
- break;
- case DO_STOP:
- loco = FindMasterLoco( trainFuncCar, NULL );
- if ( loco ) {
- StopTrain( loco, ST_StopManual );
- ControllerDialogSync( curTrainDlg );
- }
- break;
- }
MainRedraw(); //Redraw if Train altered
+ MapRedraw();
- if ( trainsState == TRAINS_PAUSE ) {
- RestartTrains();
- } else {
- DrawAllCars();
- }
+ if (trainsState == TRAINS_PAUSE) {
+ RestartTrains();
+ } else {
+ DrawAllCars();
+ }
}
-EXPORT void InitCmdTrain( wMenu_p menu )
+void InitCmdTrain(wMenu_p menu)
{
- log_trainMove = LogFindIndex( "trainMove" );
- log_trainPlayback = LogFindIndex( "trainPlayback" );
- trainPLs[I_ZERO].winLabel = (char*)wIconCreatePixMap(zero_xpm);
- ParamRegister( &trainPG );
- AddMenuButton( menu, CmdTrain, "cmdTrain", _("Train"), wIconCreatePixMap(train_xpm), LEVEL0_50, IC_POPUP2|IC_LCLICK|IC_RCLICK, 0, NULL );
- stopI = wIconCreatePixMap( ballred );
- goI = wIconCreatePixMap( ballgreen );
- trainPauseB = AddToolbarButton( "cmdTrainPause", stopI, IC_MODETRAIN_ONLY, CmdTrainStopGo, NULL );
- AddToolbarButton( "cmdTrainExit", wIconCreatePixMap(exit_xpm), IC_MODETRAIN_ONLY, CmdTrainExit, NULL );
- newcarB = AddToolbarButton( "cmdTrainNewCar", wIconCreatePixMap(newcar_xpm), IC_MODETRAIN_ONLY, CarItemLoadList, NULL );
-
- T_CAR = InitObject( &carCmds );
-
-#ifdef LATER
- trainPGp = ParamCreateGroup( "trainW", "train", 0, trainPLs, sizeof trainPLs/sizeof trainPLs[0], NULL, 0, _("Ok"), trainOk, wHide );
- ParamRegister( trainPGp );
-#endif
-
- trainPopupM = MenuRegister( "Train Commands" );
- trainPopupMI[DO_UNCOUPLE] = wMenuPushCreate( trainPopupM, "", _("Uncouple"), 0, TrainFunc, (void*)DO_UNCOUPLE );
- trainPopupMI[DO_FLIPCAR] = wMenuPushCreate( trainPopupM, "", _("Flip Car"), 0, TrainFunc, (void*)DO_FLIPCAR );
- trainPopupMI[DO_FLIPTRAIN] = wMenuPushCreate( trainPopupM, "", _("Flip Train"), 0, TrainFunc, (void*)DO_FLIPTRAIN );
- trainPopupMI[DO_MUMASTER] = wMenuPushCreate( trainPopupM, "", _("MU Master"), 0, TrainFunc, (void*)DO_MUMASTER );
- trainPopupMI[DO_CHANGEDIR] = wMenuPushCreate( trainPopupM, "", _("Change Direction"), 0, TrainFunc, (void*)DO_CHANGEDIR );
- trainPopupMI[DO_STOP] = wMenuPushCreate( trainPopupM, "", _("Stop"), 0, TrainFunc, (void*)DO_STOP );
- wMenuSeparatorCreate( trainPopupM );
- trainPopupMI[DO_DELCAR] = wMenuPushCreate( trainPopupM, "", _("Remove Car"), 0, TrainFunc, (void*)DO_DELCAR );
- trainPopupMI[DO_DELTRAIN] = wMenuPushCreate( trainPopupM, "", _("Remove Train"), 0, TrainFunc, (void*)DO_DELTRAIN );
-
-#ifdef LATER
- ParamRegister( &newCarPG );
- ParamCreateControls( &newCarPG, NULL );
- newCarControls[0] = newCarPLs[0].control;
- newCarControls[1] = newCarPLs[1].control;
-#endif
- AddPlaybackProc( "TRAINSTOPGO", (playbackProc_p)TrainStopGoPlayback, NULL );
- AddPlaybackProc( "TRAINPAUSE", (playbackProc_p)TrainTimeDoPause, NULL );
- AddPlaybackProc( "TRAINMOVIE", (playbackProc_p)TrainDoMovie, NULL );
+ log_trainMove = LogFindIndex("trainMove");
+ log_trainPlayback = LogFindIndex("trainPlayback");
+ trainPLs[I_ZERO].winLabel = (char*)wIconCreatePixMap(zero_xpm);
+ ParamRegister(&trainPG);
+ AddMenuButton(menu, CmdTrain, "cmdTrain", _("Train"),
+ wIconCreatePixMap(train_xpm), LEVEL0_50, IC_POPUP2|IC_LCLICK|IC_RCLICK, 0,
+ NULL);
+ stopI = wIconCreatePixMap(ballred);
+ goI = wIconCreatePixMap(ballgreen);
+ trainPauseB = AddToolbarButton("cmdTrainPause", stopI, IC_MODETRAIN_ONLY,
+ CmdTrainStopGo, NULL);
+ AddToolbarButton("cmdTrainExit", wIconCreatePixMap(exit_xpm), IC_MODETRAIN_ONLY,
+ CmdTrainExit, NULL);
+ newcarB = AddToolbarButton("cmdTrainNewCar", wIconCreatePixMap(newcar_xpm),
+ IC_MODETRAIN_ONLY, CarItemLoadList, NULL);
+ T_CAR = InitObject(&carCmds);
+ trainPopupM = MenuRegister("Train Commands");
+ trainPopupMI[DO_UNCOUPLE] = wMenuPushCreate(trainPopupM, "", _("Uncouple"), 0,
+ TrainFunc, (void*)DO_UNCOUPLE);
+ trainPopupMI[DO_FLIPCAR] = wMenuPushCreate(trainPopupM, "", _("Flip Car"), 0,
+ TrainFunc, (void*)DO_FLIPCAR);
+ trainPopupMI[DO_FLIPTRAIN] = wMenuPushCreate(trainPopupM, "", _("Flip Train"),
+ 0, TrainFunc, (void*)DO_FLIPTRAIN);
+ trainPopupMI[DO_MUMASTER] = wMenuPushCreate(trainPopupM, "", _("MU Master"),
+ 0, TrainFunc, (void*)DO_MUMASTER);
+ trainPopupMI[DO_CHANGEDIR] = wMenuPushCreate(trainPopupM, "",
+ _("Change Direction"), 0, TrainFunc, (void*)DO_CHANGEDIR);
+ trainPopupMI[DO_STOP] = wMenuPushCreate(trainPopupM, "", _("Stop"), 0,
+ TrainFunc, (void*)DO_STOP);
+ wMenuSeparatorCreate(trainPopupM);
+ trainPopupMI[DO_DELCAR] = wMenuPushCreate(trainPopupM, "", _("Remove Car"),
+ 0, TrainFunc, (void*)DO_DELCAR);
+ trainPopupMI[DO_DELTRAIN] = wMenuPushCreate(trainPopupM, "",
+ _("Remove Train"), 0, TrainFunc, (void*)DO_DELTRAIN);
+ AddPlaybackProc("TRAINSTOPGO", (playbackProc_p)TrainStopGoPlayback, NULL);
+ AddPlaybackProc("TRAINPAUSE", (playbackProc_p)TrainTimeDoPause, NULL);
+ AddPlaybackProc("TRAINMOVIE", (playbackProc_p)TrainDoMovie, NULL);
}
diff --git a/app/bin/ctrain.h b/app/bin/ctrain.h
index 10f836f..daa083c 100644
--- a/app/bin/ctrain.h
+++ b/app/bin/ctrain.h
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/ctrain.h,v 1.1 2005-12-07 15:46:59 rc-flyer Exp $
+/** \file ctrain.h
+ * Definitions and prototypes for train operations
*/
/* XTrkCad - Model Railroad CAD
@@ -20,6 +20,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef HAVE_CTRAIN_H
+#define HAVE_CTRAIN_H
+
+#include "common.h"
+#include "track.h"
struct carItem_t;
typedef struct carItem_t carItem_t;
@@ -53,3 +58,4 @@ int CarAvailableCount( void );
BOOL_T TraverseTrack2( traverseTrack_p, DIST_T );
void FlipTraverseTrack( traverseTrack_p );
+#endif // !HAVE_CTRAIN_H \ No newline at end of file
diff --git a/app/bin/cturnout.c b/app/bin/cturnout.c
index 55b7a4d..c3125ad 100644
--- a/app/bin/cturnout.c
+++ b/app/bin/cturnout.c
@@ -1,8 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cturnout.c,v 1.8 2009-08-16 13:07:14 m_fischer Exp $
- *
+/** \file cturnout.c
* T_TURNOUT
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -24,14 +21,24 @@
*/
#include <ctype.h>
-#include "track.h"
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
#include "ccurve.h"
-#include "cstraigh.h"
-#include "compound.h"
+#include "tbezier.h"
#include "cjoin.h"
+#include "compound.h"
+#include "cstraigh.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
-
-#include <stdint.h>
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
EXPORT TRKTYP_T T_TURNOUT = -1;
@@ -120,6 +127,8 @@ EXPORT turnoutInfo_t * CreateNewTurnout(
}
to->segCnt = segCnt;
to->segs = (trkSeg_p)memdup( segData, (sizeof *segData) * segCnt );
+ FixUpBezierSegs(to->segs,to->segCnt);
+
GetSegBounds( zero, 0.0, segCnt, to->segs, &to->orig, &to->size );
to->endCnt = endPtCnt;
to->endPt = (trkEndPt_t*)memdup( endPts, (sizeof *endPts) * to->endCnt );
@@ -154,7 +163,7 @@ EXPORT wIndex_t CheckPaths(
PATHPTR_T paths )
{
int pc, ps;
- PATHPTR_T pp;
+ PATHPTR_T pp = 0;
int inx, inx1;
static dynArr_t segMap_da;
int segInx[2], segEp[2];
@@ -663,7 +672,7 @@ static ANGLE_T GetAngleTurnout(
pos.x -= xx->orig.x;
pos.y -= xx->orig.y;
Rotate( &pos, zero, -xx->angle );
- angle = GetAngleSegs( segCnt, xx->segs, pos, &segInx );
+ angle = GetAngleSegs( segCnt, xx->segs, &pos, &segInx, NULL, NULL, NULL, NULL );
return NormalizeAngle( angle+xx->angle );
}
@@ -1202,7 +1211,6 @@ static BOOL_T TraverseTurnout(
coOrd pos0, pos1, pos2;
DIST_T d, dist;
PATHPTR_T path, pathCurr;
- BOOL_T backwards=FALSE;
trkSeg_p segPtr;
EPINX_T ep, epCnt, ep2;
int segInx;
@@ -1222,10 +1230,6 @@ LOG( log_traverseTurnout, 1, ( "TraverseTurnout( T%d, [%0.3f %0.3f] [%0.3f %0.3f
continue;
GetSegInxEP( path[0], &segInx, &segEP );
segPtr = xx->segs+segInx;
-#ifdef LATER
- for ( inx = 0; inx<xx->segCnt; inx++ ) {
- segPtr = xx->segs+inx;
-#endif
segProcData.distance.pos1 = pos0;
SegProc( SEGPROC_DISTANCE, segPtr, &segProcData );
if ( segProcData.distance.dd < d ) {
@@ -1241,46 +1245,63 @@ LOG( log_traverseTurnout, 1, ( "TraverseTurnout( T%d, [%0.3f %0.3f] [%0.3f %0.3f
LOG( log_traverseTurnout, 1, ( " PC=%d ", pathCurr[0] ) )
GetSegInxEP( pathCurr[0], &segInx, &segEP );
segPtr = xx->segs+segInx;
-#ifdef LATER
- for ( pathCurr = xx->pathCurr+strlen((char*)xx->pathCurr)+1; pathCurr[0] || pathCurr[1]; pathCurr++ ) {
- if ( pathCurr[0] == 0 )
- continue;
- if ( Abs(pathCurr[0])-1 == currInx )
- break;
- }
- if ( pathCurr[0] == 0 ) {
- fprintf( stderr, "Open turnout [%d]\n", currInx );
- return FALSE;
- }
- segPtr = xx->segs+currInx;
-#endif
segProcData.traverse1.pos = pos2;
- segProcData.traverse1.angle = xx->angle-trvTrk->angle;
+ segProcData.traverse1.angle = -xx->angle+trvTrk->angle;
SegProc( SEGPROC_TRAVERSE1, segPtr, &segProcData );
dist += segProcData.traverse1.dist;
- backwards = segProcData.traverse1.backwards;
- if ( segEP ) backwards = !backwards;
-LOG( log_traverseTurnout, 2, ( " B%d D%0.3f\n", backwards, dist ) )
-
+ //Get ready for Traverse2 - copy all Traverse1 first
+ BOOL_T backwards = segProcData.traverse1.backwards;
+ BOOL_T segs_backwards = segProcData.traverse1.segs_backwards;
+ BOOL_T neg = segProcData.traverse1.negative;
+ int BezSegInx = segProcData.traverse1.BezSegInx;
+
+ // Backwards means universally we going towards EP=0 on this segment.
+ // But the overall direction we are going can have two types of reversal,
+ // a curve that is flipped is negative (the end points are reversed) which Traverse1 handles,
+ // and a path can also be reversed (negative path number) and will have segEP = 1
+ BOOL_T turnout_backwards = backwards;
+ if (segEP) turnout_backwards = !turnout_backwards; //direction modified if path reversed
+
+LOG( log_traverseTurnout, 2, ( " SI%d TB%d SP%d B%d SB%d N%d BSI%d D%0.3f\n", segInx, turnout_backwards, segEP, backwards, segs_backwards, neg, BezSegInx, dist ) )
while ( *pathCurr ) {
+ //Set up Traverse2
GetSegInxEP( pathCurr[0], &segInx, &segEP );
segPtr = xx->segs+segInx;
- segProcData.traverse2.segDir = (backwards?1-segEP:segEP);
+ segProcData.traverse2.segDir = backwards;
segProcData.traverse2.dist = dist;
+ segProcData.traverse2.BezSegInx = BezSegInx;
+ segProcData.traverse2.segs_backwards = segs_backwards;
SegProc( SEGPROC_TRAVERSE2, segPtr, &segProcData );
if ( segProcData.traverse2.dist <= 0 ) {
*distR = 0;
REORIGIN( trvTrk->pos, segProcData.traverse2.pos, xx->angle, xx->orig );
trvTrk->angle = NormalizeAngle( xx->angle+segProcData.traverse2.angle );
+LOG( log_traverseTurnout, 2, ( " -> [%0.3f %0.3f] A%0.3f D%0.3f\n", trvTrk->pos.x, trvTrk->pos.y, trvTrk->angle, *distR ))
return TRUE;
}
- dist = segProcData.traverse2.dist;
- pathCurr += (backwards?-1:1);
-LOG( log_traverseTurnout, 1, ( " D%0.3f\n", dist ) )
- }
-
- pathCurr += (backwards?1:-1);
- pos1 = MapPathPos( xx, pathCurr[0], (backwards?0:1) );
+ dist = segProcData.traverse2.dist; //Remainder after segment
+ pathCurr += (turnout_backwards?-1:1); //Use master direction for turnout
+ //Redrive Traverse 1 for each segment for Bezier - to pick up backwards elements
+ if (pathCurr[0] == '\0') continue; //
+ //Set up Traverse1 - copy all of Traverse2 values first
+ GetSegInxEP( pathCurr[0], &segInx, &segEP );
+ segPtr = xx->segs+segInx;
+ ANGLE_T angle = segProcData.traverse2.angle;
+ coOrd pos = segProcData.traverse2.pos;
+LOG( log_traverseTurnout, 1, ( " Loop2-1 SI%d SP%d [%0.3f %0.3f] A%0.3f D%0.3f\n", segInx, segEP, pos.x, pos.y, angle, dist ) )
+ segProcData.traverse1.pos = pos;
+ segProcData.traverse1.angle = angle;
+ SegProc( SEGPROC_TRAVERSE1, segPtr, &segProcData );
+ // dist += segProcData.traverse1.dist; //Add distance from end to pos (could be zero or whole length if backwards)
+ backwards = segProcData.traverse1.backwards;
+ segs_backwards = segProcData.traverse1.segs_backwards;
+ neg = segProcData.traverse1.negative;
+ BezSegInx = segProcData.traverse1.BezSegInx;
+LOG( log_traverseTurnout, 1, ( " Loop1-2 B%d SB%d N%d BSI%d D%0.3f\n", backwards, segs_backwards, neg, BezSegInx, dist ) )
+ }
+
+ pathCurr += (turnout_backwards?1:-1);
+ pos1 = MapPathPos( xx, pathCurr[0], (turnout_backwards?0:1) );
*distR = dist;
epCnt = GetTrkEndPtCnt(trk);
ep = 0;
@@ -1354,10 +1375,25 @@ static STATUS_T ModifyTurnout( track_p trk, wAction_t action, coOrd pos )
static BOOL_T GetParamsTurnout( int inx, track_p trk, coOrd pos, trackParams_t * params )
{
- params->type = curveTypeStraight;
- params->ep = PickUnconnectedEndPoint( pos, trk );
+
+
+ params->type = curveTypeStraight; //TODO should check if last segment is actually straight
+ if (inx == PARAMS_CORNU || inx == PARAMS_BEZIER) {
+ params->arcR = 0.0;
+ params->arcP = zero;
+ params->ep = PickEndPoint(pos,trk); //Nearest
+ if (params->ep>=0) {
+ params->angle = GetTrkEndAngle(trk,params->ep);
+ params->track_angle = params->angle + params->ep?0:180;
+ } else {
+ params->angle = params-> track_angle = 0;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ params->ep = PickUnconnectedEndPointSilent( pos, trk );
if (params->ep == -1)
- return FALSE;
+ return FALSE;
params->lineOrig = GetTrkEndPos(trk,params->ep);
params->lineEnd = params->lineOrig;
params->len = 0.0;
@@ -1405,7 +1441,15 @@ static BOOL_T QueryTurnout( track_p trk, int query )
case Q_NOT_PLACE_FROGPOINTS:
case Q_HAS_DESC:
case Q_MODIFY_REDRAW_DONT_UNDRAW_TRACK:
+ case Q_CAN_EXTEND:
return TRUE;
+ case Q_MODIFY_CAN_SPLIT:
+ if (GetTrkEndPtCnt(trk) <= 2) { // allow splitting of simple track und buffers
+ return TRUE ;
+ }
+ else {
+ return FALSE;
+ }
case Q_CAN_PARALLEL:
if( GetTrkEndPtCnt( trk ) == 2 && fabs( GetTrkEndAngle( trk, 0 ) - GetTrkEndAngle( trk, 1 )) == 180.0 )
return TRUE;
@@ -1413,6 +1457,8 @@ static BOOL_T QueryTurnout( track_p trk, int query )
return FALSE;
case Q_CAN_NEXT_POSITION:
return ( GetTrkEndPtCnt(trk) > 2 );
+ case Q_CORNU_CAN_MODIFY:
+ return FALSE;
default:
return FALSE;
}
@@ -1663,7 +1709,7 @@ static void TurnoutChange( long changes )
maxTurnoutDim.x = maxTurnoutDim.y = 0.0;
if (turnoutInfo_da.cnt <= 0)
return;
- curTurnout = TurnoutAdd( LABEL_TABBED|LABEL_MANUF|LABEL_PARTNO|LABEL_DESCR, curScaleInx, turnoutListL, &maxTurnoutDim, -1 );
+ curTurnout = TurnoutAdd( LABEL_TABBED|LABEL_MANUF|LABEL_PARTNO|LABEL_DESCR, GetLayoutCurScale(), turnoutListL, &maxTurnoutDim, -1 );
wListSetIndex( turnoutListL, 0 );
wControlShow( (wControl_p)turnoutListL, TRUE );
if (curTurnout == NULL) {
@@ -1871,6 +1917,9 @@ LOG( log_turnout, 3, ( "placeTurnout T%d (%0.3f %0.3f) A%0.3f\n",
}
}
}
+ } else {
+ trk = NULL;
+ *trkR = NULL;
}
*connCntR = connCnt;
*maxDR = maxD;
@@ -1975,14 +2024,6 @@ static void AddTurnout( void )
curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlack );
UndoStart( _("Place New Turnout"), "addTurnout" );
titleLen = strlen( curTurnout->title );
-#ifdef LATER
- newTrk = NewTrack( 0, T_TURNOUT, curTurnout->endCnt, sizeof (*xx) + 1 );
- xx = GetTrkExtraData(newTrk);
- xx->orig = Dto.pos;
- xx->angle = Dto.angle;
- xx->customInfo = curTurnout->customInfo;
- xx->segs = MyMalloc( (curTurnout->segCnt)*sizeof curTurnout->segs[0] );
-#endif
DYNARR_SET( trkEndPt_t, tempEndPts_da, curTurnout->endCnt );
DYNARR_SET( junk_t, connection_da, curTurnout->endCnt );
@@ -2078,23 +2119,13 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n",
xx->customInfo = curTurnout->customInfo;
if (connection((int)curTurnoutEp).trk) {
CopyAttributes( connection((int)curTurnoutEp).trk, newTrk );
- SetTrkScale( newTrk, curScaleInx );
+ SetTrkScale( newTrk, GetLayoutCurScale());
}
xx->special = curTurnout->special;
xx->u = curTurnout->u;
-#ifdef LATER
- xx->segCnt = curTurnout->segCnt;
- memcpy( xx->segs, curTurnout->segs, xx->segCnt * sizeof *(trkSeg_p)0 );
- xx->title = curTurnout->title;
- xx->paths = xx->pathCurr = curTurnout->paths;
- xx->pathLen = curTurnout->pathLen;
-#endif
/* Make the connections */
-#ifdef LATER
- for (i=0; i<curTurnout->endCnt; i++)
- SetTrkEndPoint( newTrk, i, tempEndPts(i).pos, tempEndPts(i).angle );
-#endif
+
visible = FALSE;
noConnections = TRUE;
AuditTracks( "addTurnout T%d before connection", GetTrkIndex(newTrk) );
@@ -2102,6 +2133,9 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n",
if ( connection(i).trk != NULL ) {
p0 = GetTrkEndPos( newTrk, i );
p1 = GetTrkEndPos( connection(i).trk, connection(i).ep );
+ ANGLE_T a0 = GetTrkEndAngle( newTrk, i);
+ ANGLE_T a1 = GetTrkEndAngle( connection(i).trk, connection(i).ep );
+ ANGLE_T a = NormalizeAngle(a1-a0+180);
d = FindDistance( p0, p1 );
if ( d < connectDistance ) {
noConnections = FALSE;
@@ -2481,7 +2515,7 @@ EXPORT void AddHotBarTurnouts( void )
to = turnoutInfo(inx);
if ( !( IsParamValid(to->paramFileIndex) &&
to->segCnt > 0 &&
- CompatibleScale( TRUE, to->scaleInx, curScaleInx ) ) )
+ CompatibleScale( TRUE, to->scaleInx, GetLayoutCurScale()) ) )
continue;
AddHotBarElement( to->contentsLabel, to->size, to->orig, TRUE, to->barScale, to, CmdTurnoutHotBarProc );
}
diff --git a/app/bin/cturntbl.c b/app/bin/cturntbl.c
index 31f33ed..9264572 100644
--- a/app/bin/cturntbl.c
+++ b/app/bin/cturntbl.c
@@ -1,8 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cturntbl.c,v 1.4 2008-03-06 19:35:06 m_fischer Exp $
- *
+/** \file cturntbl.c
* TURNTABLE
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -23,9 +20,17 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <math.h>
+#include <string.h>
+
#include "cstraigh.h"
+#include "cundo.h"
+#include "fileio.h"
#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
static TRKTYP_T T_TURNTABLE = -1;
@@ -233,7 +238,7 @@ static struct {
coOrd orig;
DIST_T diameter;
long epCnt;
- LAYER_T layerNumber;
+ unsigned int layerNumber;
} trntblData;
typedef enum { OR, RA, EC, LY } trntblDesc_e;
static descData_t trntblDesc[] = {
@@ -584,6 +589,26 @@ static STATUS_T ModifyTurntable( track_p trk, wAction_t action, coOrd pos )
return C_ERROR;
}
+EXPORT BOOL_T ConnectTurntableTracks(
+ track_p trk1,
+ EPINX_T ep1,
+ track_p trk2,
+ EPINX_T ep2 ) {
+ coOrd center, pos;
+ DIST_T radius;
+ TurntableGetCenter( trk1, &center, &radius );
+ pos = GetTrkEndPos(trk2,ep2);
+ ANGLE_T angle = FindAngle(center, GetTrkEndPos(trk2,ep2));
+ if (NormalizeAngle(GetTrkEndAngle(trk2,ep2) + 180 - angle) < connectAngle) {
+ if (FindDistance(center,pos)-radius < connectDistance) {
+ EPINX_T ep = NewTurntableEndPt(trk1,angle);
+ ConnectTracks( trk1, ep, trk2, ep2 );
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
static BOOL_T GetParamsTurntable( int inx, track_p trk, coOrd pos, trackParams_t * params )
{
@@ -604,6 +629,8 @@ static BOOL_T GetParamsTurntable( int inx, track_p trk, coOrd pos, trackParams_t
params->lineEnd = params->lineOrig;
params->len = 0.0;
params->arcR = 0.0;
+ params->ttcenter = center; //Turntable
+ params->ttradius = radius; //Turntable
return TRUE;
}
@@ -623,11 +650,27 @@ static BOOL_T MoveEndPtTurntable( track_p *trk, EPINX_T *ep, coOrd pos, DIST_T d
d -= d0;
Translate( &pos, pos, angle0+180, d0 );
}
- if (d < r) {
+ if (small((r-d)/2)) {
+ Translate( &pos, posCen, angle0+180, r); //Make radius equal if close
+ } else if (d < r) {
ErrorMessage( MSG_POINT_INSIDE_TURNTABLE );
return FALSE;
}
- *ep = NewTurntableEndPt( *trk, angle0 );
+ //Look for empty slot
+ BOOL_T found = FALSE;
+ for (*ep=0; *ep<GetTrkEndPtCnt(*trk); *ep=*ep+1) {
+ if ( (GetTrkEndTrk(*trk,*ep)) == NULL )
+ found = TRUE;
+ break;
+ }
+ if (!found)
+ *ep = NewTurntableEndPt(*trk,angle0);
+ else {
+ struct extraData *xx = GetTrkExtraData(*trk);
+ coOrd pos1;
+ PointOnCircle( &pos1, xx->pos, xx->radius, angle0 );
+ SetTrkEndPoint(*trk, *ep, pos1, angle0); //Reuse
+ }
if ((d-r) > connectDistance) {
trk1 = NewStraightTrack( GetTrkEndPos(*trk,*ep), pos );
CopyAttributes( *trk, trk1 );
@@ -650,7 +693,12 @@ static BOOL_T QueryTurntable( track_p trk, int query )
case Q_ISTRACK:
case Q_NOT_PLACE_FROGPOINTS:
case Q_MODIFY_REDRAW_DONT_UNDRAW_TRACK:
+ case Q_CAN_ADD_ENDPOINTS:
+ case Q_CAN_EXTEND:
return TRUE;
+ case Q_MODIFY_CAN_SPLIT:
+ case Q_CORNU_CAN_MODIFY:
+ return FALSE;
default:
return FALSE;
}
diff --git a/app/bin/cundo.c b/app/bin/cundo.c
index 13d7af0..e27ee75 100644
--- a/app/bin/cundo.c
+++ b/app/bin/cundo.c
@@ -24,9 +24,18 @@
#include <time.h>
#include <stdarg.h>
#include <errno.h>
+#include <string.h>
+
+#include "cselect.h"
+#include "custom.h"
+#include "fileio.h"
+#include "i18n.h"
+#include "messages.h"
+#include "paths.h"
#include "track.h"
#include "trackx.h"
-#include "i18n.h"
+#include "cundo.h"
+
/*****************************************************************************
*
@@ -148,10 +157,11 @@ static BOOL_T UndoFail( char * cause, long val, char * fileName, int lineNumber
undoStack_p us;
FILE * outf;
time_t clock;
- char temp[STR_SIZE];
+ char *temp;
NoticeMessage( MSG_UNDO_ASSERT, _("Ok"), NULL, fileName, lineNumber, val, val, cause );
- sprintf( temp, "%s%s%s", workingDir, FILE_SEP_CHAR, sUndoF );
+ MakeFullpath(&temp, workingDir, sUndoF, NULL);
outf = fopen( temp, "a+" );
+ free(temp);
if ( outf == NULL ) {
NoticeMessage( MSG_OPEN_FAIL, _("Ok"), NULL, _("Undo Trace"), temp, strerror(errno) );
return FALSE;
@@ -361,6 +371,7 @@ static BOOL_T ReadObject( stream_p stream, BOOL_T needRedo )
tempTrk.extraData = trk->extraData;
if (!ReadStream( stream, tempTrk.extraData, tempTrk.extraSize ))
return FALSE;
+ RebuildTrackSegs(&tempTrk); //If we had an array of Segs - recreate it
if (recordUndo) Rprintf( "Restore T%D(%d) @ %lx\n", trk->index, tempTrk.index, (long)trk );
tempTrk.index = trk->index;
tempTrk.next = trk->next;
diff --git a/app/bin/cundo.h b/app/bin/cundo.h
index ef767ae..89beab3 100644
--- a/app/bin/cundo.h
+++ b/app/bin/cundo.h
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cundo.h,v 1.1 2005-12-07 15:46:54 rc-flyer Exp $
+/** \file cundo.h
+ * Function prototypes for undo functionality
*/
/* XTrkCad - Model Railroad CAD
@@ -20,6 +20,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef HAVE_CUNDO_H
+#define HAVE_CUNDO_H
+
+#include "common.h"
+#include "track.h"
+
int UndoUndo( void );
int UndoRedo( void );
void UndoResume( void );
@@ -30,3 +36,5 @@ BOOL_T UndoDelete( track_p );
BOOL_T UndoNew( track_p );
void UndoEnd( void );
void UndoClear( void );
+
+#endif // !HAVE_CUNDO_H
diff --git a/app/bin/custom.c b/app/bin/custom.c
index 766dbd8..618a8ac 100644
--- a/app/bin/custom.c
+++ b/app/bin/custom.c
@@ -1,6 +1,6 @@
#define RENAME_H
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/custom.c,v 1.14 2010-01-01 13:24:59 m_fischer Exp $
+/** \file custom.c
+ *
*/
/* XTrkCad - Model Railroad CAD
@@ -40,13 +40,14 @@
#include <stdarg.h>
#include <errno.h>
-#include "track.h"
-#include "version.h"
+#include "cjoin.h"
#include "common.h"
-#include "misc.h"
+#include "custom.h"
#include "fileio.h"
-#include "cjoin.h"
#include "i18n.h"
+#include "misc.h"
+#include "track.h"
+#include "version.h"
#define Product "XTrackCAD"
#define product "xtrkcad"
@@ -73,6 +74,7 @@ char * sClipboardF = product ".clp";
char * sParamQF = product "." KEYCODE "tq";
char * sUndoF = product ".und";
char * sAuditF = product ".aud";
+char * sTipF = product ".tip";
char * sSourceFilePattern = NULL;
char * sImportFilePattern = NULL;
@@ -126,8 +128,10 @@ void DoStructDesignerRedir( void )
BOOL_T Initialize( void )
{
InitTrkCurve();
+ InitTrkBezier();
InitTrkStraight();
InitTrkEase();
+ InitTrkCornu();
InitTrkTurnout();
InitTrkTurntable();
InitTrkStruct();
diff --git a/app/bin/custom.h b/app/bin/custom.h
index b8ab213..a4d335a 100644
--- a/app/bin/custom.h
+++ b/app/bin/custom.h
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/custom.h,v 1.7 2010-01-01 13:24:59 m_fischer Exp $
+/** \file custom.h
+ *
*/
/* XTrkCad - Model Railroad CAD
@@ -23,6 +23,9 @@
#ifndef CUSTOM_H
#define CUSTOM_H
+#include "wlib.h"
+#include "misc.h"
+
#define ICON_WIDTH (64)
#define ICON_HEIGHT (64)
@@ -82,12 +85,13 @@ void InitCustom( void );
void CleanupCustom( void );
void InitTrkCurve( void );
+void InitTrkBezier( void );
void InitTrkDraw( void );
void InitTrkEase( void );
+void InitTrkCornu( void );
void InitTrkNote( void );
void InitTrkStraight( void );
void InitTrkStruct( void );
-void InitTrkTableEdge( void );
void InitTrkText( void );
void InitTrkTrack( void );
void InitTrkTurnout( void );
@@ -105,13 +109,13 @@ void InitCmdElevation( wMenu_p menu );
void InitCmdJoin( wMenu_p menu );
void InitCmdProfile( wMenu_p menu );
void InitCmdPull( wMenu_p menu );
-void InitCmdTighten( void );
void InitCmdModify( wMenu_p menu );
void InitCmdMove( wMenu_p menu );
void InitCmdMoveDescription( wMenu_p menu );
void InitCmdStraight( wMenu_p menu );
void InitCmdDescribe( wMenu_p menu );
void InitCmdSelect( wMenu_p menu );
+void InitCmdPan( wMenu_p menu);
void InitCmdDelete( void );
void InitCmdSplit( wMenu_p menu );
void InitCmdTunnel( void );
@@ -119,7 +123,6 @@ void InitCmdRuler( wMenu_p menu );
void InitCmdParallel( wMenu_p menu );
wIndex_t InitCmdPrint( wMenu_p menu );
-void InitCmdTableEdge( void );
void InitCmdText( wMenu_p menu );
void InitCmdTrain( wMenu_p menu );
void InitCmdTurnout( wMenu_p menu );
@@ -135,7 +138,6 @@ void InitCmdEasement( void );
char * MakeWindowTitle( char * );
addButtonCallBack_t EasementInit( void );
-addButtonCallBack_t StructDesignerInit( void );
void InitLayers( void );
void InitHotBar( void );
@@ -144,7 +146,7 @@ BOOL_T Initialize( void );
void DoEasementRedir( void );
void DoStructDesignerRedir( void );
void InitNewTurnRedir( wMenu_p );
-void RedrawAbout( wDraw_p, void *, wPos_t, wPos_t );
-void DoKeycheck( char * );
+
+void InitAppDefaults(void);
#endif
diff --git a/app/bin/dbench.c b/app/bin/dbench.c
index 4a32360..7e44713 100644
--- a/app/bin/dbench.c
+++ b/app/bin/dbench.c
@@ -20,9 +20,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
-#include "i18n.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include "i18n.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
/*****************************************************************************
*
diff --git a/app/bin/dbitmap.c b/app/bin/dbitmap.c
index 1c9c304..340bad1 100644
--- a/app/bin/dbitmap.c
+++ b/app/bin/dbitmap.c
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/dbitmap.c,v 1.3 2008-02-14 19:49:19 m_fischer Exp $
+/** \file dbitmap.c
+ * Print to Bitmap
*/
/* XTrkCad - Model Railroad CAD
@@ -20,14 +20,17 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <assert.h>
+
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "paths.h"
+#include "track.h"
-/*****************************************************************************
- *
- * Print to Bitmap
- *
- */
static long outputBitMapTogglesV = 3;
static double outputBitMapDensity = 10;
@@ -87,14 +90,14 @@ static int SaveBitmapFile(
if (outputBitMapTogglesV&1) {
fp = wStandardFont( F_TIMES, FALSE, FALSE );
fs = 18;
- DrawTextSize( &mainD, Title1, fp, fs, FALSE, &textsize );
+ DrawTextSize( &mainD, GetLayoutTitle(), fp, fs, FALSE, &textsize );
p[0].x = (bitmap_d.size.x - (textsize.x*bitmap_d.scale))/2.0 + bitmap_d.orig.x;
p[0].y = mapD.size.y + (y1+0.30)*bitmap_d.scale;
- DrawString( &bitmap_d, p[0], 0.0, Title1, fp, fs*bitmap_d.scale, wDrawColorBlack );
- DrawTextSize( &mainD, Title2, fp, fs, FALSE, &textsize );
+ DrawString( &bitmap_d, p[0], 0.0, GetLayoutTitle(), fp, fs*bitmap_d.scale, wDrawColorBlack );
+ DrawTextSize( &mainD, GetLayoutSubtitle(), fp, fs, FALSE, &textsize );
p[0].x = (bitmap_d.size.x - (textsize.x*bitmap_d.scale))/2.0 + bitmap_d.orig.x;
p[0].y = mapD.size.y + (y1+0.05)*bitmap_d.scale;
- DrawString( &bitmap_d, p[0], 0.0, Title2, fp, fs*bitmap_d.scale, wDrawColorBlack );
+ DrawString( &bitmap_d, p[0], 0.0, GetLayoutSubtitle(), fp, fs*bitmap_d.scale, wDrawColorBlack );
fp_bi = wStandardFont( F_TIMES, TRUE, TRUE );
DrawTextSize( &mainD, _("Drawn with "), fp, fs, FALSE, &textsize );
DrawTextSize( &mainD, sProdName, fp_bi, fs, FALSE, &textsize1 );
@@ -214,7 +217,7 @@ static void OutputBitMapOk( void * junk )
_("Bitmap files|*.xpm"),
#endif
SaveBitmapFile, NULL );
- wFilSelect( bitmap_fs, curDirName );
+ wFilSelect( bitmap_fs, GetCurrentPath( BITMAPPATHKEY ));
}
diff --git a/app/bin/dcar.c b/app/bin/dcar.c
index c64582f..9236f1b 100644
--- a/app/bin/dcar.c
+++ b/app/bin/dcar.c
@@ -1,6 +1,5 @@
/** \file dcar.c
* TRAIN
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -24,14 +23,23 @@
#ifndef WINDOWS
#include <errno.h>
#endif
+#include <assert.h>
#include <ctype.h>
-
+#include <math.h>
#include <stdint.h>
+#include <string.h>
-#include "track.h"
+#include "cselect.h"
#include "ctrain.h"
-#include "i18n.h"
+#include "custom.h"
#include "fileio.h"
+#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "paths.h"
+#include "track.h"
+#include "utility.h"
static int log_carList;
static int log_carInvList;
@@ -626,6 +634,8 @@ static carProto_p CarProtoNew(
proto->type = type;
proto->dim = *dim;
proto->segCnt = segCnt;
+ //if (proto->segPtr) Can't do this because segPtr could be static
+ // free(proto->segPtr);
proto->segPtr = (trkSeg_p)memdup( segPtr, (sizeof *(trkSeg_p)0) * proto->segCnt );
CloneFilledDraw( proto->segCnt, proto->segPtr, FALSE );
GetSegBounds( zero, 0.0, proto->segCnt, proto->segPtr, &proto->orig, &proto->size );
@@ -660,6 +670,8 @@ static BOOL_T CarProtoRead(
if ( !ReadSegs() )
return FALSE;
CarProtoNew( NULL, curParamFileIndex, desc, options, type, &dim, tempSegs_da.cnt, &tempSegs(0) );
+ FreeFilledDraw(tempSegs_da.cnt,&tempSegs(0));
+ MyFree(desc);
return TRUE;
}
@@ -1255,7 +1267,7 @@ static BOOL_T CarItemWrite(
item->data.purchPrice, item->data.currPrice, item->data.condition, item->data.purchDate, item->data.serviceDate )>0;
if ( ( options&CAR_ITEM_ONLAYOUT) ) {
CarGetPos( item->car, &pos, &angle );
- rc &= fprintf( f, " %d %d %0.3f %0.3f %0.3f",
+ rc &= fprintf( f, " %d %u %0.3f %0.3f %0.3f",
GetTrkIndex(item->car), GetTrkLayer(item->car), pos.x, pos.y, angle )>0;
}
rc &= fprintf( f, "\n" )>0;
@@ -1614,7 +1626,7 @@ EXPORT int CarAvailableCount( void )
carItem_t * item;
for ( inx=0; inx < carItemHotbar_da.cnt; inx ++ ) {
item = carItemHotbar(inx);
- if ( item->scaleInx != curScaleInx )
+ if ( item->scaleInx != GetLayoutCurScale())
continue;
cnt++;
}
@@ -1636,7 +1648,7 @@ EXPORT void AddHotBarCarDesc( void )
item1 = carItemHotbar(inx);
if ( item1->car && !IsTrackDeleted(item1->car) )
continue;
- if ( item1->scaleInx != curScaleInx )
+ if ( item1->scaleInx != GetLayoutCurScale())
continue;
if ( (carHotbarModes[carHotbarModeInx]&0xF000)!=0 || ( item0 == NULL || Cmp_carHotbar( &item0, &item1 ) != 0 ) ) {
#ifdef DESCFIX
@@ -3811,7 +3823,7 @@ LOG( log_carDlgState, 3, ( "CarDlgOk()\n" ) )
sprintf( message+strlen(message), "%s: %s %s %s %s %s %s",
(partP?_(" and Part"):""),
carDlgManufStr, carDlgPartnoStr, carDlgProtoStr, carDlgDescStr,
- (carDlgRepmarkStr?carDlgRepmarkStr:carDlgRoadnameStr), carDlgNumberStr );
+ (carDlgRepmarkStr[ 0 ]?carDlgRepmarkStr:carDlgRoadnameStr), carDlgNumberStr );
carDlgQuantity = 1;
ParamLoadControl( &carDlgPG, I_CD_QTY );
@@ -3836,7 +3848,7 @@ LOG( log_carDlgState, 3, ( "CarDlgOk()\n" ) )
RestoreLocale(oldLocale);
}
reloadRoadnameList = TRUE;
- sprintf( message, _("%s Part: %s %s %s %s %s %s"), carDlgUpdatePartPtr==NULL?_("Added new"):_("Updated"), carDlgManufStr, carDlgPartnoStr, carDlgProtoStr, carDlgDescStr, carDlgRepmarkStr?carDlgRepmarkStr:carDlgRoadnameStr, carDlgNumberStr );
+ sprintf( message, _("%s Part: %s %s %s %s %s %s"), carDlgUpdatePartPtr==NULL?_("Added new"):_("Updated"), carDlgManufStr, carDlgPartnoStr, carDlgProtoStr, carDlgDescStr, carDlgRepmarkStr[ 0 ]?carDlgRepmarkStr:carDlgRoadnameStr, carDlgNumberStr );
} else if ( S_PROTO ) {
if ( carDlgUpdateProtoPtr==NULL ) {
@@ -3876,7 +3888,7 @@ LOG( log_carDlgState, 3, ( "CarDlgOk()\n" ) )
if ( carDlgUpdateItemPtr==NULL ) {
if ( partP ) {
TabStringExtract( title, 7, tabs );
- if ( CarDlgLoadLists( TRUE, tabs, curScaleInx ) )
+ if ( CarDlgLoadLists( TRUE, tabs, GetLayoutCurScale()) )
currState = S_ItemSel;
else
currState = S_ItemEnter;
@@ -4003,7 +4015,7 @@ static void DoCarPartDlg( carDlgAction_e *actions )
CarDlgLoadRoadnameList();
carProtoSegCnt = 0;
carProtoSegPtr = NULL;
- carDlgScaleInx = curScaleInx;
+ carDlgScaleInx = GetLayoutCurScale();
carDlgFlipToggle = FALSE;
carDlgChanged = 0;
@@ -4135,12 +4147,13 @@ static void CarInvDlgFind( void * junk )
if ( item == NULL || item->car == NULL || IsTrackDeleted(item->car) ) return;
CarGetPos( item->car, &pos, &angle );
CarSetVisible( item->car );
- DrawMapBoundingBox( FALSE );
+ //DrawMapBoundingBox( FALSE );
mainCenter = pos;
mainD.orig.x = pos.x-mainD.size.x/2;;
mainD.orig.y = pos.y-mainD.size.y/2;;
MainRedraw();
- DrawMapBoundingBox( TRUE );
+ MapRedraw();
+ //DrawMapBoundingBox( TRUE );
}
@@ -4345,7 +4358,7 @@ static void CarInvDlgSaveText( void )
if ( carInvSaveText_fs == NULL )
carInvSaveText_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("List Cars"),
"Text|*.txt", CarInvSaveText, NULL );
- wFilSelect( carInvSaveText_fs, curDirName );
+ wFilSelect( carInvSaveText_fs, GetCurrentPath(CARSPATHKEY));
}
@@ -4630,7 +4643,7 @@ static void CarInvDlgImportCsv( void )
if ( carInvImportCsv_fs == NULL )
carInvImportCsv_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Import Cars"),
_("Comma-Separated-Values|*.csv"), CarInvImportCsv, NULL );
- wFilSelect( carInvImportCsv_fs, curDirName );
+ wFilSelect( carInvImportCsv_fs, GetCurrentPath(CARSPATHKEY));
}
@@ -4752,7 +4765,7 @@ static void CarInvDlgExportCsv( void )
if ( carInvExportCsv_fs == NULL )
carInvExportCsv_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("Export Cars"),
_("Comma-Separated-Values|*.csv"), CarInvExportCsv, NULL );
- wFilSelect( carInvExportCsv_fs, curDirName );
+ wFilSelect( carInvExportCsv_fs, GetCurrentPath(CARSPATHKEY));
}
diff --git a/app/bin/dcmpnd.c b/app/bin/dcmpnd.c
index 2cff06c..8b92e41 100644
--- a/app/bin/dcmpnd.c
+++ b/app/bin/dcmpnd.c
@@ -1,6 +1,5 @@
/* \file dcmpnd.c
* Compound tracks: Turnouts and Structures
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -22,11 +21,18 @@
*/
#include <ctype.h>
-#include "track.h"
+#include <string.h>
+
#include "compound.h"
-#include "shrtpath.h"
+#include "cundo.h"
+#include "custom.h"
+#include "fileio.h"
#include "i18n.h"
-
+#include "messages.h"
+#include "param.h"
+#include "shrtpath.h"
+#include "track.h"
+#include "utility.h"
/*****************************************************************************
*
diff --git a/app/bin/dcontmgm.c b/app/bin/dcontmgm.c
index 45fec89..e9e929f 100644
--- a/app/bin/dcontmgm.c
+++ b/app/bin/dcontmgm.c
@@ -60,11 +60,8 @@
static const char rcsid[] = "@(#) : $Id$";
-
-
-#include "track.h"
#include <errno.h>
-#include "i18n.h"
+#include <math.h>
#ifdef WINDOWS
#include <io.h>
@@ -73,6 +70,14 @@ static const char rcsid[] = "@(#) : $Id$";
#define access _access
#endif
+#include "cundo.h"
+#include "custom.h"
+#include "i18n.h"
+#include "param.h"
+#include "track.h"
+#include "wlib.h"
+
+
/*****************************************************************************
*
* Control List Management
diff --git a/app/bin/dcustmgm.c b/app/bin/dcustmgm.c
index 86f86b1..ce6bdeb 100644
--- a/app/bin/dcustmgm.c
+++ b/app/bin/dcustmgm.c
@@ -1,5 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/dcustmgm.c,v 1.4 2009-07-30 16:58:42 m_fischer Exp $
+/** \file dcustmgm.c
+ * Custom List Management
*/
/* XTrkCad - Model Railroad CAD
@@ -20,22 +20,27 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <assert.h>
#include <errno.h>
-#include "i18n.h"
+#include <string.h>
#ifdef WINDOWS
#include <io.h>
#define F_OK (0)
#define W_OK (2)
#define access _access
+#else
+#include <unistd.h>
#endif
-/*****************************************************************************
- *
- * Custom List Management
- *
- */
+#include "custom.h"
+#include "fileio.h"
+#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "paths.h"
+#include "track.h"
+#include "wlib.h"
static void CustomEdit( void * action );
static void CustomDelete( void * action );
@@ -241,7 +246,7 @@ static void CustomExport( void * junk )
if ( customMgmExport_fs == NULL )
customMgmExport_fs = wFilSelCreate( mainW, FS_UPDATE, 0, _("Move To XTP"),
_("Parameter File|*.xtp"), CustomDoExport, NULL );
- wFilSelect( customMgmExport_fs, curDirName );
+ wFilSelect( customMgmExport_fs, GetCurrentPath(CUSTOMPATHKEY));
}
diff --git a/app/bin/dease.c b/app/bin/dease.c
index 9b07129..7841857 100644
--- a/app/bin/dease.c
+++ b/app/bin/dease.c
@@ -1,8 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/dease.c,v 1.3 2008-03-06 19:35:08 m_fischer Exp $
- *
+/** \file dease.c
* Easement Button Hdlrs
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -23,12 +20,15 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <math.h>
-#include "track.h"
#include "ccurve.h"
-#include "cstraigh.h"
#include "cjoin.h"
+#include "cstraigh.h"
+#include "custom.h"
#include "i18n.h"
+#include "param.h"
+#include "track.h"
static wButton_p easementB;
@@ -42,11 +42,13 @@ static DIST_T oldEasementVal;
static wIcon_p enone_bm;
static wIcon_p esharp_bm;
static wIcon_p egtsharp_bm;
+static wIcon_p eltsharp_bm;
static wIcon_p enormal_bm;
static wIcon_p eltbroad_bm;
static wIcon_p ebroad_bm;
static wIcon_p egtbroad_bm;
-
+static wIcon_p ecornu_bm;
+
/****************************************
*
* EASEMENTW
@@ -60,14 +62,14 @@ static void SetEasement( DIST_T, void * );
static void EasementOk( void );
static void EasementCancel( void );
-static char *easementChoiceLabels[] = { N_("None"), N_("Sharp"), N_("Normal"), N_("Broad"), NULL };
-static paramFloatRange_t r0o5_2 = { 0.5, 2.0, 60 };
+static char *easementChoiceLabels[] = { N_("None"), N_("Sharp"), N_("Normal"), N_("Broad"), N_("Cornu"), NULL };
+static paramFloatRange_t r0n1_100 = { -1.0, 100.0, 60 };
static paramFloatRange_t r0_100 = { 0.0, 100.0, 60 };
static paramFloatRange_t r0_10 = { 0.0, 10.0, 60 };
static long easeM;
static paramData_t easementPLs[] = {
#define I_EASEVAL (0)
- { PD_FLOAT, &easementVal, "val", PDO_NOPSHUPD, &r0o5_2, N_("Value") },
+ { PD_FLOAT, &easementVal, "val", PDO_NOPSHUPD, &r0n1_100, N_("Value") },
{ PD_FLOAT, &easeR, "r", PDO_DIM|PDO_DLGRESETMARGIN, &r0_100, N_("R"), BO_READONLY },
{ PD_FLOAT, &easeX, "x", PDO_DIM|PDO_DLGHORZ, &r0_10, N_("X"), BO_READONLY },
{ PD_FLOAT, &easeL, "l", PDO_DIM|PDO_DLGHORZ, &r0_100, N_("L"), BO_READONLY },
@@ -87,42 +89,57 @@ static void SetEasement(
long selVal = -1;
wIcon_p bm;
- if (val == 0.0) {
+ if (val < 0.0) {
easeX = easeR = easeL = 0.0;
- selVal = 0;
- bm = enone_bm;
- } else if (val <= 1.0) {
- z = 1.0/val - 1.0;
- easeR = Rvalues[1] - z * (Rvalues[1] - Rvalues[0]);
- easeL = Lvalues[1] - z * (Lvalues[1] - Lvalues[0]);
- if (easeR != 0.0)
- easeX = easeL*easeL/(24*easeR);
- else
- easeX = 0.0;
- if (val == 1.0) {
- selVal = 2;
- bm = enormal_bm;
- } else if (val == 0.5) {
- selVal = 1;
- bm = esharp_bm;
- } else {
- bm = egtsharp_bm;
- }
+ selVal = 4;
+ val = -1;
+ bm = ecornu_bm;
} else {
- z = val - 1.0;
- easeR = Rvalues[1] + z * (Rvalues[2] - Rvalues[1]);
- easeL = Lvalues[1] + z * (Lvalues[2] - Lvalues[1]);
- if (easeR != 0.0)
- easeX = easeL*easeL/(24*easeR);
- else
- easeX = 0.0;
- if (val == 2.0) {
- selVal = 3;
- bm = ebroad_bm;
- } else if (val < 2.0) {
- bm = eltbroad_bm;
+ if (val == 0.0) {
+ easeX = easeR = easeL = 0.0;
+ selVal = 0;
+ val = 0;
+ bm = enone_bm;
+ } else if (val <= 1.0) {
+ if (val < 0.21) val = 0.21; //Eliminate values that give negative radii
+ z = 1.0/val - 1.0;
+ easeR = Rvalues[1] - z * (Rvalues[1] - Rvalues[0]);
+ easeL = Lvalues[1] - z * (Lvalues[1] - Lvalues[0]);
+ if (easeR != 0.0)
+ easeX = easeL*easeL/(24*easeR);
+ else
+ easeX = 0.0;
+ if (val == 1.0) {
+ selVal = 2;
+ bm = enormal_bm;
+ } else if (val == 0.5) {
+ selVal = 1;
+ bm = esharp_bm;
+ } else if (val < 0.5) {
+ bm = eltsharp_bm;
+ selVal = 1;
+ } else {
+ selVal = 1;
+ bm = egtsharp_bm;
+ }
} else {
- bm = egtbroad_bm;
+ z = val - 1.0;