diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2018-03-19 19:55:58 +0100 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2018-03-19 19:55:58 +0100 |
commit | d1a8285f818eb7e5c3d6a05709ea21a808490b8c (patch) | |
tree | 326578f0505cbed07cfe60de530022822dc237ac | |
parent | 16e9630b79f0a7a90c6cedb6781175bb8b337dc1 (diff) |
New upstream version 5.1.0upstream/5.1.0
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],¶ms)) 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, ¬eTextData } }; + { PD_TEXT, NULL, "text", PDO_DLGRESIZE, ¬eTextData } +}; 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( ¬ePG, 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(¬ePG, 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"), ¬eData.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"), ¬eData.pos }, + /*LY*/ { DESC_LAYER, N_("Layer"), ¬eData.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( ¬ePG ); - AddMenuButton( menu, CmdNote, "cmdNote", _("Note"), wIconCreatePixMap(cnote_xpm), LEVEL0_50, IC_POPUP2, ACCL_NOTE, NULL ); + ParamRegister(¬ePG); + 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( ¬eCmds ); + note_bm = wDrawBitMapCreate(mainD.d, note_width, note_width, 8, 8, note_bits); + T_NOTE = InitObject(¬eCmds); } 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],¶ms); + 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],¶ms); + 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, ¢er, &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; |