diff options
Diffstat (limited to 'app')
506 files changed, 126824 insertions, 65858 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 5791fa2..72ca170 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,7 +1,9 @@ + # "bin/i18n.h" is widely used INCLUDE_DIRECTORIES(bin) include_directories(dynstring) include_directories(cornu) +include_directories(libzip) # Setup the rest of the build ... add_subdirectory(dynstring) @@ -15,5 +17,4 @@ ADD_SUBDIRECTORY(cornu) IF(XTRKCAD_USE_GETTEXT) ADD_SUBDIRECTORY(i18n) -ENDIF(XTRKCAD_USE_GETTEXT) - +ENDIF(XTRKCAD_USE_GETTEXT)
\ No newline at end of file diff --git a/app/bin/CMakeLists.txt b/app/bin/CMakeLists.txt index 74b1bc8..2dea1bc 100644 --- a/app/bin/CMakeLists.txt +++ b/app/bin/CMakeLists.txt @@ -1,5 +1,6 @@ +include( CheckSymbolExists ) + ADD_EXECUTABLE(cnvdsgn cnvdsgn.c utility.c) -GET_TARGET_PROPERTY(cnvdsgn_EXE cnvdsgn LOCATION) IF(NOT WIN32) TARGET_LINK_LIBRARIES(cnvdsgn m) ENDIF(NOT WIN32) @@ -8,7 +9,7 @@ MACRO(GENERATE_LIN lin_name) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${lin_name}.lin DEPENDS cnvdsgn ${CMAKE_CURRENT_SOURCE_DIR}/${lin_name}.src - COMMAND ${cnvdsgn_EXE} < ${CMAKE_CURRENT_SOURCE_DIR}/${lin_name}.src > ${CMAKE_CURRENT_BINARY_DIR}/${lin_name}.lin + COMMAND cnvdsgn < ${CMAKE_CURRENT_SOURCE_DIR}/${lin_name}.src > ${CMAKE_CURRENT_BINARY_DIR}/${lin_name}.lin ) ENDMACRO(GENERATE_LIN) @@ -24,6 +25,9 @@ GENERATE_LIN(tosslip) GENERATE_LIN(tostrsct) GENERATE_LIN(towye) GENERATE_LIN(toxing) +GENERATE_LIN(tocornu) +GENERATE_LIN(tocornuwye) +GENERATE_LIN(tocornu3way) SET(LIN_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/to3way.lin @@ -38,19 +42,21 @@ SET(LIN_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/tostrsct.lin ${CMAKE_CURRENT_BINARY_DIR}/towye.lin ${CMAKE_CURRENT_BINARY_DIR}/toxing.lin + ${CMAKE_CURRENT_BINARY_DIR}/tocornu.lin + ${CMAKE_CURRENT_BINARY_DIR}/tocornuwye.lin + ${CMAKE_CURRENT_BINARY_DIR}/tocornu3way.lin ) -GET_TARGET_PROPERTY(genhelp_EXE genhelp LOCATION) - ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bllnhlp.c - DEPENDS genhelp ${help_SOURCE_DIR}/genhelp.in - COMMAND ${genhelp_EXE} ${GENHELP_OPTS} ${help_SOURCE_DIR}/genhelp.in ${CMAKE_CURRENT_BINARY_DIR}/bllnhlp.c + DEPENDS genhelp ${help_SOURCE_DIR}/genhelp.json + COMMAND genhelp ${GENHELP_OPTS} ${help_SOURCE_DIR}/genhelp.json ${CMAKE_CURRENT_BINARY_DIR}/bllnhlp.c ) SET(SOURCES ${LIN_SOURCES} appdefaults.c + archive.c bllnhlp.c cbezier.c cblock.c @@ -95,6 +101,7 @@ SET(SOURCES dcontmgm.c dease.c denum.c + directory.c dlayer.c doption.c dpricels.c @@ -104,33 +111,72 @@ SET(SOURCES dxfformat.c dxfoutput.c elev.c + file2uri.c + file2uri.h fileio.c + filenoteui.c i18n.c layout.c + linknoteui.c lprintf.c macro.c + manifest.c misc2.c param.c + paramfile.c + paramfilelist.c + paramfilesearch_ui.c + partcatalog.c paths.c + shortentext.c shrtpath.c smalldlg.c + stringxtc.c tbezier.c tcornu.c tcurve.c tease.c + textnoteui.c track.c + trknote.c trkseg.c tstraigh.c utility.c + validator.c + cJSON.c + archive.h + directory.h + manifest.h + validator.h ) +# add UTF-8 conversion utilities on Windows +if(WIN32) + set( SOURCES + ${SOURCES} + utf8convert.c + include/utf8convert.h + ) +endif(WIN32) + +set (SOURCES + ${SOURCES} + include/dirent.h + include/paramfile.h + include/paramfilelist.h +) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${XTrkCAD_BINARY_DIR}) INCLUDE_DIRECTORIES(${help_BINARY_DIR}) INCLUDE_DIRECTORIES(${wlib_SOURCE_DIR}/include) +include_directories(${FREEIMAGE_INCLUDE_PATH}) +INCLUDE_DIRECTORIES(${LIBZIP_INCLUDE_DIR_ZIP}) +INCLUDE_DIRECTORIES(${CJSON_INCLUDE}) LINK_DIRECTORIES(${GTK_LIBRARY_DIRS}) LINK_DIRECTORIES(${GTK_WEBKIT_LIBRARY_DIRS}) +LINK_DIRECTORIES(${LIBZIP_LIBZIP_LIBRARY}) ADD_LIBRARY(xtrkcad-lib ${SOURCES}) @@ -145,18 +191,22 @@ TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-lib) TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-wlib) TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-cornu) TARGET_LINK_LIBRARIES(xtrkcad dynstring) +target_link_libraries(xtrkcad ${LIBZIP_LIBRARY} ${LIBZIP_LIBRARIES}) ADD_EXECUTABLE(mkturnout ${LIN_SOURCES} ctodesgn.c utility.c + ) SET_TARGET_PROPERTIES(mkturnout PROPERTIES COMPILE_FLAGS -DMKTURNOUT) +TARGET_LINK_LIBRARIES(mkturnout xtrkcad-cornu) + IF(NOT WIN32) TARGET_LINK_LIBRARIES(mkturnout m) TARGET_LINK_LIBRARIES(xtrkcad m) - + # Link libintl for systems where it is a separate library find_library( INTL_LIBRARY intl ) if(INTL_LIBRARY) @@ -164,25 +214,57 @@ IF(NOT WIN32) endif(INTL_LIBRARY) ELSE(NOT WIN32) TARGET_LINK_LIBRARIES(mkturnout xtrkcad-wlib) -ENDIF(NOT WIN32) + + # copy dlls into the build dir for easier debugging + add_custom_command( + TARGET xtrkcad POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${FREEIMAGE_SHAREDLIB} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + add_custom_command( + TARGET xtrkcad POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${LIBZIP_SHAREDLIB} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + add_custom_command( + TARGET xtrkcad POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${ZLIB_SHAREDLIB} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + # add dll to install package + install(FILES + ${LIBZIP_SHAREDLIB} + DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} + ) + install(FILES + ${ZLIB_SHAREDLIB} + DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} + ) +ENDIF(NOT WIN32) # for testing only, should be IF(APPLE) ... IF(APPLE) - ADD_EXECUTABLE( helphelper helphelper.c ) + ADD_EXECUTABLE( helphelper helphelper.c ) FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation) - FIND_LIBRARY(CARBON_LIBRARY Carbon) + FIND_LIBRARY(CARBON_LIBRARY Carbon) TARGET_lINK_LIBRARIES(helphelper ${COREFOUNDATION_LIBRARY} ${CARBON_LIBRARY}) INSTALL( TARGETS helphelper RUNTIME DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} ) ENDIF(APPLE) - + INSTALL( TARGETS xtrkcad RUNTIME DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} ) - -if(XTRKCAD_TESTING AND CMOCKA_FOUND) + +if(XTRKCAD_TESTING AND CMOCKA_FOUND) add_subdirectory( unittest ) -endif() +endif() diff --git a/app/bin/acclkeys.h b/app/bin/acclkeys.h index 1cbdf00..4dd80fc 100644 --- a/app/bin/acclkeys.h +++ b/app/bin/acclkeys.h @@ -40,6 +40,9 @@ #define ACCL_CIRCLE2 (WCTL+'9') #define ACCL_CIRCLE3 (WCTL+'0') #define ACCL_BEZIER (0) +#define ACCL_CORNU (0) +#define ACCL_CONVERTTO (0) +#define ACCL_CONVERTFR (0) #define ACCL_TURNOUT (WCTL+'t') #define ACCL_TURNTABLE (WCTL+WSHIFT+'n') #define ACCL_PARALLEL (WCTL+WSHIFT+'p') @@ -56,6 +59,8 @@ #define ACCL_PROFILE (WCTL+WSHIFT+'f') #define ACCL_DELETE (WCTL+'d') #define ACCL_TUNNEL (WCTL+WSHIFT+'t') +#define ACCL_BRIDGE (0) +#define ACCL_TIES (0) #define ACCL_HNDLDTO (WCTL+WSHIFT+'i') #define ACCL_TEXT (WCTL+WSHIFT+'x') #define ACCL_DRAWLINE (WCTL+WSHIFT+'1') @@ -75,8 +80,10 @@ #define ACCL_DRAWBEZLINE (0) #define ACCL_DRAWBOX (WCTL+WSHIFT+'[') #define ACCL_DRAWFILLBOX (WALT+WCTL+'[') -#define ACCL_DRAWPOLYLINE (WCTL+WSHIFT+'2') +#define ACCL_DRAWPOLYLINE (0) #define ACCL_DRAWPOLYGON (WALT+WCTL+'2') +#define ACCL_DRAWPOLY (0) +#define ACCL_DRAWFILLPOLYGON (WCTL+WSHIFT+'2') #define ACCL_NOTE (WALT+WCTL+'n') #define ACCL_STRUCTURE (WCTL+WSHIFT+'c') #define ACCL_ABOVE (WCTL+WSHIFT+'b') @@ -104,6 +111,7 @@ #define ACCL_COPY (WCTL+'c') #define ACCL_CUT (WCTL+'x') #define ACCL_PASTE (WCTL+'v') +#define ACCL_CLONE (0) #define ACCL_SELECTALL (WCTL+WSHIFT+'a') #define ACCL_DESELECTALL (0) #define ACCL_THIN (WCTL+'1') @@ -111,6 +119,7 @@ #define ACCL_THICK (WCTL+'3') #define ACCL_EXPORT (WALT+WCTL+'x') #define ACCL_IMPORT (WALT+WCTL+'i') +#define ACCL_IMPORT_MOD (0) #define ACCL_EXPORTDXF (0) #define ACCL_LOOSEN (WCTL+WSHIFT+'k') #define ACCL_GROUP (WCTL+WSHIFT+'g') @@ -149,6 +158,7 @@ #define ACCL_PLAYBACK (WALT+WCTL+'b') #define ACCL_BRIDGE (0) +#define ACCL_TIES (0) /* Blocks */ #define ACCL_BLOCK1 (0) diff --git a/app/bin/appdefaults.c b/app/bin/appdefaults.c index a2dd885..55a2201 100644 --- a/app/bin/appdefaults.c +++ b/app/bin/appdefaults.c @@ -82,7 +82,10 @@ static char *GetParamPrototype(struct appDefault *ptrDefault, */ struct appDefault xtcDefaults[] = { - { "DialogItem.cmdopt-preselect", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< default command is select */ + { "DialogItem.cmdopt-preselect", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< default command is select */ + { "DialogItem.cmdopt-rightclickmode", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< swap default to context */ + { "DialogItem.cmdopt-selectmode", 0, INTEGERCONSTANT,{ .intValue = 0 } }, /**< 'Only' mode */ + { "DialogItem.cmdopt-selectzero", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< 'On' mode */ { "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 */ @@ -227,6 +230,14 @@ InitializeRegionCode(void) } /** + * Use Metric measures everywhere except United States and Canada\ + */ +static bool UseMetric() +{ + return ( strcmp( regionCode, "US" ) != 0 && + strcmp( regionCode, "CA" ) != 0 ); +} +/** * For the US the classical 4x8 sheet is used as default size. in the metric world 1,25x2,0m is used. */ @@ -234,11 +245,11 @@ static double GetLocalRoomSize(struct appDefault *ptrDefault, void *data) { if (!strcmp(ptrDefault->defaultKey, "draw.roomsizeY")) { - return (strcmp(regionCode, "US") ? 125.0/2.54 : 48); + return (UseMetric() ? 125.0/2.54 : 48); } if (!strcmp(ptrDefault->defaultKey, "draw.roomsizeX")) { - return (strcmp(regionCode, "US") ? 200.0 / 2.54 : 96); + return (UseMetric() ? 200.0 / 2.54 : 96); } return (0.0); // should never get here @@ -255,21 +266,21 @@ GetLocalPopularScale(struct appDefault *ptrDefault, void *data) } /** - * The measurement system is english for the US and metric elsewhere + * The measurement system is english for the US and Canada and metric elsewhere */ static int GetLocalMeasureSystem(struct appDefault *ptrDefault, void *data) { - return (strcmp(regionCode, "US") ? 1 : 0); + return (UseMetric() ? 1 : 0); } /** -* The distance format is 999.9 cm for metric and ?? for english +* The distance format is 999.9 cm for metric and 999.99 for english */ static int GetLocalDistanceFormat(struct appDefault *ptrDefault, void *data) { - return (strcmp(regionCode, "US") ? 8 : 5); + return (UseMetric() ? 8 : 4); } /** diff --git a/app/bin/archive.c b/app/bin/archive.c new file mode 100644 index 0000000..4e82bd3 --- /dev/null +++ b/app/bin/archive.c @@ -0,0 +1,454 @@ +/** \file archive.c + * ARCHIVE PROCESSING + */ + +/* XTrkCad - Model Railroad CAD + * Copyright (C) 2018 Adam Richards and 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 <errno.h> +#include <fcntl.h> + +#include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <zip.h> + +#ifdef WINDOWS + #include "include/dirent.h" + #include <direct.h> + #include <io.h> + #include <process.h> + #define unlink(a) _unlink((a)) + #define rmdir(a) _rmdir((a)) + #define open(name, flag, mode) _open((name), (flag), (mode)) + #define write(file, buffer, count) _write((file),(buffer), (count)) + #define close(file) _close((file)) + #define getpid() _getpid() +#else + #include <dirent.h> + #include <unistd.h> +#endif + +#include <wlib.h> +#include "archive.h" +#include "directory.h" +#include "dynstring.h" +#include "i18n.h" +#include "messages.h" +#include "misc.h" +#include "misc2.h" +#include "paths.h" +#include "include/utf8convert.h" + +int log_zip = 0; + +//char * +//NativeToUtf8(const char *nativeString) +//{ +// +//#ifdef WINDOWS +// +// int cnt = 2 * (strlen(nativeString) + 1); +// char *tempBuffer = MyMalloc( cnt ); +// char *destBuffer = MyMalloc( cnt ); +// +// //// find the +// //cnt = MultiByteToWideChar(CP_ACP, +// // 0, +// // nativeString, +// // -1, +// // tempBuffer, +// // 0); +// +// //tempBuffer = realloc(tempBuffer, cnt * 2 + 4); +// +// // convert to wide character (UTF16) +// MultiByteToWideChar(CP_ACP, +// 0, +// nativeString, +// -1, +// (LPWSTR)tempBuffer, +// cnt); +// +// // convert from wide char to UTF-8 +// WideCharToMultiByte(CP_UTF8, +// 0, +// (LPCWCH)tempBuffer, +// -1, +// (LPSTR)destBuffer, +// cnt, +// NULL, +// NULL); +// +// MyFree(tempBuffer); +//#else +// char * destBuffer = MyStrdup(nativeString); +//#endif +// +// return(destBuffer); +//} + +/** + * Create the full path for temporary directories used in zip archive operations + * + * \param archive operation + * \return pointer to full path, must be free'd by caller + */ + +char * +GetZipDirectoryName(enum ArchiveOps op) +{ + char *opDesc; + char *directory; + DynString zipDirectory; + + DynStringMalloc(&zipDirectory, 0); + + switch (op) { + case ARCHIVE_READ: + opDesc = "in"; + break; + case ARCHIVE_WRITE: + opDesc = "out"; + break; + default: + opDesc = "err"; + break; + } + + DynStringPrintf(&zipDirectory, + "%s" FILE_SEP_CHAR "zip_%s.%d", + workingDir, + opDesc, + getpid()); + + directory = strdup(DynStringToCStr(&zipDirectory)); + DynStringFree(&zipDirectory); + return (directory); +} + +/***************************************************************************** + * Add directory to archive + * + * \param IN zip The open zip archive handle + * \param IN dir_path The path to add + * \param IN prefix The prefix in the archive + * + * \returns TRUE if OK + */ + +BOOL_T AddDirectoryToArchive( + struct zip * za, + const char * dir_path, + const char * prefix) +{ + + char *full_path; + char *arch_path; + DIR *dir; + const char * buf; + struct stat stat_path, stat_entry; + struct dirent *entry; + + zip_source_t * zt; + + // stat for the path + stat(dir_path, &stat_path); + + // if path does not exists or is not dir - exit with status -1 + if (S_ISDIR(stat_path.st_mode) == 0) { + NoticeMessage(MSG_NOT_DIR_FAIL, + _("Continue"), NULL, dir_path); + return FALSE; + } + + // if not possible to read the directory for this user + if ((dir = opendir(dir_path)) == NULL) { + NoticeMessage(MSG_OPEN_DIR_FAIL, + _("Continue"), NULL, dir_path); + return FALSE; + } + + // iteration through entries in the directory + while ((entry = readdir(dir)) != NULL) { + // skip entries "." and ".." + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { + continue; + } + + // determinate a full path of an entry + MakeFullpath(&full_path, dir_path, entry->d_name, NULL); + + // stat for the entry + stat(full_path, &stat_entry); + + if (prefix && prefix[0]) { + MakeFullpath(&arch_path, prefix, entry->d_name, NULL); + } else { + MakeFullpath(&arch_path, entry->d_name, NULL); + } + + // recursively add a nested directory + if (S_ISDIR(stat_entry.st_mode) != 0) { + if (zip_dir_add(za, arch_path, 0) < 0) { + zip_error_t *ziperr = zip_get_error(za); + buf = zip_error_strerror(ziperr); + NoticeMessage(MSG_ZIP_DIR_ADD_FAIL, + _("Continue"), NULL, arch_path, buf); +#if DEBUG + printf("Added Directory %s \n", arch_path); +#endif + } + + if (AddDirectoryToArchive(za, full_path, arch_path) != TRUE) { + free(full_path); + free(arch_path); + return FALSE; + } + free(arch_path); + continue; + } else { + char *archPathUtf8 = MyStrdup(arch_path); + char *fullPathUtf8 = MyStrdup(full_path); +#ifdef WINDOWS + archPathUtf8 = Convert2UTF8(archPathUtf8); + fullPathUtf8 = Convert2UTF8(fullPathUtf8); + ConvertPathForward(archPathUtf8); +#endif // WINDOWS + zt = zip_source_file(za, fullPathUtf8, 0, -1); + if (zip_file_add(za, archPathUtf8, zt, ZIP_FL_ENC_UTF_8) == -1) { + zip_error_t *ziperr = zip_get_error(za); + buf = zip_error_strerror(ziperr); + NoticeMessage(MSG_ZIP_FILE_ADD_FAIL, _("Continue"), NULL, full_path, arch_path, + buf); + free(full_path); + free(arch_path); + MyFree(fullPathUtf8); + MyFree(archPathUtf8); + return FALSE; + } + MyFree(fullPathUtf8); + MyFree(archPathUtf8); +#if DEBUG + printf("Added File %s", full_path); +#endif + } + free(arch_path); + free(full_path); + } + + closedir(dir); + return TRUE; +} + +/*********************************************************************** + * Create Archive + * + * \param IN dir_path The place to create the archive + * \param IN fileName The name of the archive + * + * \return TRUE if ok + */ + +BOOL_T CreateArchive( + const char * dir_path, + const char * fileName) +{ + struct zip *za; + int err; + char buf[100]; + + char * archive = MyStrdup(fileName); // Because of const char + char * archive_name = FindFilename(archive); + char * archive_path; + char * archiveUtf8; + + MakeFullpath(&archive_path, workingDir, archive_name, NULL); + + archiveUtf8 = MyStrdup(archive_path); +#ifdef WINDOWS + archiveUtf8 = Convert2UTF8(archiveUtf8); +#endif // WINDOWS + + MyFree(archive); + + if ((za = zip_open(archiveUtf8, ZIP_CREATE, &err)) == NULL) { + zip_error_to_str(buf, sizeof(buf), err, errno); + NoticeMessage(MSG_ZIP_CREATE_FAIL, _("Continue"), NULL, archiveUtf8, buf); + MyFree(archiveUtf8); + return FALSE; + } +#if DEBUG + printf("====================== \n"); + printf("Started Archive %s", archive_path); +#endif + + AddDirectoryToArchive(za, dir_path, ""); + + if (zip_close(za) == -1) { + zip_error_to_str(buf, sizeof(buf), err, errno); + NoticeMessage(MSG_ZIP_CLOSE_FAIL, _("Continue"), NULL, archiveUtf8, buf); + free(archive_path); + MyFree(archiveUtf8); + return FALSE; + } + + unlink(fileName); //Delete Old + if (rename(archive_path, fileName) == -1) { //Move zip into place + NoticeMessage(MSG_ZIP_RENAME_FAIL, _("Continue"), NULL, archiveUtf8, fileName, + strerror(errno)); + free(archive_path); + MyFree(archiveUtf8); + return FALSE; + } + free(archive_path); + MyFree(archiveUtf8); + +#if DEBUG + printf("Moved Archive to %s", fileName); + printf("====================== \n"); +#endif + return TRUE; +} + +/************************************************************************** + * Unpack_Archive_for + * + * \param IN pathName the name of the archive + * \param IN fileName just the filename and extension of the layout + * \param IN tempDir The directory to use to unpack into + * + * \returns TRUE if all worked + */ +BOOL_T UnpackArchiveFor( + const char * pathName, /*Full name of archive*/ + const char * fileName, /*Layout name and extension */ + const char * tempDir, /*Directory to unpack into */ + BOOL_T file_only) +{ + char *dirName; + struct zip *za; + struct zip_file *zf; + struct zip_stat sb; + char buf[100]; + int err; + int i; + int64_t len; + FILE *fd; + long long sum; + + char *destBuffer = MyStrdup(pathName); +#ifdef WINDOWS + destBuffer = Convert2UTF8(destBuffer); +#endif // WINDOWS + + + if ((za = zip_open(destBuffer, 0, &err)) == NULL) { + zip_error_to_str(buf, sizeof(buf), err, errno); + NoticeMessage(MSG_ZIP_OPEN_FAIL, _("Continue"), NULL, pathName, buf); + fprintf(stderr, "xtrkcad: can't open xtrkcad zip archive `%s': %s \n", + pathName, buf); + + MyFree(destBuffer); + return FALSE; + } + + for (i = 0; i < zip_get_num_entries(za, 0); i++) { + if (zip_stat_index(za, i, 0, &sb) == 0) { + len = strlen(sb.name); + +#if DEBUG + printf("==================\n"); + printf("Name: [%s], ", sb.name); + printf("Size: [%llu], ", sb.size); + printf("mtime: [%u]\n", (unsigned int)sb.mtime); + printf("mtime: [%u]\n", (unsigned int)sb.mtime); +#endif + + LOG(log_zip, 1, ("================= \n")) + LOG(log_zip, 1, ("Zip-Name [%s] \n", sb.name)) + LOG(log_zip, 1, ("Zip-Size [%llu] \n", sb.size)) + LOG(log_zip, 1, ("Zip-mtime [%u] \n", (unsigned int)sb.mtime)) + + if (sb.name[len - 1] == '/' && !file_only) { + MakeFullpath(&dirName, tempDir, &sb.name[0], NULL); + if (SafeCreateDir(dirName) != TRUE) { + free(dirName); + return FALSE; + } + free(dirName); + } else { + zf = zip_fopen_index(za, i, 0); + if (!zf) { + NoticeMessage(MSG_ZIP_INDEX_FAIL, _("Continue"), NULL); + fprintf(stderr, "xtrkcad zip archive open index error \n"); + return FALSE; + } + + if (file_only) { + if (strncmp(sb.name, fileName, strlen(fileName)) != 0) { + continue; /* Ignore any other files than the one we asked for */ + } + } + MakeFullpath(&dirName, tempDir, &sb.name[0], NULL); +#ifdef WINDOWS + ConvertUTF8ToSystem(dirName); +#endif // WINDOWS + fd = fopen(dirName, "wb"); + if (!fd) { + NoticeMessage(MSG_ZIP_FILE_OPEN_FAIL, _("Continue"), NULL, dirName, + strerror(errno)); + free(dirName); + return FALSE; + } + + sum = 0; + while (sum != sb.size) { + len = zip_fread(zf, buf, 100); + if (len < 0) { + NoticeMessage(MSG_ZIP_READ_FAIL, _("Continue"), NULL, dirName, &sb.name[0]); + free(dirName); + fclose(fd); + return FALSE; + } + fwrite(buf, 1, (unsigned int)len, fd); + sum += len; + } + fclose(fd); + free(dirName); + zip_fclose(zf); + } + } else { + LOG(log_zip, 1, ("Zip-Unknown File[%s] Line[%d] \n", __FILE__, __LINE__)) +#if DEBUG + printf("File[%s] Line[%d]\n", __FILE__, __LINE__); +#endif + } + } + + MyFree(destBuffer); + + if (zip_close(za) == -1) { + NoticeMessage(MSG_ZIP_CLOSE_FAIL, _("Continue"), NULL, dirName, &sb.name[0]); + return FALSE; + } + return TRUE; +} + diff --git a/app/bin/archive.h b/app/bin/archive.h new file mode 100644 index 0000000..cfbb642 --- /dev/null +++ b/app/bin/archive.h @@ -0,0 +1,15 @@ +#ifndef HAVE_ARCHIVE_H +#define HAVE_ARCHIVE_H +#include <zip.h> +#include "common.h" + +enum ArchiveOps { ARCHIVE_READ, ARCHIVE_WRITE }; // has to be contiguous, see CleanupFiles()! + +extern int log_zip; +extern const char *workingDir; + +char *GetZipDirectoryName(enum ArchiveOps op); +BOOL_T AddDirectoryToArchive(struct zip * za, const char * dir_path, const char * prefix); +BOOL_T CreateArchive(const char * dir_path, const char * fileName); +BOOL_T UnpackArchiveFor(const char * pathName, const char * fileName, const char * tempDir, BOOL_T file_only); +#endif diff --git a/app/bin/bdf2xtp.c b/app/bin/bdf2xtp.c index 76fb31a..c979aa3 100644 --- a/app/bin/bdf2xtp.c +++ b/app/bin/bdf2xtp.c @@ -9,6 +9,7 @@ #include <math.h> #ifndef _MSDOS #include <unistd.h> +#include "fileio.h" #else #define M_PI 3.14159265358979323846 #define strncasecmp strnicmp @@ -563,7 +564,7 @@ void generateTurnout( void ) fprintf( fout, "\tC 0 0 %0.6f %0.6f %0.6f %0.6f %0.6f\n", X(sp->radius), X(center.x), X(center.y), X(a0), X(a1) ); } - fprintf( fout, "\tEND\n" ); + fprintf( fout, "\t%s\n", END_SEGS ); } @@ -875,7 +876,7 @@ void process( tokenDesc_t * tp, arg_t *args ) break; } } - fprintf( fout, "\tEND\n" ); + fprintf( fout, "\t%s\n", END_SEGS ); break; case ACT_TRANSFERTABLE: @@ -928,7 +929,7 @@ void process( tokenDesc_t * tp, arg_t *args ) } offset += length2; } - fprintf( fout, "\tEND\n"); + fprintf( fout, "\t%s\n", END_SEGS); break; case ACT_ENDTRANSFERTABLE: @@ -956,7 +957,7 @@ void process( tokenDesc_t * tp, arg_t *args ) break; } } - fprintf( fout, "\tEND\n" ); + fprintf( fout, "\t%s\n", END_SEGS ); break; case ACT_FILL_POINT: diff --git a/app/bin/bitmaps/SVG/star.svg b/app/bin/bitmaps/SVG/star.svg new file mode 100644 index 0000000..13f0914 --- /dev/null +++ b/app/bin/bitmaps/SVG/star.svg @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="64" + height="64" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.45.1" + version="1.0" + inkscape:export-filename="C:\Users\mf\Desktop\star.png" + inkscape:export-xdpi="22.5" + inkscape:export-ydpi="22.5" + sodipodi:docbase="C:\Users\mf\Documents\XTrackCAD\src\work\app\bin\bitmaps\SVG" + sodipodi:docname="star.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs4"> + <linearGradient + id="linearGradient3159"> + <stop + style="stop-color:#808080;stop-opacity:1;" + offset="0" + id="stop3161" /> + <stop + id="stop3167" + offset="1" + style="stop-color:#404040;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient3153"> + <stop + id="stop3155" + offset="0" + style="stop-color:#ffff00;stop-opacity:1;" /> + <stop + id="stop3157" + offset="1" + style="stop-color:#ffff00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient3136"> + <stop + style="stop-color:#ffff00;stop-opacity:1;" + offset="0" + id="stop3138" /> + <stop + style="stop-color:#ffff00;stop-opacity:0;" + offset="1" + id="stop3140" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3159" + id="radialGradient3165" + cx="37.931442" + cy="34.408134" + fx="37.931442" + fy="34.408134" + r="35.324765" + gradientTransform="matrix(1,0,0,0.956027,0,1.7894602)" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8" + inkscape:cx="61.305799" + inkscape:cy="40.157191" + inkscape:document-units="px" + inkscape:current-layer="layer1" + width="64px" + height="64px" + inkscape:window-width="765" + inkscape:window-height="575" + inkscape:window-x="785" + inkscape:window-y="236" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + sodipodi:type="star" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.27731241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1.0;fill:url(#radialGradient3165)" + id="path2160" + sodipodi:sides="5" + sodipodi:cx="43.214287" + sodipodi:cy="44" + sodipodi:r1="35.801678" + sodipodi:r2="14.088029" + sodipodi:arg1="-2.8166875" + sodipodi:arg2="-2.1460669" + inkscape:flatsided="false" + inkscape:rounded="0" + inkscape:randomized="0" + d="M 9.2857168,32.571428 L 35.549528,32.179508 L 43.599,8.2003894 L 52.087702,33.057648 L 77.380623,33.303196 L 56.363118,49.057747 L 63.94553,73.188622 L 42.467296,58.068211 L 21.860564,72.736365 L 29.60379,47.636886 L 9.2857168,32.571428 z " + transform="matrix(0.793397,0,0,0.7725297,-2.475811,0.6853635)" /> + </g> +</svg> diff --git a/app/bin/bitmaps/XCF/bluedot.xcf b/app/bin/bitmaps/XCF/bluedot.xcf Binary files differnew file mode 100644 index 0000000..30d323e --- /dev/null +++ b/app/bin/bitmaps/XCF/bluedot.xcf diff --git a/app/bin/bitmaps/XCF/greendot.xcf b/app/bin/bitmaps/XCF/greendot.xcf Binary files differnew file mode 100644 index 0000000..f59311a --- /dev/null +++ b/app/bin/bitmaps/XCF/greendot.xcf diff --git a/app/bin/bitmaps/XCF/greydot.xcf b/app/bin/bitmaps/XCF/greydot.xcf Binary files differnew file mode 100644 index 0000000..7e795a5 --- /dev/null +++ b/app/bin/bitmaps/XCF/greydot.xcf diff --git a/app/bin/bitmaps/XCF/reddot.xcf b/app/bin/bitmaps/XCF/reddot.xcf Binary files differnew file mode 100644 index 0000000..449581f --- /dev/null +++ b/app/bin/bitmaps/XCF/reddot.xcf diff --git a/app/bin/bitmaps/XCF/yellowdot.xcf b/app/bin/bitmaps/XCF/yellowdot.xcf Binary files differnew file mode 100644 index 0000000..9395645 --- /dev/null +++ b/app/bin/bitmaps/XCF/yellowdot.xcf diff --git a/app/bin/bitmaps/arrow0.xbm b/app/bin/bitmaps/arrow0.xbm index 60fb2aa..f07a9e4 100644 --- a/app/bin/bitmaps/arrow0.xbm +++ b/app/bin/bitmaps/arrow0.xbm @@ -1,9 +1,9 @@ #define arrow0_width 24 #define arrow0_height 24 -static char arrow0_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x04, 0x02, - 0x00, 0x04, 0x01, 0x00, 0x84, 0x00, 0x00, 0x04, 0x01, 0x00, 0x24, 0x02, - 0x00, 0x54, 0x04, 0x00, 0x8c, 0x08, 0x00, 0x04, 0x11, 0x00, 0x00, 0x22, - 0x00, 0x00, 0x44, 0x00, 0x00, 0x88, 0x00, 0x00, 0x50, 0x00, 0x00, 0x20}; +static unsigned char arrow0_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x24, 0x00, +0x00, 0x42, 0x00, 0x00, 0x81, 0x00, 0x80, 0x00, 0x01, 0xc0, 0xe7, 0x03, +0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, +0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x3c, 0x00}; diff --git a/app/bin/bitmaps/arrow0_ctl.xbm b/app/bin/bitmaps/arrow0_ctl.xbm new file mode 100644 index 0000000..3b535c4 --- /dev/null +++ b/app/bin/bitmaps/arrow0_ctl.xbm @@ -0,0 +1,9 @@ +#define arrow0_ctl_width 24 +#define arrow0_ctl_height 24 +static unsigned char arrow0_ctl_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3c, 0x00, +0x00, 0x7e, 0x00, 0x00, 0xff, 0x00, 0x80, 0xff, 0x01, 0xc0, 0xff, 0x03, +0x00, 0x24, 0x00, 0x00, 0x24, 0x06, 0x00, 0x24, 0x09, 0x00, 0x24, 0x01, +0x00, 0x24, 0x01, 0x00, 0x24, 0x09, 0x00, 0x24, 0x06, 0x00, 0x3c, 0x00};
\ No newline at end of file diff --git a/app/bin/bitmaps/arrow0_shift.xbm b/app/bin/bitmaps/arrow0_shift.xbm new file mode 100644 index 0000000..683f7e3 --- /dev/null +++ b/app/bin/bitmaps/arrow0_shift.xbm @@ -0,0 +1,9 @@ +#define arrow0_shift_width 24 +#define arrow0_shift_height 24 +static unsigned char arrow0_shift_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x00, 0x00, 0x24, 0x00, 0x00, 0x5a, 0x00, 0x00, 0xa5, 0x00, +0x80, 0x42, 0x01, 0x40, 0x81, 0x02, 0xa0, 0x00, 0x05, 0xd0, 0xe7, 0x0b, +0x10, 0x24, 0x08, 0xe0, 0xa5, 0x67, 0x00, 0xa5, 0x90, 0x00, 0xa5, 0x10, +0x00, 0xa5, 0x60, 0x00, 0xa5, 0x80, 0x00, 0xa5, 0x90, 0x00, 0xbd, 0x60};
\ No newline at end of file diff --git a/app/bin/bitmaps/arrow3.xbm b/app/bin/bitmaps/arrow3.xbm index 5f85bc0..aeac91f 100644 --- a/app/bin/bitmaps/arrow3.xbm +++ b/app/bin/bitmaps/arrow3.xbm @@ -1,6 +1,6 @@ #define arrow3_width 24 #define arrow3_height 24 -static char arrow3_bits[] = { +static unsigned char arrow3_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0xfc, 0x03, diff --git a/app/bin/bitmaps/arrow3_ctl.xbm b/app/bin/bitmaps/arrow3_ctl.xbm new file mode 100644 index 0000000..e87279a --- /dev/null +++ b/app/bin/bitmaps/arrow3_ctl.xbm @@ -0,0 +1,9 @@ +#define arrow3_ctl_width 24 +#define arrow3_ctl_height 24 +static unsigned char arrow3_ctl_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x04, 0x02, +0x00, 0x04, 0x01, 0x00, 0x84, 0x00, 0x00, 0xc4, 0x01, 0x00, 0xe4, 0x03, +0xc0, 0xd4, 0x07, 0x20, 0x8d, 0x0f, 0x20, 0x04, 0x1f, 0x20, 0x00, 0x3e, +0x20, 0x00, 0x7c, 0x20, 0x01, 0xf8, 0xc0, 0x00, 0x70, 0x00, 0x00, 0x20 };
\ No newline at end of file diff --git a/app/bin/bitmaps/arrow3_shift.xbm b/app/bin/bitmaps/arrow3_shift.xbm new file mode 100644 index 0000000..d2ee571 --- /dev/null +++ b/app/bin/bitmaps/arrow3_shift.xbm @@ -0,0 +1,9 @@ +#define arrow3_shift_width 24 +#define arrow3_shift_height 24 +static unsigned char arrow3_shift_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x0f, 0x00, 0x01, 0x10, 0x00, 0xfd, 0x17, 0x00, 0xfd, 0x0b, +0x00, 0xfd, 0x05, 0x00, 0xfd, 0x02, 0x00, 0xfd, 0x05, 0x00, 0xfd, 0x0b, +0x30, 0xdd, 0x17, 0x48, 0xad, 0x2f, 0x08, 0x55, 0x5f, 0x30, 0x89, 0xbe, +0x40, 0x06, 0x7d, 0x48, 0x00, 0xfa, 0x30, 0x00, 0x74, 0x00, 0x00, 0xa8};
\ No newline at end of file diff --git a/app/bin/bitmaps/arrowr3.xbm b/app/bin/bitmaps/arrowr3.xbm new file mode 100644 index 0000000..e63a39b --- /dev/null +++ b/app/bin/bitmaps/arrowr3.xbm @@ -0,0 +1,9 @@ +#define arrowr3_width 24 +#define arrowr3_height 24 +static unsigned char arrowr3_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0x3f, 0x00, +0x80, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x80, 0x3f, 0x00, 0xc0, 0x3f, 0x00, +0xe0, 0x3b, 0x00, 0xf0, 0x31, 0x00, 0xf8, 0x20, 0x00, 0x7c, 0x00, 0x00, +0x3e, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x04, 0x00, 0x00};
\ No newline at end of file diff --git a/app/bin/bitmaps/arrowr3_ctl.xbm b/app/bin/bitmaps/arrowr3_ctl.xbm new file mode 100644 index 0000000..f7bd770 --- /dev/null +++ b/app/bin/bitmaps/arrowr3_ctl.xbm @@ -0,0 +1,9 @@ +#define arrowr3_ctl_width 24 +#define arrowr3_ctl_height 24 +static unsigned char arrowr3_ctl_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x40, 0x20, 0x00, +0x80, 0x20, 0x00, 0x00, 0x21, 0x00, 0x80, 0x23, 0x00, 0xc0, 0x27, 0x00, +0xe0, 0x2b, 0x00, 0xf0, 0x31, 0x06, 0xf8, 0x20, 0x09, 0x7c, 0x00, 0x01, +0x3e, 0x00, 0x01, 0x1f, 0x00, 0x09, 0x0e, 0x00, 0x06, 0x04, 0x00, 0x00};
\ No newline at end of file diff --git a/app/bin/bitmaps/arrowr3_shift.xbm b/app/bin/bitmaps/arrowr3_shift.xbm new file mode 100644 index 0000000..1b10ea9 --- /dev/null +++ b/app/bin/bitmaps/arrowr3_shift.xbm @@ -0,0 +1,9 @@ +#define arrowr3_shift_width 24 +#define arrowr3_shift_height 24 +static unsigned char arrowr3_shift_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xf0, 0xff, 0x00, 0x08, 0x80, 0x00, 0xe8, 0xbf, 0x00, 0xd0, 0xbf, 0x00, +0xa0, 0xbf, 0x00, 0x40, 0xbf, 0x00, 0xa0, 0xbf, 0x00, 0xd0, 0xbf, 0x00, +0xe8, 0xbb, 0x00, 0xf4, 0xb5, 0x0c, 0xfa, 0xaa, 0x12, 0x7d, 0x91, 0x02, +0xbe, 0x60, 0x0c, 0x5f, 0x00, 0x10, 0x2e, 0x00, 0x12, 0x15, 0x00, 0x0c};
\ No newline at end of file diff --git a/app/bin/bitmaps/arrows.xbm b/app/bin/bitmaps/arrows.xbm index 494b8de..7ac3113 100644 --- a/app/bin/bitmaps/arrows.xbm +++ b/app/bin/bitmaps/arrows.xbm @@ -1,7 +1,7 @@ #define arrows_width 24 #define arrows_height 24 // static unsigned char arrows_bits[] = { -static char arrows_bits[] = { +static unsigned char arrows_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x01, 0x10, 0x00, 0xfd, 0x17, 0x00, 0xfd, 0x13, diff --git a/app/bin/bitmaps/background.xpm b/app/bin/bitmaps/background.xpm new file mode 100644 index 0000000..4859734 --- /dev/null +++ b/app/bin/bitmaps/background.xpm @@ -0,0 +1,155 @@ +/* XPM */
+static char *background[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 133 2 ",
+" c #0B2B2B",
+". c #183A3A",
+"X c #789757",
+"o c #799358",
+"O c #7E9068",
+"+ c #86A068",
+"@ c #9BA77A",
+"# c #99B073",
+"$ c #9DB777",
+"% c #98B67E",
+"& c #A6BD7F",
+"* c #A4BE7E",
+"= c #77AAA8",
+"- c #5FA7D7",
+"; c #58A1DB",
+": c #59A2DB",
+"> c #5AA3DA",
+", c #5BA4DB",
+"< c #5CA4D9",
+"1 c #5DA5DB",
+"2 c #66ACD3",
+"3 c #62A9D5",
+"4 c #69AED1",
+"5 c #60A9DB",
+"6 c #63ACDB",
+"7 c #64ACDA",
+"8 c #66AFDB",
+"9 c #62ACDE",
+"0 c #67B0DC",
+"q c #67B0DE",
+"w c #68B1DB",
+"e c #6BB4DB",
+"r c #6EB7DB",
+"t c #6FBADF",
+"y c #71B9DB",
+"u c #71BADB",
+"i c #74BEDE",
+"p c #6FBAE0",
+"a c #6EB9E3",
+"s c #73BEE3",
+"d c #74BEE0",
+"f c #72BEE4",
+"g c #70BCE7",
+"h c #6BBFFF",
+"j c #7CC9E9",
+"k c #7CCAEC",
+"l c #6EC2FF",
+"z c #6FC4FF",
+"x c #73C8FF",
+"c c #74C9FF",
+"v c #78CDFF",
+"b c #79CEFF",
+"n c #7DD2FF",
+"m c #7ED3FF",
+"M c #809786",
+"N c #84AC98",
+"B c #93A492",
+"V c #A1AD8E",
+"C c #A3B587",
+"Z c #A7B787",
+"A c #ABB584",
+"S c #A2B389",
+"D c #A3B988",
+"F c #A8BA94",
+"G c #ACBD97",
+"H c #B5BC90",
+"J c #8EA8A8",
+"K c #97BEAB",
+"L c #8BADB7",
+"P c #80B2B8",
+"I c #91B5B6",
+"U c #AFBFA9",
+"Y c #A4C182",
+"T c #B5C987",
+"R c #B2C088",
+"E c #BAD08E",
+"W c #AFC491",
+"Q c #B6CB97",
+"! c #BED190",
+"~ c #AFCEAA",
+"^ c #BBCAA0",
+"/ c #BECFA1",
+"( c #BDCEA7",
+") c #B5C7A9",
+"_ c #BFD0AE",
+"` c #BFD1AF",
+"' c #A8CDBF",
+"] c #C2CC95",
+"[ c #C7D798",
+"{ c #C3D19D",
+"} c #C6D898",
+"| c #CDD8A6",
+" . c #D0DDA6",
+".. c #C4DCB6",
+"X. c #D3E0A2",
+"o. c #D0E4B9",
+"O. c #DBE5B9",
+"+. c #D9E5BD",
+"@. c #E2ECB3",
+"#. c #E4EDB0",
+"$. c #87B8C5",
+"%. c #96CFDB",
+"&. c #9CD1D5",
+"*. c #98D1DF",
+"=. c #A4CDC4",
+"-. c #ADD7D0",
+";. c #B0D1D5",
+":. c #82D6FF",
+">. c #83D7FF",
+",. c #83D8FF",
+"<. c #8CDEFF",
+"1. c #95DEFC",
+"2. c #99E1F6",
+"3. c #A8E4ED",
+"4. c #B6E6E2",
+"5. c #BDEAE6",
+"6. c #ADE7F8",
+"7. c #E2EBCA",
+"8. c #E2F3F3",
+"9. c #E4F4F4",
+"0. c #E6F5F5",
+"q. c #E9F6F6",
+"w. c #EBF7F7",
+"e. c #E9F9F9",
+"r. c #EEF8F8",
+"t. c #F1F9F9",
+"y. c #F4FBFB",
+"u. c #F7FCFC",
+"i. c #F9FDFD",
+"p. c #FCFEFE",
+"a. c #FEFFFF",
+"s. c #FFFFFF",
+"d. c None",
+/* pixels */
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.s.s.s.s.s.s.s.s.s.s.s.s.s.d.d.",
+"d.s.; ; , < 5 6 7 w e r r s.d.d.",
+"d.s.; l l 9 x v a m ,.1.k s.d.d.",
+"d.i.< z x q b m j ,.3.5.-.i.d.d.",
+"d.u.- 7 q g p s %.*.%.=.{ u.d.d.",
+"d.y.3 b m t :.5.| @.o...K u.d.d.",
+"d.t.2 m :.i 2.#._ .} ! = t.d.d.",
+"d.w.4 u i k ' ] / W * $ = w.d.d.",
+"d.q.$.<.6.;.7.+.^ ~ D % N q.d.d.",
+"d.w.H O. .R T * D _ ) F I q.d.d.",
+"d.q.A [ ! # Q ( F F ) V L 0.d.d.",
+"d.0.@ Z C S + X o O B M J 0.d.d.",
+". e.8.8.8.8.8.8.8.8.8.8.8.e.. d.",
+"d. d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d."
+};
diff --git a/app/bin/bitmaps/bluedot.xpm b/app/bin/bitmaps/bluedot.xpm new file mode 100644 index 0000000..5c1df4c --- /dev/null +++ b/app/bin/bitmaps/bluedot.xpm @@ -0,0 +1,26 @@ +/* XPM */
+static char * bluedot[] = {
+"16 16 7 1",
+" c None",
+". c #000000",
+"+ c #3465A4",
+"@ c #3565A4",
+"# c #4465A1",
+"$ c #5A649B",
+"% c #4C79BA",
+" ",
+" ",
+" .... ",
+" ..#@@#.. ",
+" .$%%%+++$. ",
+" .%%%%%+++. ",
+" .#%%%%%+++#. ",
+" .@%%%%%+++@. ",
+" .@+%%%++++@. ",
+" .#++++++++#. ",
+" .++++++++. ",
+" .$++++++$. ",
+" ..#@@#.. ",
+" .... ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/bma0.xbm b/app/bin/bitmaps/bma0.xbm index e0a2815..6986b0f 100644 --- a/app/bin/bitmaps/bma0.xbm +++ b/app/bin/bitmaps/bma0.xbm @@ -1,6 +1,6 @@ #define bma0_width 16 #define bma0_height 16 -static char bma0_bits[] = { +static unsigned char bma0_bits[] = { 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bma135.xbm b/app/bin/bitmaps/bma135.xbm index e0c5f4a..5a3ffcb 100644 --- a/app/bin/bitmaps/bma135.xbm +++ b/app/bin/bitmaps/bma135.xbm @@ -1,6 +1,6 @@ #define bma135_width 16 #define bma135_height 16 -static char bma135_bits[] = { +static unsigned char bma135_bits[] = { 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bma45.xbm b/app/bin/bitmaps/bma45.xbm index c4717b4..6a943f0 100644 --- a/app/bin/bitmaps/bma45.xbm +++ b/app/bin/bitmaps/bma45.xbm @@ -1,6 +1,6 @@ #define bma45_width 16 #define bma45_height 16 -static char bma45_bits[] = { +static unsigned char bma45_bits[] = { 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bma90.xbm b/app/bin/bitmaps/bma90.xbm index cf03ee3..007a8d5 100644 --- a/app/bin/bitmaps/bma90.xbm +++ b/app/bin/bitmaps/bma90.xbm @@ -1,6 +1,6 @@ #define bma90_width 16 #define bma90_height 16 -static char bma90_bits[] = { +static unsigned char bma90_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bmendpt.xbm b/app/bin/bitmaps/bmendpt.xbm index 1bea7b7..7572d17 100644 --- a/app/bin/bitmaps/bmendpt.xbm +++ b/app/bin/bitmaps/bmendpt.xbm @@ -1,6 +1,6 @@ #define bmendpt_width 16 #define bmendpt_height 16 -static char bmendpt_bits[] = { +static unsigned char bmendpt_bits[] = { 0x81, 0x40, 0x82, 0x20, 0x84, 0x10, 0x88, 0x08, 0x90, 0x04, 0xa0, 0x02, 0xc0, 0x01, 0xff, 0x7f, 0xc0, 0x01, 0xa0, 0x02, 0x90, 0x04, 0x88, 0x08, 0x84, 0x10, 0x82, 0x20, 0x81, 0x40, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bridge.xpm b/app/bin/bitmaps/bridge.xpm new file mode 100644 index 0000000..446f055 --- /dev/null +++ b/app/bin/bitmaps/bridge.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * bridge_xpm[] = { +"16 16 3 1", +" c None", +". c #00FFFF", +"+ c #000000", +".. ..", +" .. .. ", +" ............ ", +" .......... ", +"+ + + + ", +"+++++++++++++++ ", +"+ + + + ", +"+ + + + ", +"+ + + + ", +"+++++++++++++++ ", +"+ + + + ", +" .......... ", +" ............ ", +" .. .. ", +".. ..", +" "}; diff --git a/app/bin/bitmaps/clip.xbm b/app/bin/bitmaps/clip.xbm new file mode 100644 index 0000000..6bffd55 --- /dev/null +++ b/app/bin/bitmaps/clip.xbm @@ -0,0 +1,6 @@ +#define clip_width 16 +#define clip_height 16 +static unsigned char clip_bits[] = { + 0xff, 0x03, 0x01, 0x06, 0x01, 0x0a, 0x01, 0x12, 0x01, 0x22, 0x01, 0x7e, + 0x01, 0x40, 0xf9, 0x5f, 0x05, 0x60, 0x13, 0x60, 0xf3, 0x7f, 0x05, 0x60, + 0xf9, 0x5f, 0x01, 0x40, 0x01, 0x40, 0xff, 0x7f }; diff --git a/app/bin/bitmaps/convertfr.xpm b/app/bin/bitmaps/convertfr.xpm new file mode 100644 index 0000000..7f141c8 --- /dev/null +++ b/app/bin/bitmaps/convertfr.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char * convertfr_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/convertto.xpm b/app/bin/bitmaps/convertto.xpm new file mode 100644 index 0000000..f0fead2 --- /dev/null +++ b/app/bin/bitmaps/convertto.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char * convertto_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/cornu.xpm b/app/bin/bitmaps/cornu.xpm new file mode 100644 index 0000000..bd3a2ed --- /dev/null +++ b/app/bin/bitmaps/cornu.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char * cornu_xpm[] = { +"16 16 4 1", +" c None", +"! c #000000000000", +"# c #FFFF00000000", +"$ c #808080000000", +" !!$!!!! ", +" !! $ !! ", +" !! $!!! $$$", +" $! !!$ $$ !!", +" !! $! ! !!", +"!! !! !! !! ", +"! !! $###$ ", +"$$$$ # # ", +"! !! ### ", +"! !! ", +"! !$ ", +"!!$$! ", +"!$ !! ", +"$! $!!!$!!$###", +" !! $ $ # #", +" $!!!!!$!!$###"}; diff --git a/app/bin/bitmaps/cross0.xbm b/app/bin/bitmaps/cross0.xbm index 373d897..8f2e35d 100644 --- a/app/bin/bitmaps/cross0.xbm +++ b/app/bin/bitmaps/cross0.xbm @@ -1,5 +1,5 @@ #define cross0_width 8 #define cross0_height 8 //static unsigned char cross0_bits[] = { -static char cross0_bits[] = { +static unsigned char cross0_bits[] = { 0x04, 0x04, 0x1f, 0x04, 0x04, 0x00, 0x00, 0x00}; diff --git a/app/bin/bitmaps/delete.xpm b/app/bin/bitmaps/delete.xpm index 1e88b80..63b875a 100644 --- a/app/bin/bitmaps/delete.xpm +++ b/app/bin/bitmaps/delete.xpm @@ -1,21 +1,22 @@ /* XPM */ static char * delete_xpm[] = { -"16 16 2 1", -". c None", -" c #000000000000", -" ............ .", -" ......... ..", -".. ...... ...", -"... .... ....", -".. .. .. .. ..", -" .. . ", -".. ... ... ..", -".. .... .... ..", -".. ... ... ..", -" . . . ", -".. . .... . ..", -"... ...... ...", -".. ........ ..", -". ........... .", -" .............", -". ............. "}; +"16 16 3 1", +" c None", +". c #FF0000", +"+ c #000000", +" .. .. ", +" .. .. ", +" .. .. ", +" .. .. ", +" + .. .. + ", +"++++++....++++++", +" + +..+ + ", +" + +..+ + ", +" + .... + ", +"+++++..++..+++++", +" + .. .. + ", +" .. .. ", +" .. .. ", +" .. .. ", +".. ..", +" "}; diff --git a/app/bin/bitmaps/document-export.xpm b/app/bin/bitmaps/document-export.xpm new file mode 100644 index 0000000..8d632de --- /dev/null +++ b/app/bin/bitmaps/document-export.xpm @@ -0,0 +1,90 @@ +/* XPM */
+static char * export_xpm[] = {
+"16 16 71 1",
+" c None",
+". c #406C98",
+"+ c #DDF0FB",
+"@ c #D4E9F7",
+"# c #D1E7F5",
+"$ c #CEE4F4",
+"% c #CCE2F3",
+"& c #CCE1F2",
+"* c #A7C2DC",
+"= c #D6EBF7",
+"- c #C5DFEF",
+"; c #C1DBED",
+"> c #BCD6EA",
+", c #B6D0E8",
+"' c #B3CDE6",
+") c #B2CCE5",
+"! c #9AB6D2",
+"~ c #E5F6FF",
+"{ c #D7ECF8",
+"] c #C7E1EF",
+"^ c #85A4C2",
+"/ c #D7EDF8",
+"( c #C8E2F0",
+"_ c #D8EEF8",
+": c #CAE4F1",
+"< c #D9EEF9",
+"[ c #CBE5F2",
+"} c #8FAFCF",
+"| c #83A5C7",
+"1 c #DAEFF9",
+"2 c #CDE7F2",
+"3 c #81A3C5",
+"4 c #105293",
+"5 c #DAF0F9",
+"6 c #CEE8F3",
+"7 c #C0DAEB",
+"8 c #AFCCE0",
+"9 c #9AB9D4",
+"0 c #88A9C9",
+"a c #7FA1C3",
+"b c #CCE1F0",
+"c c #155493",
+"d c #DBF0FA",
+"e c #D0EAF4",
+"f c #CFE8F3",
+"g c #D4EAF6",
+"h c #E1F3FD",
+"i c #195793",
+"j c #DBF1FA",
+"k c #D1EBF4",
+"l c #C1DCEB",
+"m c #AFCBE0",
+"n c #98B7D1",
+"o c #84A4C4",
+"p c #799BBD",
+"q c #CBE0EF",
+"r c #1E5993",
+"s c #DCF1FA",
+"t c #D2ECF5",
+"u c #7597B9",
+"v c #275D94",
+"w c #DCF2FB",
+"x c #D3EDF5",
+"y c #84A4C0",
+"z c #6B8DAF",
+"A c #3D71A5",
+"B c #DDF2FB",
+"C c #D4EEF6",
+"D c #D8EDF8",
+"E c #E1F4FD",
+"F c #DFF2FC",
+" ......... ",
+" .+@#$%&&*. ",
+" .=-;>,')!~. ",
+" .{]-;>,'^^^. ",
+" ./(]-;>,')&. ",
+" ._:(]-;>,'&. ",
+" .<[:(]-;>}| ",
+" .12[:(]-;3~4 ",
+" .562[7890ab~c ",
+" .de62fg1h~~~~i",
+" .jke6lmnopq~r ",
+" .stke62[:u~v ",
+" .wxtke62[yzA ",
+" .BCxtke62[D. ",
+" .EBwsjd51<F. ",
+" ............ "};
diff --git a/app/bin/bitmaps/document-exportdxf.xpm b/app/bin/bitmaps/document-exportdxf.xpm new file mode 100644 index 0000000..fc4071b --- /dev/null +++ b/app/bin/bitmaps/document-exportdxf.xpm @@ -0,0 +1,84 @@ +/* XPM */
+static char * export_dxf_xpm[] = {
+"16 16 65 1",
+" c None",
+". c #406C98",
+"+ c #DDF0FB",
+"@ c #D4E9F7",
+"# c #11CC22",
+"$ c #CEE4F4",
+"% c #CCE2F3",
+"& c #CCE1F2",
+"* c #A7C2DC",
+"= c #D6EBF7",
+"- c #C5DFEF",
+"; c #BCD6EA",
+"> c #B6D0E8",
+", c #B3CDE6",
+"' c #9AB6D2",
+") c #E5F6FF",
+"! c #D7ECF8",
+"~ c #C7E1EF",
+"{ c #C1DBED",
+"] c #85A4C2",
+"^ c #D8EEF8",
+"/ c #CAE4F1",
+"( c #D9EEF9",
+"_ c #CBE5F2",
+": c #C8E2F0",
+"< c #8FAFCF",
+"[ c #83A5C7",
+"} c #DAEFF9",
+"| c #CDE7F2",
+"1 c #81A3C5",
+"2 c #105293",
+"3 c #AFCCE0",
+"4 c #9AB9D4",
+"5 c #88A9C9",
+"6 c #7FA1C3",
+"7 c #CCE1F0",
+"8 c #155493",
+"9 c #DBF0FA",
+"0 c #D0EAF4",
+"a c #CFE8F3",
+"b c #D4EAF6",
+"c c #E1F3FD",
+"d c #195793",
+"e c #DBF1FA",
+"f c #D1EBF4",
+"g c #CEE8F3",
+"h c #C1DCEB",
+"i c #AFCBE0",
+"j c #98B7D1",
+"k c #84A4C4",
+"l c #799BBD",
+"m c #CBE0EF",
+"n c #1E5993",
+"o c #DCF1FA",
+"p c #D2ECF5",
+"q c #7597B9",
+"r c #275D94",
+"s c #84A4C0",
+"t c #6B8DAF",
+"u c #3D71A5",
+"v c #DDF2FB",
+"w c #D4EEF6",
+"x c #D8EDF8",
+"y c #E1F4FD",
+"z c #DFF2FC",
+" ......... ",
+" .+@#$%&#*. ",
+" .=-#;>,#'). ",
+" .!~#{;>#]]]. ",
+" .##########. ",
+" .^/#~-{#>,&. ",
+" .(_#:~-#;<[ ",
+" .}|#/:~#{1)2 ",
+" .#####34567)8 ",
+" .90#|ab}c))))d",
+" .ef#ghijklm)n ",
+" .op#0g|#/q)r ",
+" .########stu ",
+" .vw#pf0#|_x. ",
+" .yv#oe9#}(z. ",
+" ............ "};
diff --git a/app/bin/bitmaps/document-import.xpm b/app/bin/bitmaps/document-import.xpm new file mode 100644 index 0000000..28dc3c8 --- /dev/null +++ b/app/bin/bitmaps/document-import.xpm @@ -0,0 +1,92 @@ +/* XPM */
+static char * import_xpm[] = {
+"16 16 73 1",
+" c None",
+". c #406C98",
+"+ c #DDF0FB",
+"@ c #D4E9F7",
+"# c #D1E7F5",
+"$ c #CEE4F4",
+"% c #CCE2F3",
+"& c #CCE1F2",
+"* c #A7C2DC",
+"= c #D6EBF7",
+"- c #C5DFEF",
+"; c #C1DBED",
+"> c #BCD6EA",
+", c #B6D0E8",
+"' c #B3CDE6",
+") c #B2CCE5",
+"! c #9AB6D2",
+"~ c #E5F6FF",
+"{ c #D7ECF8",
+"] c #C7E1EF",
+"^ c #85A4C2",
+"/ c #D7EDF8",
+"( c #C8E2F0",
+"_ c #D8EEF8",
+": c #94B4D1",
+"< c #86A7C9",
+"[ c #AECBE1",
+"} c #D9EEF9",
+"| c #81A3C5",
+"1 c #E4F6FF",
+"2 c #93B2D0",
+"3 c #B6D2E6",
+"4 c #155493",
+"5 c #7FA1C3",
+"6 c #CBE1F0",
+"7 c #DEF2FC",
+"8 c #A5C3DA",
+"9 c #BED9EA",
+"0 c #195793",
+"a c #DFF2FC",
+"b c #CFE7F4",
+"c c #1E5993",
+"d c #799BBD",
+"e c #CAE0EF",
+"f c #A4C2D9",
+"g c #C0DBEB",
+"h c #D4EAF7",
+"i c #DBF1FA",
+"j c #7597B9",
+"k c #8BABC7",
+"l c #B8D4E6",
+"m c #CBE5F2",
+"n c #CAE4F1",
+"o c #D5EBF7",
+"p c #DCF1FA",
+"q c #86A6C1",
+"r c #6F91B2",
+"s c #ACC9DC",
+"t c #CEE8F3",
+"u c #CDE7F2",
+"v c #D6ECF7",
+"w c #DCF2FB",
+"x c #D3EDF5",
+"y c #D2ECF5",
+"z c #D1EBF4",
+"A c #D0EAF4",
+"B c #DDF2FB",
+"C c #D4EEF6",
+"D c #D8EDF8",
+"E c #E1F4FD",
+"F c #DBF0FA",
+"G c #DAF0F9",
+"H c #DAEFF9",
+" ......... ",
+" .+@#$%&&* ",
+" .=-;>,')!~ ",
+" .{]-;>,'^^^. ",
+" ./(]-;>,')&. ",
+" ._:<[-;>,'&. ",
+" .}|123-;>,%. ",
+" 44556789-;>$. ",
+"0~~~~1a/b]-;#. ",
+" ccddeafg(]-h. ",
+" .ij1klmn(]o. ",
+" .pqrstumn(v. ",
+" .wxyzAtumn{. ",
+" .BCxyzAtumD. ",
+" .EBwpiFGH}a. ",
+" ............ "};
diff --git a/app/bin/bitmaps/document-importmod.xpm b/app/bin/bitmaps/document-importmod.xpm new file mode 100644 index 0000000..d0efd02 --- /dev/null +++ b/app/bin/bitmaps/document-importmod.xpm @@ -0,0 +1,71 @@ +/* XPM */ +static char *importmod_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 49 1 ", +" c #27795F", +". c #305173", +"X c #1A6878", +"o c #07900F", +"O c #0E8E14", +"+ c #0B9C17", +"@ c #10971E", +"# c #0BA619", +"$ c #10A51D", +"% c #0DB61C", +"& c #159E22", +"* c #209E2D", +"= c #18A727", +"- c #16B627", +"; c #27AB35", +": c #30AF3B", +"> c #2AB437", +", c #31B63E", +"< c #36BD46", +"1 c #3CC44C", +"2 c #40C94E", +"3 c #44CB54", +"4 c #54DB64", +"5 c #195793", +"6 c #3B6D8D", +"7 c #39798B", +"8 c #3F6E9C", +"9 c #377C97", +"0 c #3D77A6", +"q c #3F7FBC", +"w c #37878B", +"e c #38938E", +"r c #378399", +"t c #3983A7", +"y c #6F91B2", +"u c #789ABC", +"i c #7FA1C3", +"p c #86A6C4", +"a c #96B4D1", +"s c #A7C4DB", +"d c #AECBE1", +"f c #B9D5E7", +"g c #C0DBEB", +"h c #C9E1EF", +"j c #CDE4F2", +"k c #D7EDF8", +"l c #DFF2FC", +"z c #E5F6FF", +"x c None", +/* pixels */ +"xxqqqqqqqqqxxxxx", +"xxt3111;<>sqxxxx", +"xxq1<<:O;<a;qxxx", +"xxq<;;&x=2pppqxx", +"xxq===$o+;>#xxxx", +"xxq=aid=$=,1>txx", +"xxq=ilaf->44>txx", +"x5qiijlsg-31=0xx", +"5zzzzzzkjh1,#rxx", +"x5Xuuhlsf1111exx", +"xxw<uzpf211;:exx", +"xx9;pys1<<;$+9xx", +"xx0@&@=<;;=%#9xx", +"xx8;<;;===$##7xx", +"xx8*<<==+@++#7xx", +"xx.677776667w xx" +}; diff --git a/app/bin/bitmaps/dpolyline.xpm b/app/bin/bitmaps/dpolyline.xpm new file mode 100644 index 0000000..7f01bda --- /dev/null +++ b/app/bin/bitmaps/dpolyline.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char * dpolyline_xpm[] = { +"16 16 3 1", +"X c None", +" c #FFFF00000000", +". c #000000000000", +"XXXXXXXXXXXXXXXX", +"XXXXXXX .... XXX", +"XXXXXXXXXX..XXXX", +"XXXXXXXXX.XXXXXX", +"XXXXXXX..XXXXXXX", +"XXXXXX.XXXXXXXXX", +"XXXX..XXXXXXXXXX", +"XXX ...XXXXXXXXX", +"XXXXXXX......XXX", +" XXXXXXXXXXXX.. ", +"X.XXXXXXXXXXXX.X", +"X.XXXXXXXXXX..XX", +"XX.XXXXXXXX.XXXX", +"XXX.XXXXXX.XXXXX", +"XXX.XXXX..XXXXXX", +"XXXX .. XXXXXXXX"}; + diff --git a/app/bin/bitmaps/export.xpm b/app/bin/bitmaps/export.xpm deleted file mode 100644 index f6bc7d3..0000000 --- a/app/bin/bitmaps/export.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static char * export_xpm[] = { -"16 16 2 1", -" c None", -". c #000000000000", -" .........", -" . .", -" . . .", -" . . .", -"...... . .", -" .. .", -" .. .", -"...... . .", -" . . .. .", -" . .. . ..", -" . .. ", -" ", -" . . ... .", -" . . .", -" . . . . .", -" "}; diff --git a/app/bin/bitmaps/flash.xbm b/app/bin/bitmaps/flash.xbm index 677978d..d135b2f 100644 --- a/app/bin/bitmaps/flash.xbm +++ b/app/bin/bitmaps/flash.xbm @@ -1,6 +1,6 @@ #define flash_width 24 #define flash_height 24 -static char flash_bits[] = { +static unsigned char flash_bits[] = { 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x08, 0x04, 0x02, 0x10, 0x04, 0x01, 0x20, 0x84, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf5, 0x1f, 0x00, 0x00, 0x00, diff --git a/app/bin/bitmaps/greendot.xpm b/app/bin/bitmaps/greendot.xpm new file mode 100644 index 0000000..8c44035 --- /dev/null +++ b/app/bin/bitmaps/greendot.xpm @@ -0,0 +1,23 @@ +/* XPM */
+static char * greendot[] = {
+"16 16 4 1",
+" c None",
+". c #000000",
+"+ c #4E9A06",
+"@ c #59A51A",
+" ",
+" ",
+" .... ",
+" ..++++.. ",
+" .+@@@++++. ",
+" .@@@@@+++. ",
+" .+@@@@@++++. ",
+" .+@@@@@++++. ",
+" .++@@@+++++. ",
+" .++++++++++. ",
+" .++++++++. ",
+" .++++++++. ",
+" ..++++.. ",
+" .... ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/greenstar.xpm b/app/bin/bitmaps/greenstar.xpm new file mode 100644 index 0000000..b83a4b9 --- /dev/null +++ b/app/bin/bitmaps/greenstar.xpm @@ -0,0 +1,69 @@ +/* XPM */
+static char * greenstar[] = {
+"16 16 50 1",
+" c None",
+". c #264706",
+"+ c #274906",
+"@ c #346408",
+"# c #386C09",
+"$ c #478A0D",
+"% c #46880C",
+"& c #224007",
+"* c #131D0A",
+"= c #234207",
+"- c #274B06",
+"; c #2D5306",
+"> c #305A07",
+", c #3A700A",
+"' c #4D960E",
+") c #4A900D",
+"! c #356508",
+"~ c #264806",
+"{ c #203B07",
+"] c #1C3508",
+"^ c #203C07",
+"/ c #42800C",
+"( c #478B0D",
+"_ c #529E0F",
+": c #4C940E",
+"< c #46890D",
+"[ c #417E0B",
+"} c #3C730A",
+"| c #1B3208",
+"1 c #346208",
+"2 c #4B920E",
+"3 c #498F0D",
+"4 c #45850C",
+"5 c #407C0B",
+"6 c #315B07",
+"7 c #336108",
+"8 c #44840C",
+"9 c #2E5507",
+"0 c #3F7A0B",
+"a c #3F790B",
+"b c #3C740A",
+"c c #2B5106",
+"d c #1F3808",
+"e c #386B09",
+"f c #234107",
+"g c #2A4F06",
+"h c #182C09",
+"i c #2E5707",
+"j c #1A3008",
+"k c #172B09",
+" ",
+" ",
+" ",
+" .+ ",
+" @# ",
+" $%& ",
+" *=-;>,')!~={] ",
+" ^#/('_:<[}@| ",
+" 1%)23456 ",
+" 74%8[9 ",
+" ,05abc ",
+" deef;e1 ",
+" &gh di| ",
+" j k ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/greydot.xpm b/app/bin/bitmaps/greydot.xpm new file mode 100644 index 0000000..771a096 --- /dev/null +++ b/app/bin/bitmaps/greydot.xpm @@ -0,0 +1,25 @@ +/* XPM */
+static char * greydot[] = {
+"16 16 6 1",
+" c None",
+". c #000000",
+"+ c #30312F",
+"@ c #959792",
+"# c #888A85",
+"$ c #A2A49F",
+" ",
+" ",
+" .... ",
+" .+@@@@+. ",
+" .#$$$@@@#. ",
+" +$$$$$@@@+ ",
+" .@$$$$$@@@@. ",
+" .@$$$$$@@@@. ",
+" .@@$$$@@@@@. ",
+" .@@@@@@@@@@. ",
+" +@@@@@@@@+ ",
+" .#@@@@@@#. ",
+" .+@@@@+. ",
+" .... ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/greystar.xpm b/app/bin/bitmaps/greystar.xpm new file mode 100644 index 0000000..e7c5300 --- /dev/null +++ b/app/bin/bitmaps/greystar.xpm @@ -0,0 +1,69 @@ +/* XPM */
+static char * greystar[] = {
+"16 16 50 1",
+" c None",
+". c #5A5B57",
+"+ c #5B5D59",
+"@ c #6D6F6A",
+"# c #73756F",
+"$ c #878984",
+"% c #868882",
+"& c #555652",
+"* c #3D3F3C",
+"= c #565854",
+"- c #5C5E59",
+"; c #62645F",
+"> c #676964",
+", c #757772",
+"' c #8F918C",
+") c #8B8D88",
+"! c #6E706A",
+"~ c #5A5C58",
+"{ c #51534F",
+"] c #4D4F4B",
+"^ c #525450",
+"/ c #81837D",
+"( c #888A84",
+"_ c #959792",
+": c #8E908A",
+"< c #868983",
+"[ c #7F817B",
+"} c #787A74",
+"| c #4C4D49",
+"1 c #6C6E69",
+"2 c #8D8F8A",
+"3 c #8B8D87",
+"4 c #848680",
+"5 c #7D807A",
+"6 c #686A65",
+"7 c #6B6D68",
+"8 c #83857F",
+"9 c #646561",
+"0 c #7D7F79",
+"a c #7C7E78",
+"b c #787B75",
+"c c #60625D",
+"d c #50514D",
+"e c #72746E",
+"f c #565753",
+"g c #5F615D",
+"h c #474945",
+"i c #646661",
+"j c #4A4B48",
+"k c #474844",
+" ",
+" ",
+" ",
+" .+ ",
+" @# ",
+" $%& ",
+" *=-;>,')!~={] ",
+" ^#/('_:<[}@| ",
+" 1%)23456 ",
+" 74%8[9 ",
+" ,05abc ",
+" deef;e1 ",
+" &gh di| ",
+" j k ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/import.xpm b/app/bin/bitmaps/import.xpm deleted file mode 100644 index f048333..0000000 --- a/app/bin/bitmaps/import.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static char * import_xpm[] = { -"16 16 2 1", -" c None", -". c #FFFFFFFFFFFF", -" .......", -" ....... .......", -" ....... ... ...", -" ....... .... ..", -" ....... . .", -" ....... ...... ", -" ....... ...... ", -" ....... . .", -" . .... .... ..", -" .. .. ... ...", -" .... .........", -"................", -".. . . . .....", -"... ... .. .....", -" . . .. .. .....", -"................"}; diff --git a/app/bin/bitmaps/joinline.xpm b/app/bin/bitmaps/joinline.xpm new file mode 100644 index 0000000..06e22f8 --- /dev/null +++ b/app/bin/bitmaps/joinline.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * joinline_xpm[] = { +"16 16 3 1", +" c None", +". c #000000000000", +"X c #FFFF00000000", +" ", +" ", +" ", +" .", +" ..", +" ...", +" ... ", +" ... ", +" XXX ", +" X X ", +" X X X ", +".....X X ", +".....XXXX ", +"..... X ", +" X ", +" "};
\ No newline at end of file diff --git a/app/bin/bitmaps/link.xbm b/app/bin/bitmaps/link.xbm new file mode 100644 index 0000000..199256e --- /dev/null +++ b/app/bin/bitmaps/link.xbm @@ -0,0 +1,6 @@ +#define link_width 16 +#define link_height 16 +static unsigned char link_bits[] = { + 0xff, 0x03, 0x01, 0x06, 0x01, 0x0a, 0x01, 0x12, 0x01, 0x22, 0x01, 0x7e, + 0x01, 0x40, 0x01, 0x40, 0x3d, 0x5e, 0x43, 0x61, 0xf3, 0x67, 0x43, 0x61, + 0x3d, 0x5e, 0x01, 0x40, 0x01, 0x40, 0xff, 0x7f }; diff --git a/app/bin/bitmaps/magnet.xpm b/app/bin/bitmaps/magnet.xpm new file mode 100644 index 0000000..99a31db --- /dev/null +++ b/app/bin/bitmaps/magnet.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * magnet_xpm[] = { +"16 16 3 1", +" c #FF0000", +". c None", +"X c #FFFF00", +"................", +"........ ......", +"....... ....", +"...... ...", +"..... ..", +"..... . .", +".... ... .", +"... ... .", +"..XXX ... ..", +".XXXXX... ..", +"..XXXX.. ...", +"...XX..XX ....", +"......XXXXX ....", +"......XXXXX.....", +"........XX......", +"................"}; diff --git a/app/bin/bitmaps/magnifier.xpm b/app/bin/bitmaps/magnifier.xpm new file mode 100644 index 0000000..69a3faa --- /dev/null +++ b/app/bin/bitmaps/magnifier.xpm @@ -0,0 +1,89 @@ +/* XPM */
+static char * magnifier_xpm[] = {
+"16 16 70 1",
+" c None",
+". c #545454",
+"+ c #555555",
+"@ c #515151",
+"# c #5E6063",
+"$ c #94A3B1",
+"% c #C5D5E6",
+"& c #DFEAF4",
+"* c #D9E3ED",
+"= c #A2ACB6",
+"- c #4D4D4D",
+"; c #5A5D5F",
+"> c #AEC1D5",
+", c #C4D8EB",
+"' c #E2ECF6",
+") c #E4EDF6",
+"! c #B8C8D9",
+"~ c #5B5D60",
+"{ c #494949",
+"] c #919FAD",
+"^ c #BBD2E8",
+"/ c #D5E3F1",
+"( c #D6E4F2",
+"_ c #97A4B0",
+": c #434343",
+"< c #B6CBE0",
+"[ c #C1D3E4",
+"} c #3E3E3E",
+"| c #BED4E9",
+"1 c #C8DBED",
+"2 c #383838",
+"3 c #BCCFE1",
+"4 c #CAD8E7",
+"5 c #313131",
+"6 c #939DA8",
+"7 c #BFD5EA",
+"8 c #DFE9F5",
+"9 c #9EA6AD",
+"0 c #373737",
+"a c #444647",
+"b c #C4D1DE",
+"c c #D9E6F3",
+"d c #E6EFF7",
+"e c #D3D9DF",
+"f c #3B3C3D",
+"g c #262626",
+"h c #3B3B3B",
+"i c #3C3C3C",
+"j c #ADADAF",
+"k c #28292B",
+"l c #91979D",
+"m c #E3E8EE",
+"n c #EDF3F9",
+"o c #E5EAEF",
+"p c #9EA0A3",
+"q c #282829",
+"r c #464647",
+"s c #B8B8BC",
+"t c #151516",
+"u c #141414",
+"v c #3D3D3D",
+"w c #515153",
+"x c #C4C4CC",
+"y c #212122",
+"z c #606064",
+"A c #D1D1DD",
+"B c #2E2E30",
+"C c #DADAEA",
+"D c #3F3F43",
+"E c #151515",
+" .+++++. ",
+" @#$%&*=#@ ",
+" -;>,'))'!~-",
+" {]^/))))(_{",
+" :<^^^^^^^[:",
+" }|^^)))))1}",
+" 23^))))))42",
+" 5678))))'95",
+" 0abc)))defg",
+" hijklmnopq ",
+" irst uuuuu ",
+" vwxy ",
+" }zAB ",
+" 0CD ",
+" Eu ",
+" "};
diff --git a/app/bin/bitmaps/note.xbm b/app/bin/bitmaps/note.xbm index 7ca281a..3d2cac9 100644 --- a/app/bin/bitmaps/note.xbm +++ b/app/bin/bitmaps/note.xbm @@ -1,6 +1,6 @@ #define note_width 16 #define note_height 16 -static char note_bits[] = { - 0xff, 0x03, 0x01, 0x06, 0x81, 0x0a, 0x81, 0x12, 0x81, 0x22, 0x81, 0x7e, - 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x01, 0x40, - 0x81, 0x40, 0x01, 0x40, 0x01, 0x40, 0xff, 0x7f}; +static unsigned char note_bits[] = { + 0xff, 0x03, 0x01, 0x06, 0x01, 0x0a, 0x01, 0x12, 0x01, 0x22, 0x01, 0x7e, + 0x01, 0x40, 0xbd, 0x43, 0x01, 0x40, 0x01, 0x40, 0xfd, 0x5e, 0x01, 0x40, + 0x01, 0x40, 0xbd, 0x4f, 0x01, 0x40, 0xff, 0x7f }; diff --git a/app/bin/bitmaps/pan.xpm b/app/bin/bitmaps/pan.xpm index 8782714..9575ec5 100644 --- a/app/bin/bitmaps/pan.xpm +++ b/app/bin/bitmaps/pan.xpm @@ -14,7 +14,7 @@ static char * pan_xpm[] = { " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XX XX XX ", -" XX ", +" XX ", " XX XX XX ", " XXXXXX ", " XXXX ", diff --git a/app/bin/bitmaps/parallel-line.xpm b/app/bin/bitmaps/parallel-line.xpm new file mode 100644 index 0000000..4ac471d --- /dev/null +++ b/app/bin/bitmaps/parallel-line.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * parallel_line_xpm[] = { +"16 16 3 1", +" c None", +". c #000000000000", +"X c #FFFF00000000", +" ", +" ", +" ", +"................", +" X ", +" X X ", +" X X ", +" ", +" ", +" . . . ", +"................", +" . . . ", +" . . . ", +" . . . ", +"................", +" . . . "}; diff --git a/app/bin/bitmaps/parallel.xpm b/app/bin/bitmaps/parallel.xpm index 3fe5591..eb816dc 100644 --- a/app/bin/bitmaps/parallel.xpm +++ b/app/bin/bitmaps/parallel.xpm @@ -1,15 +1,16 @@ /* XPM */ static char * parallel_xpm[] = { -"16 16 2 1", +"16 16 3 1", " c None", ". c #000000000000", -" ", -" ", -" ", +"X c #FFFF00000000", +"................", +" . . . ", +" . . . ", "................", -" . ", -" . . ", -" . . ", +" . X . ", +" X X ", +" X X ", " ", " ", " . . . ", diff --git a/app/bin/bitmaps/reddot.xpm b/app/bin/bitmaps/reddot.xpm new file mode 100644 index 0000000..14529bf --- /dev/null +++ b/app/bin/bitmaps/reddot.xpm @@ -0,0 +1,26 @@ +/* XPM */
+static char * reddot[] = {
+"16 16 7 1",
+" c None",
+". c #000000",
+"+ c #CC0000",
+"@ c #CA1F1E",
+"# c #E62E16",
+"$ c #C04E4B",
+"% c #B25F5B",
+" ",
+" ",
+" .... ",
+" ..$@@$.. ",
+" .%###+++%. ",
+" .#####+++. ",
+" .$#####+++$. ",
+" .@#####+++@. ",
+" .@+###++++@. ",
+" .$++++++++$. ",
+" .++++++++. ",
+" .%++++++%. ",
+" ..$@@$.. ",
+" .... ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/redstar.xpm b/app/bin/bitmaps/redstar.xpm new file mode 100644 index 0000000..b9f51f9 --- /dev/null +++ b/app/bin/bitmaps/redstar.xpm @@ -0,0 +1,67 @@ +/* XPM */
+static char * redstar[] = {
+"16 16 48 1",
+" c None",
+". c #950800",
+"+ c #980800",
+"@ c #B50A00",
+"# c #BF0A00",
+"$ c #E00C00",
+"% c #DE0C00",
+"& c #8D0800",
+"* c #670600",
+"= c #900800",
+"- c #990800",
+"; c #A30900",
+"> c #AC0900",
+", c #C30B00",
+"' c #ED0D00",
+") c #E70C00",
+"! c #B70A00",
+"~ c #960800",
+"{ c #870700",
+"] c #810700",
+"^ c #890700",
+"/ c #D60C00",
+"( c #E20C00",
+"_ c #F70D00",
+": c #EC0D00",
+"< c #D30B00",
+"[ c #C70B00",
+"} c #7E0700",
+"| c #B40A00",
+"1 c #EA0D00",
+"2 c #DB0C00",
+"3 c #D10B00",
+"4 c #AD0900",
+"5 c #B20A00",
+"6 c #D90C00",
+"7 c #A50900",
+"8 c #D00B00",
+"9 c #CE0B00",
+"0 c #C90B00",
+"a c #A00900",
+"b c #850700",
+"c c #BE0A00",
+"d c #8E0800",
+"e c #9E0900",
+"f c #770600",
+"g c #A70900",
+"h c #7B0700",
+"i c #760600",
+" ",
+" ",
+" ",
+" .+ ",
+" @# ",
+" $%& ",
+" *=-;>,')!~={] ",
+" ^#/('_:$<[@} ",
+" |%)1)234 ",
+" 52%6<7 ",
+" ,8390a ",
+" bccd;c| ",
+" &ef bg} ",
+" h i ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/sticky-note-chain.xpm b/app/bin/bitmaps/sticky-note-chain.xpm new file mode 100644 index 0000000..aa9445a --- /dev/null +++ b/app/bin/bitmaps/sticky-note-chain.xpm @@ -0,0 +1,84 @@ +/* XPM */
+static char * sticky_note_chain_bits[] = {
+"16 16 65 1",
+" c None",
+". c #CCB301",
+"+ c #CAB101",
+"@ c #FBEF9C",
+"# c #F9EB8F",
+"$ c #F8EA8D",
+"% c #F8E98A",
+"& c #F6E785",
+"* c #F3E37C",
+"= c #F0E074",
+"- c #EEDD6F",
+"; c #D5C44D",
+"> c #C8AF01",
+", c #FBED95",
+"' c #F7E67E",
+") c #F6E57C",
+"! c #F5E47B",
+"~ c #F4E379",
+"{ c #F1E075",
+"] c #ECDB70",
+"^ c #E8D76A",
+"/ c #E6D567",
+"( c #CDBC45",
+"_ c #FFF6BB",
+": c #C6AD01",
+"< c #FCEB84",
+"[ c #B7A73A",
+"} c #BFAE37",
+"| c #AC9401",
+"1 c #C3AA01",
+"2 c #FBED97",
+"3 c #EEDD7B",
+"4 c #9D96F6",
+"5 c #E1D26F",
+"6 c #C0A701",
+"7 c #006E6E",
+"8 c #00FFFF",
+"9 c #BCA401",
+"0 c #AFA358",
+"a c #ADA054",
+"b c #B9A101",
+"c c #B59E01",
+"d c #FEF19E",
+"e c #EDDD7C",
+"f c #E5D575",
+"g c #E5D571",
+"h c #B29A01",
+"i c #FFF2A1",
+"j c #FEED87",
+"k c #FDEC86",
+"l c #FDEC85",
+"m c #FBEA82",
+"n c #FAE981",
+"o c #F8E77F",
+"p c #A89100",
+"q c #FFF4AF",
+"r c #FFF1A0",
+"s c #FDF09C",
+"t c #FDEF9B",
+"u c #FCEE99",
+"v c #FAEC92",
+"w c #F9EA90",
+"x c #FAEC96",
+"y c #9D8600",
+"z c #9C8500",
+" ",
+" ",
+" ........... ",
+" +@#$%&*=--;+ ",
+" >,')!~{]^/(_> ",
+" :<<<<<<<<<[}}| ",
+" 1234445444''-1 ",
+" 647887478874-6 ",
+" 94800878a084=9 ",
+" b47887478874*b ",
+" cde444f444g{&c ",
+" hijkl<mno')!%h ",
+" pqirdstu2,vwxp ",
+" yzzzzzzzzzzzzy ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/sticky-note-clip.xpm b/app/bin/bitmaps/sticky-note-clip.xpm new file mode 100644 index 0000000..c74c64d --- /dev/null +++ b/app/bin/bitmaps/sticky-note-clip.xpm @@ -0,0 +1,99 @@ +/* XPM */
+static char * sticky_note_clip_bits[] = {
+"16 16 80 1",
+" c None",
+". c #CCB301",
+"+ c #CAB101",
+"@ c #FBEF9C",
+"# c #F9EB8F",
+"$ c #F8EA8D",
+"% c #F8E98A",
+"& c #F7E992",
+"* c #EDE1A3",
+"= c #555753",
+"- c #DFCF67",
+"; c #D5C44D",
+"> c #C8AF01",
+", c #FBED95",
+"' c #F7E67E",
+") c #F6E57C",
+"! c #F6E68A",
+"~ c #ECE0A0",
+"{ c #BABDB6",
+"] c #EFE3A7",
+"^ c #CDBC45",
+"/ c #FFF6BB",
+"( c #C6AD01",
+"_ c #FBED97",
+": c #F8E77F",
+"< c #F8E88D",
+"[ c #EDE0A0",
+"} c #F5E68F",
+"| c #F0E39B",
+"1 c #888A85",
+"2 c #BFAE37",
+"3 c #AC9401",
+"4 c #C3AA01",
+"5 c #FCEE99",
+"6 c #F7E78B",
+"7 c #EBDE9C",
+"8 c #F8EBA2",
+"9 c #ECDB70",
+"0 c #E8D76A",
+"a c #E6D567",
+"b c #EEDD6F",
+"c c #C0A701",
+"d c #FDF0A5",
+"e c #DCD695",
+"f c #EAE29B",
+"g c #E8E098",
+"h c #DACB69",
+"i c #BCA401",
+"j c #FDF3B6",
+"k c #B9A101",
+"l c #FEF4B7",
+"m c #E0D986",
+"n c #F5E47B",
+"o c #F4E379",
+"p c #F1E075",
+"q c #F3E37C",
+"r c #B59E01",
+"s c #FFF3B4",
+"t c #DECF6F",
+"u c #F4E47D",
+"v c #F5E47C",
+"w c #F6E785",
+"x c #B29A01",
+"y c #FFF2A3",
+"z c #FBEDA4",
+"A c #F0E07C",
+"B c #F3E27C",
+"C c #F5E47D",
+"D c #A89100",
+"E c #FFF4AF",
+"F c #FFF2A1",
+"G c #FFF1A0",
+"H c #FEF19E",
+"I c #FDF09C",
+"J c #FDEF9B",
+"K c #FAEC92",
+"L c #F9EA90",
+"M c #FAEC96",
+"N c #9D8600",
+"O c #9C8500",
+" ",
+" ",
+" ........... ",
+" +@#$%&*==-;+ ",
+" >,')!~={]=^/> ",
+" (_:<[=}=|1{223 ",
+" 4567=8=8=90ab4 ",
+" cde=f=g=}h90bc ",
+" ij1818=8={)))i ",
+" kl=m=1f={nopqk ",
+" rs1t)8={uvnowr ",
+" xyz1=1{ABC)n%x ",
+" DEFGHIJ5_,KLMD ",
+" NOOOOOOOOOOOON ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/sticky-note-text.xpm b/app/bin/bitmaps/sticky-note-text.xpm new file mode 100644 index 0000000..119f39b --- /dev/null +++ b/app/bin/bitmaps/sticky-note-text.xpm @@ -0,0 +1,86 @@ +/* XPM */
+static char * sticky_note_text_bits[] = {
+"16 16 67 1",
+" c None",
+". c #CCB301",
+"+ c #CAB101",
+"@ c #FBEF9C",
+"# c #F9EB8F",
+"$ c #F8EA8D",
+"% c #F8E98A",
+"& c #F6E785",
+"* c #F3E37C",
+"= c #F0E074",
+"- c #EEDD6F",
+"; c #D5C44D",
+"> c #C8AF01",
+", c #FBED95",
+"' c #F7E67E",
+") c #F6E57C",
+"! c #F5E47B",
+"~ c #F4E379",
+"{ c #F1E075",
+"] c #ECDB70",
+"^ c #E8D76A",
+"/ c #E6D567",
+"( c #CDBC45",
+"_ c #FFF6BB",
+": c #C6AD01",
+"< c #FBED97",
+"[ c #F8E77F",
+"} c #BFAE37",
+"| c #AC9401",
+"1 c #C3AA01",
+"2 c #FCEE99",
+"3 c #7E7E7E",
+"4 c #979797",
+"5 c #C0A701",
+"6 c #FDEF9B",
+"7 c #E5DC75",
+"8 c #E4DB73",
+"9 c #E4DA70",
+"0 c #E3D86D",
+"a c #E2D769",
+"b c #EBDC70",
+"c c #BCA401",
+"d c #FDF09D",
+"e c #B9A101",
+"f c #FEF19E",
+"g c #E5DD77",
+"h c #EDDF75",
+"i c #B59E01",
+"j c #FFF1A0",
+"k c #DED273",
+"l c #E1D078",
+"m c #B29A01",
+"n c #FFF2A1",
+"o c #FEED87",
+"p c #FDEC86",
+"q c #FDEC85",
+"r c #FCEB84",
+"s c #FBEA82",
+"t c #FAE981",
+"u c #A89100",
+"v c #FFF4AF",
+"w c #FDF09C",
+"x c #FAEC92",
+"y c #F9EA90",
+"z c #FAEC96",
+"A c #9D8600",
+"B c #9C8500",
+" ",
+" ",
+" ........... ",
+" +@#$%&*=--;+ ",
+" >,')!~{]^/(_> ",
+" :<[')!~{]^}}}| ",
+" 12334344{]^/-1 ",
+" 567890ab~{]^-5 ",
+" cd3334333443=c ",
+" efgg789h)!~{*e ",
+" ij3343kl')!~&i ",
+" mnopqrst[')!%m ",
+" uvnjfw62<,xyzu ",
+" ABBBBBBBBBBBBA ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/tunnel.xpm b/app/bin/bitmaps/tunnel.xpm index 79aed20..449080e 100644 --- a/app/bin/bitmaps/tunnel.xpm +++ b/app/bin/bitmaps/tunnel.xpm @@ -1,19 +1,20 @@ /* XPM */ static char * tunnel_xpm[] = { -"16 16 2 1", +"16 16 3 1", " c None", -". c #000000000000", +". c #00FFFF", +"+ c #000000", " .. ", " .. ", " .. ", " .. ", -". . .. ", -".......... . . ", -". . .. ", -". . .. ", -". . .. ", -".......... . . ", -". . .. ", +"+ + .. ", +"++++++++.. + + ", +"+ + .. ", +"+ + .. ", +"+ + .. ", +"++++++++.. + + ", +"+ + .. ", " .. ", " .. ", " .. ", diff --git a/app/bin/bitmaps/yellowdot.xpm b/app/bin/bitmaps/yellowdot.xpm new file mode 100644 index 0000000..da0dddf --- /dev/null +++ b/app/bin/bitmaps/yellowdot.xpm @@ -0,0 +1,27 @@ +/* XPM */
+static char * yellowdot[] = {
+"16 16 8 1",
+" c None",
+". c #000000",
+"+ c #B69A19",
+"@ c #E0C504",
+"# c #EBD200",
+"$ c #CFB410",
+"% c #EFD947",
+"& c #EDD400",
+" ",
+" ",
+" .... ",
+" .+@##@+. ",
+" .$%%%&&&$. ",
+" +%%%%%&&&+ ",
+" .@%%%%%&&&@. ",
+" .#%%%%%&&&#. ",
+" .#&%%%&&&&#. ",
+" .@&&&&&&&&@. ",
+" +&&&&&&&&+ ",
+" .$&&&&&&$. ",
+" .+@##@+. ",
+" .... ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/yellowstar.xpm b/app/bin/bitmaps/yellowstar.xpm new file mode 100644 index 0000000..637ad9c --- /dev/null +++ b/app/bin/bitmaps/yellowstar.xpm @@ -0,0 +1,67 @@ +/* XPM */
+static char * yellowstar[] = {
+"16 16 48 1",
+" c None",
+". c #AB9600",
+"+ c #AE9900",
+"@ c #D0B600",
+"# c #DBC000",
+"$ c #FFDF02",
+"% c #FFDF00",
+"& c #A28D00",
+"* c #766700",
+"= c #A59000",
+"- c #B09A00",
+"; c #BBA400",
+"> c #C5AC00",
+", c #DFC300",
+"' c #FFE111",
+") c #FFE00A",
+"! c #D2B800",
+"~ c #AC9700",
+"{ c #9B8800",
+"] c #948100",
+"^ c #9D8A00",
+"/ c #F6D700",
+"( c #FFE004",
+"_ c #FFE31D",
+": c #FFE10F",
+"< c #F2D400",
+"[ c #E5C800",
+"} c #917F00",
+"| c #CEB500",
+"1 c #FFE10E",
+"2 c #FCDC00",
+"3 c #F0D200",
+"4 c #C7AE00",
+"5 c #CCB300",
+"6 c #FADB00",
+"7 c #BEA600",
+"8 c #EED100",
+"9 c #ECCF00",
+"0 c #E6CA00",
+"a c #B8A100",
+"b c #988500",
+"c c #DABE00",
+"d c #A38F00",
+"e c #B69F00",
+"f c #897800",
+"g c #BFA700",
+"h c #8D7B00",
+"i c #877600",
+" ",
+" ",
+" ",
+" .+ ",
+" @# ",
+" $%& ",
+" *=-;>,')!~={] ",
+" ^#/('_:$<[@} ",
+" |%)1)234 ",
+" 52%6<7 ",
+" ,8390a ",
+" bccd;c| ",
+" &ef bg} ",
+" h i ",
+" ",
+" "};
diff --git a/app/bin/cJSON.c b/app/bin/cJSON.c new file mode 100755 index 0000000..1733811 --- /dev/null +++ b/app/bin/cJSON.c @@ -0,0 +1,2932 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <limits.h> +#include <ctype.h> + +#ifdef ENABLE_LOCALES +#include <locale.h> +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 8) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occured */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((len < 0) || (buf == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buf; + p.length = (size_t)len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* faile to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) + { + return false; + } + + child = array->child; + + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + } + else + { + /* append to the end */ + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return; + } + + add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return; + } + + add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + add_item_to_array(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (parent->child == item) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + unsigned char *into = (unsigned char*)json; + + if (json == NULL) + { + return; + } + + while (*json) + { + if (*json == ' ') + { + json++; + } + else if (*json == '\t') + { + /* Whitespace characters. */ + json++; + } + else if (*json == '\r') + { + json++; + } + else if (*json=='\n') + { + json++; + } + else if ((*json == '/') && (json[1] == '/')) + { + /* double-slash comments, to end of line. */ + while (*json && (*json != '\n')) + { + json++; + } + } + else if ((*json == '/') && (json[1] == '*')) + { + /* multiline comments. */ + while (*json && !((*json == '*') && (json[1] == '/'))) + { + json++; + } + json += 2; + } + else if (*json == '\"') + { + /* string literals, which are \" sensitive. */ + *into++ = (unsigned char)*json++; + while (*json && (*json != '\"')) + { + if (*json == '\\') + { + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + else + { + /* All other characters. */ + *into++ = (unsigned char)*json++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/app/bin/cJSON.h b/app/bin/cJSON.h new file mode 100755 index 0000000..8d45390 --- /dev/null +++ b/app/bin/cJSON.h @@ -0,0 +1,285 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 8 + +#include <stddef.h> + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/bin/cbezier.c b/app/bin/cbezier.c index b91a81e..7f90a27 100644 --- a/app/bin/cbezier.c +++ b/app/bin/cbezier.c @@ -104,7 +104,8 @@ static struct { DIST_T trackGauge; } Da; - +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) /** * Draw a ControlArm. @@ -233,17 +234,16 @@ double BezErrorLine(coOrd pos[4], coOrd start_point, coOrd end_point, double sta /* * Add element to DYNARR pointed to by caller from segment handed in */ -void addSegBezier(dynArr_t * const array_p, trkSeg_p seg) { +void addSegBezier(dynArr_t * 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); + 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) { @@ -394,15 +394,15 @@ EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawC 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); + curr_good = (error <= errorThreshold/4); + //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); + curr_good = (error <= errorThreshold/4); }; done = prev_good && !curr_good; //Was better than this last time? @@ -449,7 +449,7 @@ EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawC curveSeg.width = track?0:width; if ( prev_arc.curveData.type == curveTypeCurve ) { if (track) - curveSeg.color = (fabs(prev_arc.curveData.curveRadius)<(GetLayoutMinTrackRadius()-EPSILON))?wDrawColorRed:wDrawColorBlack; + curveSeg.color = (fabs(prev_arc.curveData.curveRadius)<(GetLayoutMinTrackRadius()-EPSILON))?exceptionColor:normalColor; else curveSeg.color = color; curveSeg.type = track?SEG_CRVTRK:SEG_CRVLIN; @@ -466,7 +466,7 @@ EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawC curveSeg.color = wDrawColorBlack; else curveSeg.color = color; - curveSeg.u.l.angle = prev_arc.curveData.a1; + curveSeg.u.l.angle = FindAngle(prev_arc.pos0,prev_arc.pos1); curveSeg.u.l.pos[0] = prev_arc.pos0; curveSeg.u.l.pos[1] = prev_arc.pos1; curveSeg.u.l.option = 0; @@ -483,7 +483,7 @@ EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawC * */ -EXPORT void DrawBezCurve(trkSeg_p control_arm1, +static void DrawBezCurve(trkSeg_p control_arm1, int cp1Segs_cnt, trkSeg_p control_arm2, int cp2Segs_cnt, @@ -491,28 +491,24 @@ EXPORT void DrawBezCurve(trkSeg_p control_arm1, 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, Da.trackGauge, color ); if (cp1Segs_cnt && control_arm1) DrawSegs( &tempD, zero, 0.0, control_arm1, cp1Segs_cnt, Da.trackGauge, drawColorBlack ); if (cp2Segs_cnt && control_arm2) DrawSegs( &tempD, zero, 0.0, control_arm2, cp2Segs_cnt, Da.trackGauge, drawColorBlack ); - tempD.funcs->options = oldDrawOptions; - tempD.options = oldOptions; } /* + * Undraw the temp Bezier + */ + +/* * 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); + 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,fabs(Da.minRadius)<(GetLayoutMinTrackRadius()-EPSILON)?exceptionColor:normalColor); 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 } @@ -542,6 +538,19 @@ void CreateBothControlArms(int selectPoint, BOOL_T track) { } } +void CreateMoveAnchor(coOrd pos,BOOL_T fill) { + double d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int inx = anchors_da.cnt-1; + anchors(inx).type = fill?SEG_FILCRCL:SEG_CRVLIN; + anchors(inx).u.c.a0 = 0.0; + anchors(inx).u.c.a1 = 360.0; + anchors(inx).width = 0; + anchors(inx).color = wDrawColorBlue; + anchors(inx).u.c.radius = d/4; + anchors(inx).u.c.center = pos; +} + /* * AdjustBezCurve * @@ -590,14 +599,24 @@ EXPORT STATUS_T AdjustBezCurve( InfoMessage( _("Select End-Point - Ctrl unlocks end-point") ); else InfoMessage( _("Select End-Point") ); - DrawTempBezier(Da.track); return C_CONTINUE; + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if (Da.state != PICK_POINT) return C_CONTINUE; + if (Da.state != PICK_POINT) return C_CONTINUE; + for (int i=0;i<4;i++) { + if (i==0 && Da.trk[0]) continue; + if (i==3 && Da.trk[1]) continue; //ignore locked points + d = FindDistance(Da.pos[i],pos); + if (IsClose(d)) CreateMoveAnchor(Da.pos[i],TRUE); + } + break; + 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) { @@ -609,19 +628,19 @@ EXPORT STATUS_T AdjustBezCurve( } if (!IsClose(dd) ) Da.selectPoint = -1; + DYNARR_RESET(trkSeg_t,anchors_da); 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]; + CreateMoveAnchor(pos,TRUE); 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: @@ -629,8 +648,8 @@ EXPORT STATUS_T AdjustBezCurve( InfoMessage(_("Pick any circle to adjust it - Enter to confirm, ESC to abort")); return C_CONTINUE; } + DYNARR_RESET(trkSeg_t,anchors_da); //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]) { @@ -642,6 +661,7 @@ EXPORT STATUS_T AdjustBezCurve( } // Dont Snap control points } else SnapPos(&pos); Da.pos[Da.selectPoint] = pos; + CreateMoveAnchor(pos,TRUE); 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); @@ -666,7 +686,6 @@ EXPORT STATUS_T AdjustBezCurve( 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: @@ -674,11 +693,8 @@ EXPORT STATUS_T AdjustBezCurve( //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 - + DYNARR_RESET(trkSeg_t,anchors_da); 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 @@ -701,6 +717,7 @@ EXPORT STATUS_T AdjustBezCurve( 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; @@ -722,7 +739,6 @@ EXPORT STATUS_T AdjustBezCurve( 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; @@ -751,7 +767,6 @@ EXPORT STATUS_T AdjustBezCurve( } } 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); @@ -761,26 +776,30 @@ EXPORT STATUS_T AdjustBezCurve( 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); + DYNARR_RESET(trkSeg_t,anchors_da); 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); + if (Da.state != NONE) + DrawTempBezier(Da.track); + if (anchors_da.cnt>0) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; default: return C_CONTINUE; } + return C_CONTINUE; + } @@ -824,14 +843,16 @@ STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG) Da.selectPoint = -1; Da.selectTrack = NULL; - if (IsTrack(trk)) Da.track = TRUE; + if (IsTrack(trk)) { + Da.track = TRUE; + 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); + } 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"); @@ -839,8 +860,12 @@ STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG) 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 wActionMove: + if (Da.state == NONE) return C_CONTINUE; + return AdjustBezCurve(wActionMove, 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 + UndrawNewTrack( Da.selectTrack ); return AdjustBezCurve(C_DOWN, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage); @@ -867,9 +892,10 @@ STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG) 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); - + if (Da.track) CopyAttributes( trk, t ); + Da.state = NONE; //Must do before Delete for redraw DeleteTrack(trk, TRUE); if (Da.track) { @@ -879,16 +905,14 @@ STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG) } } } + DrawNewTrack( t ); UndoEnd(); - InfoMessage(_("Modify Bezier Complete - select another")); - Da.state = NONE; + InfoMessage(_("Modify Bezier Complete")); return C_TERMINATE; case C_CANCEL: InfoMessage(_("Modify Bezier Cancelled")); Da.state = NONE; - MainRedraw(); - MapRedraw(); return C_TERMINATE; case C_REDRAW: @@ -919,6 +943,23 @@ DIST_T BezierLength(coOrd pos[4],dynArr_t segs) { return dd; } +DIST_T BezierOffsetLength(dynArr_t segs, double offset) { + 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+(t.u.c.radius>0?offset:-offset))*D2R(t.u.c.a1)); + } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) { + dd +=BezierOffsetLength(t.bezSegs,offset); + } 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; @@ -934,6 +975,20 @@ DIST_T BezierMinRadius(coOrd pos[4],dynArr_t segs) { return r; } +static void CreateEndAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} + /* * Create a Bezier Curve (Track or Line) * Sequence is @@ -955,7 +1010,6 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) cmd = action>>8; } else cmd = (long)commandContext; - Da.color = lineColor; Da.width = (double)lineWidth/mainD.dpi; Da.trackGauge = trackGauge; @@ -965,6 +1019,10 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) case C_START: Da.track = (cmd == bezCmdModifyTrack || cmd == bezCmdCreateTrack)?TRUE:FALSE; + if (Da.track ) + Da.color = wDrawColorBlack; + else + Da.color = lineColor; Da.state = POS_1; Da. selectPoint = -1; @@ -977,44 +1035,43 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) 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" ); + InfoMessage( _("Place 1st endpoint of Bezier - snap to %s"), Da.track?"unconnected Track":"line" ); return C_CONTINUE; case C_DOWN: + DYNARR_RESET(trkSeg_t,anchors_da); 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 ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == 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 (GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) { + wBeep(); + InfoMessage(_("Track is different gauge")); + ep = -1; + t = NULL; + } else { + 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 ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == 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; } } } @@ -1024,37 +1081,58 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd 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") ); + 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 { + } 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 + InfoMessage( _("Drag end of second control 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 wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if ( Da.state != POS_1 && Da.state != POS_2) return C_CONTINUE; + if (Da.track) { + if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == 0) { + if ((t = OnTrack(&pos, FALSE, TRUE)) != NULL) { + EPINX_T ep = PickUnconnectedEndPointSilent(pos, t); + if (ep != -1) { + if (GetTrkGauge(t) == GetScaleTrackGauge(GetLayoutCurScale())) { + pos = GetTrkEndPos(t, ep); + CreateEndAnchor(pos,FALSE); + } + } + } + } + } else { + if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == 0) { + if ((t = OnTrack(&pos,FALSE, FALSE)) != NULL) { + CreateEndAnchor(pos,TRUE); + } + } + } + if (anchors_da.cnt) + 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" ); + InfoMessage( _("Place 1st endpoint of Bezier - snap to %s"), 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" ); + InfoMessage( _("Select other end of Bezier - 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; @@ -1066,7 +1144,6 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) } // 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 ); } @@ -1074,7 +1151,6 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) 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; @@ -1091,9 +1167,8 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) return C_CONTINUE; } Da.state = POS_2; - InfoMessage( _("Select other end of Bezier, +Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" ); + InfoMessage( _("Select other end of Bezier - 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 ); @@ -1108,14 +1183,14 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) 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); } + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); 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; @@ -1139,13 +1214,13 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) } 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); + } diff --git a/app/bin/cbezier.h b/app/bin/cbezier.h index 8d0dde8..49b818f 100644 --- a/app/bin/cbezier.h +++ b/app/bin/cbezier.h @@ -25,7 +25,7 @@ #include "utility.h" -dynArr_t tempEndPts_da; +extern dynArr_t tempEndPts_da; #define BezSegs(N) DYNARR_N( trkEndPt_t, tempEndPts_da, N ) #define bezCmdNone (0) @@ -42,12 +42,15 @@ STATUS_T CmdBezCurve( wAction_t, coOrd); STATUS_T CmdBezModify(track_p, wAction_t, coOrd, DIST_T); STATUS_T CreateBezier( wAction_t, coOrd, BOOL_T, wDrawColor, DIST_T, long, bezMessageProc ); -DIST_T BezierDescriptionDistance( coOrd, track_p ); +DIST_T BezierDescriptionDistance( coOrd, track_p, coOrd *, BOOL_T, BOOL_T * ); 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 BezierOffsetLength(dynArr_t,double offset); double BezierMinRadius(coOrd[4],dynArr_t); void UpdateParms(wDrawColor color,long width); +void addSegBezier(dynArr_t * array_p, trkSeg_p seg); + diff --git a/app/bin/cblock.c b/app/bin/cblock.c index 4c4895c..b395306 100644 --- a/app/bin/cblock.c +++ b/app/bin/cblock.c @@ -61,6 +61,10 @@ #include "trackx.h" #include "utility.h" +#ifdef WINDOWS +#include "include/utf8convert.h" +#endif // WINDOWS + EXPORT TRKTYP_T T_BLOCK = -1; static int log_block = 0; @@ -74,8 +78,8 @@ static void NoDrawString( drawCmd_p d, coOrd p, ANGLE_T a, char * s, wFont_p fp, FONTSIZE_T fontSize, wDrawColor color ) {} static void NoDrawBitMap( drawCmd_p d, coOrd p, wDrawBitMap_p bm, wDrawColor color) {} -static void NoDrawFillPoly( drawCmd_p d, int cnt, coOrd * pts, - wDrawColor color ) {} +static void NoDrawFillPoly( drawCmd_p d, int cnt, coOrd * pts, int * types, + wDrawColor color, wDrawWidth width, int fill, int open) {} static void NoDrawFillCircle( drawCmd_p d, coOrd p, DIST_T r, wDrawColor color ) {} @@ -100,6 +104,8 @@ static drawCmd_t blockD = { static char blockName[STR_SHORT_SIZE]; static char blockScript[STR_LONG_SIZE]; static long blockElementCount; +static track_p first_block; +static track_p last_block; static paramData_t blockPLs[] = { /*0*/ { PD_STRING, blockName, "name", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)200, N_("Name"), 0, 0, sizeof( blockName )}, @@ -116,7 +122,7 @@ static track_p blockEditTrack; static paramData_t blockEditPLs[] = { /*0*/ { PD_STRING, blockEditName, "name", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)200, N_("Name"), 0, 0, sizeof(blockEditName)}, /*1*/ { PD_STRING, blockEditScript, "script", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)350, N_("Script"), 0, 0, sizeof(blockEditScript)}, -/*2*/ { PD_STRING, blockEditSegs, "segments", PDO_NOPREF, (void*)350, N_("Segments"), BO_READONLY }, +/*2*/ { PD_STRING, blockEditSegs, "segments", PDO_NOPREF, (void*)350, N_("Segments"), BO_READONLY }, }; static paramGroup_t blockEditPG = { "block", 0, blockEditPLs, sizeof blockEditPLs/sizeof blockEditPLs[0] }; static wWin_p blockEditW; @@ -129,12 +135,14 @@ typedef struct btrackinfo_t { static dynArr_t blockTrk_da; #define blockTrk(N) DYNARR_N( btrackinfo_t , blockTrk_da, N ) +#define tracklist(N) (&(xx->trackList))[N] typedef struct blockData_t { char * name; char * script; BOOL_T IsHilite; + track_p next_block; wIndex_t numTracks; btrackinfo_t trackList; } blockData_t, *blockData_p; @@ -221,10 +229,11 @@ static DIST_T DistanceBlock (track_p t, coOrd * p ) DIST_T closest, current; int iTrk = 1; coOrd pos = *p; - closest = GetTrkDistance ((&(xx->trackList))[0].t, &pos); + closest = 99999.0; coOrd best_pos = pos; - for (; iTrk < xx->numTracks; iTrk++) { + for (iTrk = 0; iTrk < xx->numTracks; iTrk++) { pos = *p; + if ((&(xx->trackList))[iTrk].t == NULL) continue; current = GetTrkDistance ((&(xx->trackList))[iTrk].t, &pos); if (current < closest) { closest = current; @@ -252,22 +261,25 @@ static void DescribeBlock (track_p trk, char * str, CSIZE_T len ) *str = tolower((unsigned char)*str); str++; } - sprintf( str, _("(%d): Layer=%d %s"), + sprintf( str, _("(%d): Layer=%u %s"), GetTrkIndex(trk), GetTrkLayer(trk)+1, message ); blockData.name[0] = '\0'; strncat(blockData.name,xx->name,STR_SHORT_SIZE-1); blockData.script[0] = '\0'; strncat(blockData.script,xx->script,STR_LONG_SIZE-1); blockData.length = 0; - if (xx->numTracks > 0) { - blockData.endPt[0] = GetTrkEndPos((&(xx->trackList))[0].t,0); - } + BOOL_T first = TRUE; for (tcount = 0; tcount < xx->numTracks; tcount++) { - if ((&(xx->trackList))[tcount].t == NULL) continue; - blockData.length += GetTrkLength((&(xx->trackList))[tcount].t,0,1); - lastTrk = (&(xx->trackList))[tcount].t; + if ((&(xx->trackList))[tcount].t == NULL) continue; + if (first) { + blockData.endPt[0] = GetTrkEndPos((&(xx->trackList))[tcount].t,0); + first = FALSE; + } + blockData.endPt[1] = GetTrkEndPos((&(xx->trackList))[tcount].t,1); + blockData.length += GetTrkLength((&(xx->trackList))[tcount].t,0,1); + tcount++; + break; } - if (lastTrk != NULL) blockData.endPt[1] = GetTrkEndPos(lastTrk,1); blockDesc[E0].mode = blockDesc[E1].mode = blockDesc[LN].mode = DESC_RO; @@ -347,13 +359,31 @@ static BOOL_T blockCheckContigiousPath() static void DeleteBlock ( track_p t ) { - LOG( log_block, 1, ("*** DeleteBlock(%p)\n",t)) - blockData_p xx = GetblockData(t); - LOG( log_block, 1, ("*** DeleteBlock(): index is %d\n",GetTrkIndex(t))) - LOG( log_block, 1, ("*** DeleteBlock(): xx = %p, xx->name = %p, xx->script = %p\n", + track_p trk1; + blockData_p xx1; + + LOG( log_block, 1, ("*** DeleteBlock(%p)\n",t)) + blockData_p xx = GetblockData(t); + LOG( log_block, 1, ("*** DeleteBlock(): index is %d\n",GetTrkIndex(t))) + LOG( log_block, 1, ("*** DeleteBlock(): xx = %p, xx->name = %p, xx->script = %p\n", xx,xx->name,xx->script)) MyFree(xx->name); xx->name = NULL; MyFree(xx->script); xx->script = NULL; + + if (first_block == t) + first_block = xx->next_block; + trk1 = first_block; + while(trk1) { + xx1 = GetblockData (trk1); + if (xx1->next_block == t) { + xx1->next_block = xx->next_block; + break; + } + trk1 = xx1->next_block; + } + if (t == last_block) + last_block = trk1; + } static BOOL_T WriteBlock ( track_p t, FILE * f ) @@ -361,25 +391,31 @@ static BOOL_T WriteBlock ( track_p t, FILE * f ) BOOL_T rc = TRUE; wIndex_t iTrack; blockData_p xx = GetblockData(t); + char *blockName = MyStrdup(xx->name); + +#ifdef WINDOWS + blockName = Convert2UTF8(blockName); +#endif // WINDOWS rc &= fprintf(f, "BLOCK %d \"%s\" \"%s\"\n", - GetTrkIndex(t), xx->name, xx->script)>0; + GetTrkIndex(t), blockName, xx->script)>0; for (iTrack = 0; iTrack < xx->numTracks && rc; iTrack++) { if ((&(xx->trackList))[iTrack].t == NULL) continue; rc &= fprintf(f, "\tTRK %d\n", GetTrkIndex((&(xx->trackList))[iTrack].t))>0; } - rc &= fprintf( f, "\tEND\n" )>0; + rc &= fprintf( f, "\t%s\n", END_BLOCK )>0; + MyFree(blockName); return rc; } -static void ReadBlock ( char * line ) +static BOOL_T ReadBlock ( char * line ) { TRKINX_T trkindex; wIndex_t index; - track_p trk; + track_p trk, trk1; char * cp = NULL; - blockData_p xx; + blockData_p xx,xx1; wIndex_t iTrack; EPINX_T ep; trkEndPt_p endPtP; @@ -387,19 +423,24 @@ static void ReadBlock ( char * line ) LOG( log_block, 1, ("*** ReadBlock: line is '%s'\n",line)) if (!GetArgs(line+6,"dqq",&index,&name,&script)) { - return; + return FALSE; } + +#ifdef WINDOWS + ConvertUTF8ToSystem(name); +#endif // WINDOWS + DYNARR_RESET( btrackinfo_p , blockTrk_da ); while ( (cp = GetNextLine()) != NULL ) { - while (isspace((unsigned char)*cp)) cp++; - if ( strncmp( cp, "END", 3 ) == 0 ) { + if ( IsEND( END_BLOCK ) ) { break; } + while (isspace((unsigned char)*cp)) cp++; if ( *cp == '\n' || *cp == '#' ) { continue; } if ( strncmp( cp, "TRK", 3 ) == 0 ) { - if (!GetArgs(cp+4,"d",&trkindex)) return; + if (!GetArgs(cp+4,"d",&trkindex)) return FALSE; /*trk = FindTrack(trkindex);*/ DYNARR_APPEND( btrackinfo_p *, blockTrk_da, 10 ); blockTrk(blockTrk_da.cnt-1).i = trkindex; @@ -411,18 +452,28 @@ static void ReadBlock ( char * line ) endPtP = &tempEndPts(ep); SetTrkEndPoint( trk, ep, endPtP->pos, endPtP->angle ); } - xx = GetblockData( trk ); - LOG( log_block, 1, ("*** ReadBlock(): trk = %p (%d), xx = %p\n",trk,GetTrkIndex(trk),xx)) - LOG( log_block, 1, ("*** ReadBlock(): name = %p, script = %p\n",name,script)) - xx->name = name; - xx->script = script; - xx->IsHilite = FALSE; + xx = GetblockData( trk ); + LOG( log_block, 1, ("*** ReadBlock(): trk = %p (%d), xx = %p\n",trk,GetTrkIndex(trk),xx)) + LOG( log_block, 1, ("*** ReadBlock(): name = %p, script = %p\n",name,script)) + xx->name = name; + xx->script = script; + xx->IsHilite = FALSE; xx->numTracks = blockTrk_da.cnt; + trk1 = last_block; + if (!trk1) first_block = trk; + else { + xx1 = GetblockData(trk1); + xx1->next_block = trk; + } + xx->next_block = NULL; + last_block = trk; for (iTrack = 0; iTrack < blockTrk_da.cnt; iTrack++) { - LOG( log_block, 1, ("*** ReadBlock(): copying track T%d\n",GetTrkIndex(blockTrk(iTrack).t))) - memcpy((void*)&((&(xx->trackList))[iTrack]),(void*)&(blockTrk(iTrack)),sizeof(btrackinfo_t)); + LOG( log_block, 1, ("*** ReadBlock(): copying track T%d\n",blockTrk(iTrack).i)) + tracklist(iTrack).i = blockTrk(iTrack).i; + tracklist(iTrack).t = NULL; // Not resolved yet!! // } blockDebug(trk); + return TRUE; } EXPORT void ResolveBlockTrack ( track_p trk ) @@ -435,12 +486,12 @@ EXPORT void ResolveBlockTrack ( track_p trk ) LOG( log_block, 1, ("*** ResolveBlockTrack(%d)\n",GetTrkIndex(trk))) xx = GetblockData(trk); for (iTrack = 0; iTrack < xx->numTracks; iTrack++) { - t_trk = FindTrack((&(xx->trackList))[iTrack].i); + t_trk = FindTrack(tracklist(iTrack).i); if (t_trk == NULL) { - NoticeMessage( _("resolveBlockTrack: T%d[%d]: T%d doesn't exist"), _("Continue"), NULL, GetTrkIndex(trk), iTrack, (&(xx->trackList))[iTrack].i ); + NoticeMessage( _("resolveBlockTrack: T%d[%d]: T%d doesn't exist"), _("Continue"), NULL, GetTrkIndex(trk), iTrack, tracklist(iTrack).i,t_trk ); } - (&(xx->trackList))[iTrack].t = t_trk; - LOG( log_block, 1, ("*** ResolveBlockTrack(): %d (%d): %p\n",iTrack,(&(xx->trackList))[iTrack].i,t_trk)) + tracklist(iTrack).t = t_trk; + LOG( log_block, 1, ("*** ResolveBlockTrack(): %d (%d): %p\n",iTrack,tracklist(iTrack).i,t_trk)) } } @@ -494,17 +545,24 @@ static BOOL_T TrackInBlock (track_p trk, track_p blk) { static track_p FindBlock (track_p trk) { track_p a_trk; - for (a_trk = NULL; TrackIterate( &a_trk ) ;) { - if (GetTrkType(a_trk) == T_BLOCK && - TrackInBlock(trk,a_trk)) return a_trk; + blockData_p xx; + if (!first_block) return NULL; + a_trk = first_block; + while (a_trk) { + if (!IsTrackDeleted(a_trk)) { + if (GetTrkType(a_trk) == T_BLOCK && + TrackInBlock(trk,a_trk)) return a_trk; + } + xx = GetblockData(a_trk); + a_trk = xx->next_block; } return NULL; } static void BlockOk ( void * junk ) { - blockData_p xx; - track_p trk; + blockData_p xx,xx1; + track_p trk,trk1; wIndex_t iTrack; EPINX_T ep; trkEndPt_p endPtP; @@ -525,10 +583,11 @@ static void BlockOk ( void * junk ) while ( TrackIterate( &trk ) ) { if ( GetTrkSelected( trk ) ) { if ( IsTrack(trk) ) { - DYNARR_APPEND( btrackinfo_p *, blockTrk_da, 10 ); + DYNARR_APPEND( btrackinfo_t, blockTrk_da, 10 ); + blockTrk(blockTrk_da.cnt - 1).t = trk; + blockTrk(blockTrk_da.cnt - 1).i = GetTrkIndex(trk); LOG( log_block, 1, ("*** BlockOk(): adding track T%d\n",GetTrkIndex(trk))) - blockTrk(blockTrk_da.cnt-1).t = trk; - blockTrk(blockTrk_da.cnt-1).i = GetTrkIndex(trk); + } } } @@ -556,15 +615,26 @@ static void BlockOk ( void * junk ) SetTrkEndPoint( trk, ep, endPtP->pos, endPtP->angle ); } - xx = GetblockData( trk ); - LOG(log_block, 1, ("*** BlockOk(): trk = %p (%d), xx = %p\n", trk, GetTrkIndex(trk), xx)) + xx = GetblockData( trk ); + LOG(log_block, 1, ("*** BlockOk(): trk = %p (%d), xx = %p\n", trk, GetTrkIndex(trk), xx)) xx->name = MyStrdup(blockName); xx->script = MyStrdup(blockScript); - xx->IsHilite = FALSE; + xx->IsHilite = FALSE; xx->numTracks = blockTrk_da.cnt; + trk1 = last_block; + if (!trk1) { + first_block = trk; + } + else { + xx1 = GetblockData(trk1); + xx1->next_block = trk; + } + xx->next_block = NULL; + last_block = trk; for (iTrack = 0; iTrack < blockTrk_da.cnt; iTrack++) { - LOG( log_block, 1, ("*** BlockOk(): copying track T%d\n",GetTrkIndex(blockTrk(iTrack).t))) - memcpy((void*)&(&(xx->trackList))[iTrack],(void*)&blockTrk(iTrack),sizeof(btrackinfo_t)); + LOG( log_block, 1, ("*** BlockOk(): copying track T%d\n",tracklist(iTrack).i)) + tracklist(iTrack).i = blockTrk(iTrack).i; + tracklist(iTrack).t = blockTrk(iTrack).t; } blockDebug(trk); UndoEnd(); @@ -710,13 +780,17 @@ static STATUS_T CmdBlock (wAction_t action, coOrd pos ) } #endif -EXPORT void CheckDeleteBlock (track_p t) +void CheckDeleteBlock(track_p t) { track_p blk; blockData_p xx; - + if (!IsTrack(t)) { + return; + } blk = FindBlock(t); - if (blk == NULL) return; + if (blk == NULL) { + return; + } xx = GetblockData(blk); NoticeMessage(_("Deleting block %s"),_("Ok"),NULL,xx->name); DeleteTrack(blk,FALSE); @@ -789,7 +863,7 @@ static void DrawBlockTrackHilite( void ) w = (wPos_t)((blkhiliteSize.x/mainD.scale)*mainD.dpi+0.5); h = (wPos_t)((blkhiliteSize.y/mainD.scale)*mainD.dpi+0.5); mainD.CoOrd2Pix(&mainD,blkhiliteOrig,&x,&y); - wDrawFilledRectangle( mainD.d, x, y, w, h, blkhiliteColor, wDrawOptTemp ); + wDrawFilledRectangle( mainD.d, x, y, w, h, blkhiliteColor, wDrawOptTemp|wDrawOptTransparent ); } diff --git a/app/bin/ccontrol.c b/app/bin/ccontrol.c index fb02fdf..793acc3 100644 --- a/app/bin/ccontrol.c +++ b/app/bin/ccontrol.c @@ -58,6 +58,9 @@ static const char rcsid[] = "@(#) : $Id$"; #include "param.h" #include "track.h" #include "trackx.h" +#ifdef WINDOWS +#include "include/utf8convert.h" +#endif // WINDOWS #include "utility.h" #include "messages.h" @@ -276,7 +279,7 @@ static void DescribeControl (track_p trk, char * str, CSIZE_T len ) *str = tolower((unsigned char)*str); str++; } - sprintf( str, _("(%d [%s]): Layer=%d, at %0.3f,%0.3f"), + sprintf( str, _("(%d [%s]): Layer=%u, at %0.3f,%0.3f"), GetTrkIndex(trk), xx->name,GetTrkLayer(trk)+1, xx->orig.x, xx->orig.y); strncpy(controlProperties.name,xx->name,STR_SHORT_SIZE-1); @@ -305,14 +308,22 @@ static BOOL_T WriteControl ( track_p t, FILE * f ) { BOOL_T rc = TRUE; controlData_p xx = GetcontrolData(t); - rc &= fprintf(f, "CONTROL %d %d %s %d %0.6f %0.6f \"%s\" \"%s\" \"%s\"\n", + char *controlName = MyStrdup(xx->name); + +#ifdef WINDOWS + controlName = Convert2UTF8(controlName); +#endif // WINDOWS + + rc &= fprintf(f, "CONTROL %d %u %s %d %0.6f %0.6f \"%s\" \"%s\" \"%s\"\n", GetTrkIndex(t), GetTrkLayer(t), GetTrkScaleName(t), - GetTrkVisible(t), xx->orig.x, xx->orig.y, xx->name, + GetTrkVisible(t), xx->orig.x, xx->orig.y, controlName, xx->onscript, xx->offscript)>0; + + MyFree(controlName); return rc; } -static void ReadControl ( char * line ) +static BOOL_T ReadControl ( char * line ) { wIndex_t index; /*TRKINX_T trkindex;*/ @@ -326,8 +337,13 @@ static void ReadControl ( char * line ) wIndex_t layer; controlData_p xx; if (!GetArgs(line+7,"dLsdpqqq",&index,&layer,scale, &visible, &orig,&name,&onscript,&offscript)) { - return; + return FALSE; } + +#ifdef WINDOWS + ConvertUTF8ToSystem(name); +#endif // WINDOWS + trk = NewTrack(index, T_CONTROL, 0, sizeof(controlData_t)); SetTrkVisible(trk, visible); SetTrkScale(trk, LookupScale( scale )); @@ -338,6 +354,7 @@ static void ReadControl ( char * line ) xx->onscript = onscript; xx->offscript = offscript; ComputeControlBoundingBox(trk); + return TRUE; } static void MoveControl (track_p trk, coOrd orig ) @@ -502,24 +519,29 @@ static void CreateNewControl (coOrd orig) static STATUS_T CmdControl ( wAction_t action, coOrd pos ) { - + static coOrd control_pos; + static BOOL_T create; switch (action) { case C_START: InfoMessage(_("Place control")); + create = FALSE; return C_CONTINUE; case C_DOWN: + create = TRUE; + /* no break */ case C_MOVE: SnapPos(&pos); - DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack ); + control_pos = pos; return C_CONTINUE; case C_UP: SnapPos(&pos); - DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack ); CreateNewControl(pos); return C_TERMINATE; case C_REDRAW: + if (create) + DDrawControl( &tempD, control_pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack ); + return C_CONTINUE; case C_CANCEL: - DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack ); return C_CONTINUE; default: return C_CONTINUE; @@ -537,7 +559,7 @@ static void DrawControlTrackHilite( void ) w = (wPos_t)((ctlhiliteSize.x/mainD.scale)*mainD.dpi+0.5); h = (wPos_t)((ctlhiliteSize.y/mainD.scale)*mainD.dpi+0.5); mainD.CoOrd2Pix(&mainD,ctlhiliteOrig,&x,&y); - wDrawFilledRectangle( mainD.d, x, y, w, h, ctlhiliteColor, wDrawOptTemp ); + wDrawFilledRectangle( mainD.d, x, y, w, h, ctlhiliteColor, wDrawOptTemp|wDrawOptTransparent ); } static int ControlMgmProc ( int cmd, void * data ) diff --git a/app/bin/ccornu.c b/app/bin/ccornu.c index 9bdb0d0..fd51755 100644 --- a/app/bin/ccornu.c +++ b/app/bin/ccornu.c @@ -1,3 +1,7 @@ + + + + /** \file ccornu.c * Cornu Command. Draw or modify a Cornu Easement Track. */ @@ -71,6 +75,7 @@ #include "ccurve.h" #include "ccornu.h" #include "tcornu.h" +#include "tbezier.h" #include "cstraigh.h" #include "drawgeom.h" #include "cjoin.h" @@ -83,12 +88,24 @@ #include "cundo.h" #include "messages.h" #include "cselect.h" +#include "fileio.h" + +#include <stdint.h> extern drawCmd_t tempD; extern TRKTYP_T T_BEZIER; extern TRKTYP_T T_CORNU; - +typedef struct { + coOrd end_center; + coOrd end_curve; + DIST_T mid_disp; + BOOL_T end_valid; + BOOL_T angle_selected; + BOOL_T radius_selected; + BOOL_T last_selected; + ANGLE_T arc_angle; +} endHandle; /* * STATE INFO @@ -101,11 +118,18 @@ enum Cornu_States { NONE, POINT_PICKED, TRACK_SELECTED }; +typedef enum {CORNU_MODIFY, CORNU_CREATE} cornuCmdType_e; + + static struct { enum Cornu_States state; coOrd pos[2]; - int selectPoint; - wDrawColor color; + int number_of_points; + int selectEndPoint; + int selectMidPoint; + int selectEndHandle; + int prevSelected; + int prevEndPoint; DIST_T width; track_p trk[2]; EPINX_T ep[2]; @@ -119,9 +143,9 @@ static struct { BOOL_T extend[2]; trkSeg_t extendSeg[2]; - trkSeg_t ep1Segs[2]; + trkSeg_t ep1Segs[11]; int ep1Segs_da_cnt; - trkSeg_t ep2Segs[2]; + trkSeg_t ep2Segs[11]; int ep2Segs_da_cnt; dynArr_t crvSegs_da; int crvSegs_da_cnt; @@ -132,9 +156,143 @@ static struct { BOOL_T circleorHelix[2]; DIST_T trackGauge; + int cmdType; + + dynArr_t midSegs; + + dynArr_t mid_points; + dynArr_t tracks; + BOOL_T ends[2]; + + endHandle endHandle[2]; + bezctx * bezc; + + cornuCmdType_e commandType; + } Da; +static trkSeg_p curCornu; +static wIndex_t cornuHotBarCmdInx; + +static struct { + trkSeg_t st; + trkSeg_t back; + trkSeg_t txt; + int count; +} hotB; + + +static char * CmdCornuHotBarProc( + hotBarProc_e op, + void * data, + drawCmd_p d, + coOrd * origP ) +{ + trkSeg_p trkseg = &hotB.st; + switch ( op ) { + case HB_SELECT: + CmdCornu( C_CANCEL, zero ); + curCornu = trkseg; + DoCommandB( (void*)(intptr_t)cornuHotBarCmdInx ); + return NULL; + case HB_LISTTITLE: + sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale())); + return message; + case HB_BARTITLE: + sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale())); + return message; + case HB_FULLTITLE: + sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale())); + return message; + case HB_DRAW: + DrawSegs( d, *origP, 0.0, trkseg, hotB.count, trackGauge, wDrawColorBlack ); + return NULL; + } + return NULL; +} + +static pts_t pts[4]; + + +EXPORT void AddHotBarCornu( void ) +{ + hotB.st.type = SEG_STRTRK; + hotB.st.color = wDrawColorBlack; + hotB.st.u.l.pos[0] = zero; + DIST_T ratio = 75.0/curScaleRatio; + Translate(&hotB.st.u.l.pos[1],zero,45.0,15.0*ratio); + hotB.st.u.l.angle = 45.0; + + pts[0].pt_type = wPolyLineStraight; + pts[0].pt.x = 1.0*ratio; + pts[0].pt.y = 5.0*ratio; + pts[1].pt_type = wPolyLineStraight; + pts[1].pt.x = 1.0*ratio; + pts[1].pt.y = 8.0*ratio; + pts[2].pt_type = wPolyLineStraight; + pts[2].pt.x = 13.0*ratio; + pts[2].pt.y = 8.0*ratio; + pts[3].pt_type = wPolyLineStraight; + pts[3].pt.x = 13.0*ratio; + pts[3].pt.y = 5.0*ratio; + + hotB.back.type = SEG_FILPOLY; + hotB.back.color = wDrawColorWhite; + hotB.back.u.p.orig.x = 0.0; + hotB.back.u.p.orig.y = 0.0; + hotB.back.u.p.cnt = 4; + hotB.back.u.p.angle = 0.0; + hotB.back.u.p.polyType = RECTANGLE; + hotB.back.u.p.pts = &pts[0]; + + hotB.txt.type = SEG_TEXT; + hotB.txt.color = wDrawColorBlack; + hotB.txt.u.t.pos.x = 1.0*ratio; + hotB.txt.u.t.pos.y = 5.0*ratio; + hotB.txt.u.t.boxed = TRUE; + hotB.txt.u.t.string = MyStrdup(_(" FLEX ")); + hotB.txt.u.t.fontP = NULL; + hotB.txt.u.t.fontSize = 160.0*ratio; + hotB.txt.u.t.angle = 0.0; + + char * label = MyMalloc(256); + sprintf(label,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale())); + coOrd end; + end = hotB.st.u.l.pos[1]; + //end.x = 21.25; + //end.y = 21.25; + hotB.count = 3; + //hotB.st.u.l.pos[1] = end; + AddHotBarElement( label, end, zero, TRUE, TRUE, curBarScale>0?curBarScale:-1, &hotB, CmdCornuHotBarProc ); +} + +int createMidPoint(dynArr_t * ap, + 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*/ + + DYNARR_APPEND(trkSeg_t,*ap,1); + + trkSeg_p sp = &DYNARR_LAST(trkSeg_t,*ap); + + sp->u.c.center = pos0; + sp->u.c.a0 = 0.0; + sp->u.c.a1 = 360.0; + sp->u.c.radius = d/2; + sp->type = point_selected?SEG_FILCRCL:SEG_CRVLIN; + sp->width = w; + sp->color = drawColorBlack; + + return 1; + +} /** @@ -146,35 +304,208 @@ int createEndPoint( coOrd pos0, //end on curve BOOL_T point_selected, BOOL_T point_selectable, - BOOL_T track_modifyable + BOOL_T track_modifyable, + BOOL_T track_present, + ANGLE_T angle, + DIST_T radius, + coOrd centert, + endHandle * endHandle ) { DIST_T d, w; + int num =0; d = tempD.scale*0.25; w = tempD.scale/tempD.dpi; /*double width*/ + num = 1; + 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 = point_selected?drawColorBlue:drawColorRed; + num = 2; + } 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; + sp[0].color = point_selected?drawColorBlue:drawColorRed; 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; + if (!track_present && endHandle ) { + endHandle->end_center = zero; + endHandle->end_curve = zero; + endHandle->end_valid = TRUE; + endHandle->mid_disp = 0.0; + DIST_T end_length = 20*trackGauge; + Translate(&endHandle->end_curve,pos0,angle,end_length); + Translate(&endHandle->end_center,pos0,angle,end_length/2); + if (radius>0.0) { + ANGLE_T a1 = R2D(end_length/radius); + if (DifferenceBetweenAngles(angle,FindAngle(centert,pos0))>0.0) { + a1 = -a1; + } + PointOnCircle( &endHandle->end_curve, centert,radius,NormalizeAngle(FindAngle(centert,pos0)+a1)); + PointOnCircle( &endHandle->end_center,centert,radius,NormalizeAngle(FindAngle(centert,pos0)+(a1/2.0))); + coOrd cm; + cm = endHandle->end_center; + ANGLE_T a = FindAngle(endHandle->end_curve,pos0); + Rotate(&cm,endHandle->end_curve,-a ); + endHandle->mid_disp = cm.x-endHandle->end_curve.x; + curveData_t curveData; + PlotCurve(crvCmdFromCenter,pos0,endHandle->end_center, endHandle->end_curve, &curveData, FALSE); + if (curveData.type == curveTypeStraight) { + coOrd pos_line[2]; + Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2); + Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2); + Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + pos_line[0]= pos0; + Translate(&pos_line[1],pos0,-FindAngle(pos0,endHandle->end_curve),end_length); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = drawColorRed; + num++; + } else { + DIST_T pos_rad; + pos_rad = radius+trackGauge/2; + sp[num].type = SEG_CRVLIN; + sp[num].width = w; + sp[num].u.c.center = centert; + sp[num].u.c.radius = pos_rad; + ANGLE_T an0 = FindAngle(centert,pos0); + ANGLE_T an1 = FindAngle(centert,endHandle->end_curve); + if (DifferenceBetweenAngles(an0,an1)>0) { + sp[num].u.c.a1 = DifferenceBetweenAngles(an0,an1); + sp[num].u.c.a0 = an0; + } else { + sp[num].u.c.a1 = -DifferenceBetweenAngles(an0,an1); + sp[num].u.c.a0 = an1; + } + endHandle->arc_angle = sp[num].u.c.a1; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + pos_rad = radius-trackGauge/2; + sp[num].type = SEG_CRVLIN; + sp[num].width = w; + sp[num].u.c.center = centert; + sp[num].u.c.radius = pos_rad; + sp[num].u.c.a1 = sp[num-1].u.c.a1; + sp[num].u.c.a0 = sp[num-1].u.c.a0; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + } + } else { + coOrd pos_line[2]; + Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2); + Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2); + Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + + } + coOrd pos_line[2]; + pos_line[0]= pos0; + Translate(&pos_line[1],pos0,angle+180,end_length); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = drawColorRed; + num++; + sp[num].type = SEG_CRVLIN; + sp[num].u.c.center = endHandle->end_curve; + sp[num].u.c.a0 = 0.0; + sp[num].u.c.a1 = 360.0; + sp[num].width = w; + sp[num].u.c.radius = d/4; + sp[num].color = endHandle->angle_selected?drawColorBlue:drawColorRed; + num++; + if (radius<=0.0) + DrawArrowHeads(&sp[num],endHandle->end_center,angle+90.0,TRUE,endHandle->radius_selected?drawColorBlue:drawColorRed); + else + DrawArrowHeads(&sp[num],endHandle->end_center,FindAngle(centert,endHandle->end_center),TRUE,endHandle->radius_selected?drawColorBlue:drawColorRed); + num=num+5; + } else if (endHandle) { + endHandle->end_valid=FALSE; } - return 1; + return num; +} + +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) + +static void CreateCornuEndAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; + +} + +static void CreateCornuExtendAnchor(coOrd p, ANGLE_T a, wBool_t selected) { + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),p,a,FALSE,wDrawColorBlue); } +static void CreateCornuAnchor(coOrd p, wBool_t open) { + DIST_T d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = open?SEG_CRVLIN:SEG_FILCRCL; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} /* * Add element to DYNARR pointed to by caller from segment handed in @@ -182,7 +513,6 @@ int createEndPoint( 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; @@ -206,20 +536,105 @@ void addSegCornu(dynArr_t * const array_p, trkSeg_p seg) { s->u = seg->u; } } -EXPORT void SetKnots(spiro_cp knots[6], coOrd posk[6]) { - for (int i = 0; i < 6; i++) { +EXPORT void SetKnots(spiro_cp knots[], coOrd posk[], char type[], int count) { + for (int i = 0; i < count; i++) { knots[i].x = posk[i].x; knots[i].y = posk[i].y; + knots[i].ty = type[i]; + } +} + +typedef struct { + coOrd pos; + char ty; +} points_t; + +// Take in extra points within Cornu +// G2 (position only k1'' = k2'' = 0); Also Cornu <-> Cornu +// G4 (position only - splitable for Cornu - a G4 point) k1''= k2'' + +BOOL_T CallCornuM(dynArr_t extra_points, BOOL_T end[2], coOrd pos[2], cornuParm_t * cp, 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] = (end[0]?2:0); ends[1] = (end[0]?3:1)+extra_points.cnt; + spiro_cp * knots; + coOrd * posk; + char * type; + posk = MyMalloc((6+extra_points.cnt)*sizeof(coOrd)); + knots = MyMalloc((6+extra_points.cnt)*sizeof(spiro_cp)); + type = MyMalloc((6+extra_points.cnt)*sizeof(char)); + BOOL_T back; + ANGLE_T angle1; + + if (Da.bezc) free(Da.bezc); + + Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots,tempD.scale*0.15/4); + + coOrd pos0 = pos[0]; + + if (end[0]) { + type[0] = SPIRO_OPEN_CONTOUR; + type[1] = SPIRO_G2; + type[2] = SPIRO_RIGHT; + if (cp->radius[0] == 0.0) { + Translate(&posk[0],pos0,cp->angle[0],10); + Translate(&posk[1],pos0,cp->angle[0],5); + } else { + angle1 = FindAngle(cp->center[0],pos[0]); + if (NormalizeAngle(angle1 - cp->angle[0])<180) back = TRUE; + else back = FALSE; + posk[0] = pos[0]; + Rotate(&posk[0],cp->center[0],(back)?-10:10); + posk[1] = pos[0]; + Rotate(&posk[1],cp->center[0],(back)?-5:5); + } + posk[2] = pos[0]; + } else { + type[0] = SPIRO_OPEN_CONTOUR; + posk[0] = pos[0]; + } + + for (int i=0;i<extra_points.cnt;i++) { + posk[(end[0]?3:1)+i] = DYNARR_N(coOrd,extra_points,i); + type[(end[0]?3:1)+i] = SPIRO_G4; + } + + posk[(end[0]?3:1)+extra_points.cnt] = pos[1]; + coOrd pos1 = pos[1]; + + if (end[1]) { + type[(end[0]?3:1)+extra_points.cnt] = SPIRO_LEFT; + type[(end[0]?3:1)+extra_points.cnt+1] = SPIRO_G2; + type[(end[0]?3:1)+extra_points.cnt+2] = SPIRO_END_OPEN_CONTOUR; + if (cp->radius[1] == 0.0) { + Translate(&posk[(end[0]?3:1)+extra_points.cnt+1],pos1,cp->angle[1],5); + Translate(&posk[(end[0]?3:1)+extra_points.cnt+2],pos1,cp->angle[1],10); + } else { + angle1 = FindAngle(cp->center[1],pos[1]); + if (NormalizeAngle(angle1 - cp->angle[1])>180) back = TRUE; + else back = FALSE; + posk[(end[0]?3:1)+extra_points.cnt+1] = pos[1]; + Rotate(&posk[(end[0]?3:1)+extra_points.cnt+1],cp->center[1],(back)?5:-5); + posk[(end[0]?3:1)+extra_points.cnt+2] = pos[1]; + Rotate(&posk[(end[0]?3:1)+extra_points.cnt+2],cp->center[1],(back)?10:-10); + } + } else { + type[(end[0]?3:1)+extra_points.cnt] = SPIRO_END_OPEN_CONTOUR; } - 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; + SetKnots(knots, posk, type, ((end[0]?3:1)+(end[1]?3:1)+extra_points.cnt)); + TaggedSpiroCPsToBezier(knots,Da.bezc); + MyFree(posk); + MyFree(knots); + MyFree(type); + if (!bezctx_xtrkcad_close(Da.bezc)) { + return FALSE; + } + return TRUE; } -BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p, BOOL_T spots) { +EXPORT 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 @@ -227,14 +642,17 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius ends[0] = 2; ends[1] = 3; spiro_cp knots[6]; coOrd posk[6]; + char type[6]; BOOL_T back; ANGLE_T angle1; if (Da.bezc) free(Da.bezc); - Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots); + Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots,tempD.scale*0.15/4); coOrd pos0 = pos[0]; + type[0] = SPIRO_OPEN_CONTOUR; + if (radius[0] == 0.0) { Translate(&posk[0],pos0,angle[0],10); @@ -248,9 +666,12 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius posk[1] = pos[0]; Rotate(&posk[1],center[0],(back)?-5:5); } + type[1] = SPIRO_G2; posk[2] = pos[0]; + type[2] = SPIRO_RIGHT; posk[3] = pos[1]; + type[3] = SPIRO_LEFT; coOrd pos1 = pos[1]; @@ -266,7 +687,10 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius posk[5] = pos[1]; Rotate(&posk[5],center[1],(back)?10:-10); } - SetKnots(knots,posk); + type[4] = SPIRO_G2; + type[5] = SPIRO_END_OPEN_CONTOUR; + + SetKnots(knots, posk, type, 6); TaggedSpiroCPsToBezier(knots,Da.bezc); if (!bezctx_xtrkcad_close(Da.bezc)) { return FALSE; @@ -290,19 +714,19 @@ BOOL_T CallCornu(coOrd pos[2], track_p trk[2], EPINX_T ep[2], dynArr_t * array_p 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)); + if (ep && ep[i]>=0) 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 + if (ep && ep[i]>=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)); + if (ep && ep[i]>=0) 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)); + if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); cp->radius[i] = params.arcR; cp->center[i] = params.arcP; } else { @@ -317,6 +741,7 @@ BOOL_T CallCornu(coOrd pos[2], track_p trk[2], EPINX_T ep[2], dynArr_t * array_p } + /* * Draw Cornu while editing it. It consists of up to five elements - the ends, the curve and one or two End Points. * @@ -333,30 +758,26 @@ EXPORT void DrawCornuCurve( trkSeg_p second_trk, trkSeg_p extend1_trk, trkSeg_p extend2_trk, + trkSeg_p mids, + int midSegs_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 (first_trk) DrawSegs( &tempD, zero, 0.0, first_trk, 1, Da.trackGauge, drawColorBlack ); - if (crvSegs_cnt && curveSegs) + if (crvSegs_cnt>0 && curveSegs) DrawSegs( &tempD, zero, 0.0, curveSegs, crvSegs_cnt, Da.trackGauge, color ); if (second_trk) DrawSegs( &tempD, zero, 0.0, second_trk, 1, Da.trackGauge, drawColorBlack ); - if (ep1Segs_cnt && point1) + if (ep1Segs_cnt>0 && point1) DrawSegs( &tempD, zero, 0.0, point1, ep1Segs_cnt, Da.trackGauge, drawColorBlack ); - if (ep2Segs_cnt && point2) + if (ep2Segs_cnt>0 && point2) DrawSegs( &tempD, zero, 0.0, point2, ep2Segs_cnt, Da.trackGauge, drawColorBlack ); + if (midSegs_cnt>0 && mids) + DrawSegs( &tempD, zero, 0.0, mids, midSegs_cnt, Da.trackGauge, drawColorBlack ); if (extend1_trk) DrawSegs( &tempD, zero, 0.0, extend1_trk, 1, Da.trackGauge, drawColorBlack); if (extend2_trk) DrawSegs( &tempD, zero, 0.0, extend2_trk, 1, Da.trackGauge, drawColorBlack); - tempD.funcs->options = oldDrawOptions; - tempD.options = oldOptions; } @@ -373,35 +794,53 @@ void DrawTempCornu() { &Da.trk2Seg, Da.extend[0]?&Da.extendSeg[0]:NULL, Da.extend[1]?&Da.extendSeg[1]:NULL, - Da.minRadius<(GetLayoutMinTrackRadius()-EPSILON)?drawColorRed:drawColorBlack); + (trkSeg_t *)Da.midSegs.ptr,Da.midSegs.cnt, + fabs(Da.minRadius)<(GetLayoutMinTrackRadius()-EPSILON)?exceptionColor:normalColor); } -void CreateBothEnds(int selectPoint) { +void CreateBothEnds(int selectEndPoint, int selectMidPoint, int selectEndHandle, int lastSelected ) { BOOL_T selectable[2],modifyable[2]; selectable[0] = !Da.trk[0] || ( Da.trk[0] && !QueryTrack(Da.trk[0],Q_IS_CORNU) && !QueryTrack(Da.trk[0],Q_CAN_MODIFY_CONTROL_POINTS)); modifyable[0] = !Da.trk[0] || ( Da.trk[0] && QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY)); selectable[1] = !Da.trk[1] || ( - Da.trk[1] && !QueryTrack(Da.trk[1],Q_IS_CORNU) && !QueryTrack(Da.trk[0],Q_CAN_MODIFY_CONTROL_POINTS)); + Da.trk[1] && !QueryTrack(Da.trk[1],Q_IS_CORNU) && !QueryTrack(Da.trk[1],Q_CAN_MODIFY_CONTROL_POINTS)); modifyable[1] = !Da.trk[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]); + + Da.endHandle[0].angle_selected = (selectEndHandle==1)?TRUE:FALSE; + Da.endHandle[0].radius_selected = (selectEndHandle==0)?TRUE:FALSE; + Da.endHandle[1].angle_selected = (selectEndHandle==3)?TRUE:FALSE; + Da.endHandle[1].radius_selected = (selectEndHandle==2)?TRUE:FALSE; + Da.endHandle[0].last_selected = lastSelected==0?TRUE:FALSE; + Da.endHandle[1].last_selected = lastSelected==1?TRUE:FALSE; + if (selectEndPoint == -1) { + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0],Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],Da.extend[0]?NULL:&Da.endHandle[0]); + Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1],Da.trk[1]!=NULL,Da.angle[1],Da.radius[1],Da.center[1],Da.extend[1]?NULL:&Da.endHandle[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]); + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],selectEndPoint == 0,selectable[0],modifyable[0],Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],Da.extend[0]?NULL:&Da.endHandle[0]); + Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],selectEndPoint == 1,selectable[1],modifyable[1],Da.trk[1]!=NULL,Da.angle[1],Da.radius[1],Da.center[1],Da.extend[1]?NULL:&Da.endHandle[1]); } + Da.endHandle[0].end_valid = !Da.extend[0]; + Da.endHandle[1].end_valid = !Da.extend[1]; + DYNARR_RESET(trkSeg_t,Da.midSegs); + for (int i=0;i<Da.mid_points.cnt;i++) { + createMidPoint(&Da.midSegs, DYNARR_N(coOrd,Da.mid_points,i),selectMidPoint == i,TRUE, TRUE ); + } + if (Da.radius[0] >=0.0) Da.ends[0] = TRUE; + else Da.ends[0] = FALSE; + if (Da.radius[1] >=0.0) Da.ends[1] = TRUE; + else Da.ends[1] = FALSE; } -BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track_end) { +BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track_end, wBool_t extend) { trackParams_t trackParams; - if (!GetTrackParams(PARAMS_CORNU, t, pos, &trackParams)) return FALSE; + coOrd pos1; + if ((track_end>=0) && extend) pos1 = GetTrkEndPos(t,track_end); + else pos1 = pos; + if (!GetTrackParams(PARAMS_CORNU, t, pos1, &trackParams)) return FALSE; Da.radius[end] = 0.0; Da.center[end] = zero; Da.circleorHelix[end] = FALSE; @@ -415,7 +854,8 @@ BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track Da.circleorHelix[end] = TRUE; Da.angle[end] = trackParams.track_angle; //For Now } else { - Da.angle[end] = NormalizeAngle(trackParams.track_angle + (track_end?180:0)); + Da.angle[end] = NormalizeAngle(GetTrkEndAngle(t,track_end)+180); + //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)); @@ -430,12 +870,12 @@ BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track } } else if (trackParams.type == curveTypeCornu) { int ep = trackParams.ep; - Da.angle[end] = NormalizeAngle(trackParams.cornuAngle[ep]+(track_end?180:0)); + Da.angle[end] = NormalizeAngle(trackParams.cornuAngle[ep]+180); 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) + if (trackParams.ep>=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 @@ -483,11 +923,106 @@ void SetUpCornuParms(cornuParm_t * cp) { cp->radius[1] = Da.radius[1]; } +track_p CreateCornuFromPoints(coOrd pos[2],BOOL_T track_end[2]) { + coOrd center[2]; + DIST_T radius[2]; + ANGLE_T angle[2]; + BOOL_T back, neg; + cornuParm_t new; + int inx,subinx; + coOrd pos_temp[2]; + + for (int i=0;i<2;i++) { + pos_temp[i] = pos[i]; + + if (!track_end[i] || (Da.radius[i]==-1.0)) { + + angle[i] = GetAngleSegs(Da.crvSegs_da.cnt,(trkSeg_t *)(Da.crvSegs_da.ptr),&pos_temp[i],&inx,NULL,&back,&subinx,&neg); + + trkSeg_p segPtr = &DYNARR_N(trkSeg_t, Da.crvSegs_da, inx); + + if (segPtr->type == SEG_BEZTRK) + segPtr = &DYNARR_N(trkSeg_t, segPtr->bezSegs, subinx); + + if (i==0) { + if (neg==back) angle[i] = NormalizeAngle(angle[i]+180); + } else { + if (!(neg==back)) angle[i] = NormalizeAngle(angle[i]+180); + } + + if (segPtr->type == SEG_STRTRK) { + radius[i] = 0.0; + center[i] = zero; + } else if (segPtr->type == SEG_CRVTRK) { + center[i] = segPtr->u.c.center; + radius[i] = fabs(segPtr->u.c.radius); + } + } else { + pos[i] = Da.pos[i]; + radius[i] = Da.radius[i]; + center[i] = Da.center[i]; + angle[i] = Da.angle[i]; + neg = FALSE; + back = FALSE; + } + } + new.pos[0] = pos[0]; + new.pos[1] = pos[1]; + new.angle[0] = angle[0]; + new.angle[1] = angle[1]; + new.center[0] = center[0]; + new.center[1] = center[1]; + new.radius[0] = radius[0]; + new.radius[1] = radius[1]; + + track_p trk1 = NewCornuTrack(new.pos,new.center,new.angle,new.radius,NULL,0); + if (trk1==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"), + new.pos[0].x,new.pos[0].y, + new.pos[1].x,new.pos[1].y, + new.center[0].x,new.center[0].y, + new.center[1].x,new.center[1].y, + new.angle[0],new.angle[1], + FormatDistance(new.radius[0]),FormatDistance(new.radius[1])); + UndoEnd(); + return NULL; + } + return trk1; +} + struct extraData { cornuData_t cornuData; }; +ANGLE_T GetOpenAngle(coOrd pos[2],ANGLE_T angle[2],int moved) { + ANGLE_T a = FindAngle(pos[1-moved],pos[moved]); + ANGLE_T diff = (180+a)-angle[1-moved]; //Difference between input and line + return a+diff; //Change to line plus this at the other end +} + +static struct { + ANGLE_T angle; + DIST_T radius; + +} cornuModCmdContext; + +static BOOL_T infoSubst = FALSE; + +static paramFloatRange_t r10000_10000 = {-10000, 10000}; +static paramFloatRange_t r0_360 = { 0, 360, 80 }; + +static paramData_t cornuModPLs[] = { + +#define cornuModEndAnglePD (cornuModPLs[0]) +#define cornuModEndAngle 0 + { PD_FLOAT, &cornuModCmdContext.angle, "End Angle", PDO_NORECORD|BO_ENTER, &r0_360, N_("End Angle") }, +#define cornuModEndRadiusPD (cornuModPLs[1]) +#define cornuModEndRadius 1 + { PD_FLOAT, &cornuModCmdContext.radius, "End Radius", PDO_DIM|PDO_NORECORD|BO_ENTER, &r10000_10000, N_("End Radius") }, +}; +static paramGroup_t cornuModPG = { "cornuMod", 0, cornuModPLs, sizeof cornuModPLs/sizeof cornuModPLs[0] }; /* * AdjustCornuCurve @@ -509,221 +1044,535 @@ EXPORT STATUS_T AdjustCornuCurve( track_p t; DIST_T d; ANGLE_T a, a2; - DIST_T dd; EPINX_T ep; cornuParm_t cp; + wControl_p controls[5]; //Always needs a NULL last entry + char * labels[4]; + + Da.cmdType = (long)commandContext; + 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; + DYNARR_RESET(trkSeg_t,anchors_da); + infoSubst = FALSE; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.selectEndHandle = -1; + Da.prevSelected = -1; + Da.prevEndPoint = -1; + Da.extend[0] = FALSE; + Da.extend[1] = FALSE; + CreateBothEnds(Da.selectEndPoint, Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + Da.crvSegs_da.cnt = 0; + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); + InfoMessage( _("Select Point, or Add Point") ); + TempRedraw(); // AdjustCornuCurve C_START + return C_CONTINUE; + + case C_UPDATE: + if (Da.state != PICK_POINT && Da.prevSelected>-1) return C_CONTINUE; + int sel = Da.prevSelected; + if (Da.trk[sel]) return C_CONTINUE; //Track Here - should never happen + Da.radius[sel] = fabs(cornuModCmdContext.radius); + Da.angle[sel] = cornuModCmdContext.angle; + if (cornuModCmdContext.radius!=0) + Translate(&Da.center[sel],Da.pos[sel],Da.angle[sel]+90,cornuModCmdContext.radius); + CreateBothEnds(Da.prevSelected,-1,-1,Da.prevSelected); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); + return C_CONTINUE; + break; + + case wActionMove: + if (Da.state == NONE || Da.state == PICK_POINT) { + DYNARR_RESET(trkSeg_t,anchors_da); + for(int i=0;i<2;i++) { + if (IsClose(FindDistance(pos,Da.pos[i]))) { + if (((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) { + CreateCornuExtendAnchor(Da.pos[i], Da.angle[i], FALSE); + return C_CONTINUE; + } else { + CreateCornuAnchor(Da.pos[i], FALSE); + return C_CONTINUE; + } + } + } + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + Da.selectEndPoint = -1; + for (int i=0;i<Da.mid_points.cnt;i++) { + d = FindDistance(DYNARR_N(coOrd,Da.mid_points,i),pos); + if (IsClose(d)) { + CreateCornuAnchor(DYNARR_N(coOrd,Da.mid_points,i),FALSE); + return C_CONTINUE; + } + } + for (int i=0;i<2;i++) { + if (Da.endHandle[i].end_valid == FALSE) continue; + d = FindDistance(Da.endHandle[i].end_center,pos); + if (IsClose(d)) { + CreateCornuAnchor(Da.endHandle[i].end_center, FALSE); + return C_CONTINUE; + } + } + for (int i=0;i<2;i++) { + if (Da.endHandle[i].end_valid == FALSE) continue; + d = FindDistance(Da.endHandle[i].end_curve,pos); + if (IsClose(d)) { + CreateCornuAnchor(Da.endHandle[i].end_curve, FALSE); + return C_CONTINUE; + } + } + coOrd temp_pos = pos; + if (IsClose(DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,NULL))) { + CreateCornuAnchor(temp_pos, TRUE); + } + } + return C_CONTINUE; case C_DOWN: + DYNARR_RESET(trkSeg_t,anchors_da); if (Da.state != PICK_POINT) return C_CONTINUE; - dd = 10000.0; - Da.selectPoint = -1; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.selectEndHandle = -1; + Da.prevSelected = -1; + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } for (int i=0;i<2;i++) { d = FindDistance(Da.pos[i],pos); - if (d < dd) { - dd = d; - Da.selectPoint = i; + if (IsClose(d)) { + Da.selectEndPoint = i; + CreateCornuAnchor(Da.pos[i],FALSE); + break; } } - if (!IsClose(dd) ) Da.selectPoint = -1; - if (Da.selectPoint == -1) { + if (Da.selectEndPoint == -1) { + for (int i=0;i<Da.mid_points.cnt;i++) { + d = FindDistance(DYNARR_N(coOrd,Da.mid_points,i),pos); + if (IsClose(d)) { + Da.selectMidPoint = i; + Da.selectEndPoint = -1; + CreateCornuAnchor(DYNARR_N(coOrd,Da.mid_points,i),FALSE); + break; + } + } + if (Da.selectMidPoint == -1 ) { + for (int i=0;i<2;i++) { + if (Da.endHandle[i].end_valid == FALSE) continue; + d = FindDistance(Da.endHandle[i].end_center,pos); + if (IsClose(d)) { + Da.selectEndHandle = i*2; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + CreateCornuAnchor(Da.endHandle[i].end_center,i); + break; + } + } + if (Da.selectEndHandle == -1) { + for (int i=0;i<2;i++) { + if (Da.endHandle[i].end_valid == FALSE) continue; + d = FindDistance(Da.endHandle[i].end_curve,pos); + if (IsClose(d)) { + Da.selectEndHandle = 1+i*2; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + CreateCornuAnchor(Da.endHandle[i].end_curve,i); + break; + } + } + } + } + } else { //We picked an end point + if (!Da.trk[Da.selectEndPoint] && ((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) { //With Shift no track -> Extend + Da.extend[Da.selectEndPoint] = TRUE; //Adding to end Point + DYNARR_RESET(trkSeg_t,anchors_da); + CreateCornuExtendAnchor(Da.pos[Da.selectEndPoint], Da.angle[Da.selectEndPoint], FALSE); + } + } + if (Da.selectMidPoint ==-1 && Da.selectEndPoint ==-1 && Da.selectEndHandle ==-1) { + coOrd temp_pos = pos; + wIndex_t index; + if (IsClose(DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&index))) { + //Add Point between two other points + //Find closest two points along Track + int closest = -1; + wIndex_t pIndex, nIndex; + temp_pos = Da.pos[0]; + DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&pIndex); + if (Da.mid_points.cnt>0) { + for (int i=0;i<Da.mid_points.cnt;i++) { + temp_pos = DYNARR_N(coOrd ,Da.mid_points,i); + DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&nIndex); + if (((pIndex<=index) && (nIndex>=index))) { + closest = i; + break; + } + pIndex = nIndex; + } + temp_pos = Da.pos[1]; + DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&nIndex); + if (index == nIndex) closest = Da.mid_points.cnt; + if (closest == -1) + closest = Da.mid_points.cnt; + } else closest = 0; + DYNARR_APPEND(coOrd,Da.mid_points,1); + for (int i=Da.mid_points.cnt-1;i>closest;i--) { + DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd ,Da.mid_points,i-1); + } + DYNARR_N(coOrd,Da.mid_points,closest) = pos; + Da.selectMidPoint = closest; + Da.number_of_points++; + CreateCornuAnchor(pos,FALSE); + InfoMessage("Pin Point Added"); + } else { + wBeep(); + InfoMessage("Add Point Is Not on Track"); + return C_CONTINUE; + } + } + if (Da.selectEndPoint == -1 && Da.selectMidPoint == -1 && Da.selectEndHandle ==-1) { wBeep(); - InfoMessage( _("Not close enough to end point, reselect") ); + InfoMessage( _("Not close enough to track or point, reselect") ); return C_CONTINUE; } else { - pos = Da.pos[Da.selectPoint]; + if (Da.selectEndPoint >=0 ) { + pos = Da.pos[Da.selectEndPoint]; + if (Da.extend[Da.selectEndPoint]) + InfoMessage( _("Drag out end of Cornu")); + else if (Da.trk[Da.selectEndPoint]) { + InfoMessage( _("Drag along end of track")); + } else + InfoMessage( _("Drag to move")); + } else if (Da.selectMidPoint >=0 ) { + pos = DYNARR_N(coOrd,Da.mid_points,Da.selectMidPoint); + InfoMessage( _("Drag point to new location, Delete to remove")); + } else { + if (Da.selectEndHandle%2 == 0) { + pos = Da.endHandle[Da.selectEndHandle/2].end_center; + InfoMessage( _("Drag to change end radius")); + } else { + pos = Da.endHandle[Da.selectEndHandle/2].end_curve; + InfoMessage( _("Drag to change end angle")); + } + } Da.state = POINT_PICKED; - InfoMessage( _("Drag point %d to new location and release it"),Da.selectPoint+1 ); } - DrawTempCornu(); //wipe out - CreateBothEnds(Da.selectPoint); + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); SetUpCornuParms(&cp); - if (CallCornu(Da.pos, Da.trk,Da.ep, &Da.crvSegs_da, &cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) 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: + DYNARR_RESET(trkSeg_t,anchors_da); if (Da.state != POINT_PICKED) { - InfoMessage(_("Pick any circle to adjust it by dragging - Enter to accept, Esc to cancel")); + InfoMessage(_("Pick any circle to adjust or add - 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]); + if (Da.selectEndPoint >= 0) { + //If locked, reset pos to be on line from other track + int sel = Da.selectEndPoint; + coOrd pos2 = pos; + BOOL_T inside = FALSE; + if (Da.trk[sel]) { //Track + if (OnTrack(&pos,FALSE,TRUE) == Da.trk[sel]) { //And the pos is on it + inside = TRUE; + if (!QueryTrack(Da.trk[Da.selectEndPoint],Q_CORNU_CAN_MODIFY)) { //Turnouts + InfoMessage(_("Track can't be split")); + inside = FALSE; + if (Da.ep[sel]>=0) { //If not turntable + Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + } else { + if (QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)){ //Turntable + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, Da.trk[sel], pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + Da.angle[sel] = NormalizeAngle(a+180); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + } else return C_CONTINUE; + } + } + } else { + pos = pos2; //Put Back to original position as outside track } - } 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 (!inside) { + if (Da.ep[sel]>=0) { //Track defined end point + ANGLE_T diff = NormalizeAngle(GetTrkEndAngle(Da.trk[sel],Da.ep[sel])-FindAngle(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),pos)); + if (diff>90.0 && diff<270.0) { //The point is not on track but outside cone of end angle+/-90 + Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + return C_CONTINUE; + } + } else { //Not an end point + if (QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)){ //Turntable + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, Da.trk[sel], pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + coOrd edge; + Translate(&edge,tp.ttcenter,a,tp.ttradius); + ANGLE_T da = DifferenceBetweenAngles(FindAngle(edge,pos),a); + DIST_T d = fabs(FindDistance(edge,pos)*cos(R2D(da))); + Translate(&pos,edge,a,d); + Da.angle[sel] = NormalizeAngle(a+180); + Da.pos[sel] = pos; + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + Da.extendSeg[sel].type = SEG_STRTRK; + Da.extendSeg[sel].width = 0; + Da.extendSeg[sel].color = wDrawColorBlack; + Da.extendSeg[sel].u.l.pos[1-sel] = pos; + Da.extendSeg[sel].u.l.pos[sel] = edge; + Da.extend[sel] = TRUE; + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + return C_CONTINUE; //Stop moving end point + } else 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 + // 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)) // Not Turntable - may not be needed + && (!QueryTrack(Da.trk[sel],Q_HAS_VARIABLE_ENDPOINTS))) { // Not Helix or a Circle + 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 + } + } + } else if (Da.ep[sel]>=0 && inside) { //Has a point and inside track + InfoMessage(_("Can't move end inside a turnout")); //Turnouts are stuck to end-point + Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + return C_CONTINUE; } } - } - } - DrawTempCornu(); //wipe out old - Da.extend[sel] = FALSE; - if(!Da.trk[sel]) { //Cornu with no ends - struct extraData *xx = GetTrkExtraData(Da.selectTrack); - Da.pos[sel] = xx->cornuData.pos[sel]; //Re-Copy parms from old trk - Da.radius[sel] = xx->cornuData.r[sel]; - Da.angle[sel] = xx->cornuData.a[sel]; - Da.center[sel] = xx->cornuData.c[sel]; - 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); + if(!Da.trk[sel]) { //Cornu with no end + if (((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) { //Extend end locked + SetUpCornuParms(&cp); + CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,FALSE); + struct extraData *xx = GetTrkExtraData(Da.selectTrack); + 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[sel]; + Da.extend[sel] = TRUE; + } else Da.extend[sel] = FALSE; + } 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.extendSeg[sel].u.c.center, Da.radius[sel], a ); + a2 = FindAngle(Da.extendSeg[sel].u.c.center,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 { - 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; - } - if (Da.extend[sel] == FALSE) { // Not extending - so trim along our own Cornu - GetCornuParmsNear(Da.selectTrack, sel, &pos, &Da.center[sel], &Da.angle[sel], &Da.radius[sel] ); - Da.pos[sel] = pos; - } - } 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])); + coOrd offset; //Just move end (no shift) + offset.x = pos.x-Da.pos[sel].x; + offset.y = pos.y-Da.pos[sel].y; + Da.pos[sel] = pos; + if (Da.radius[sel] >0.0) { + Da.center[sel].x += offset.x; + Da.center[sel].y += offset.y; } - // 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]; + if (Da.selectTrack) { //We have track + if (!Da.trk[sel] && ((t = OnTrackIgnore(&pos,FALSE,TRUE,Da.selectTrack))!= NULL) ) { + if ((ep = PickUnconnectedEndPointSilent(pos,t))>=0) { + pos = GetTrkEndPos(t,ep); + if (IsClose(FindDistance(pos,pos)/2)) { + CreateCornuEndAnchor(pos,FALSE); + } + } + } + } else { //Not yet a track + coOrd p = pos; + Da.angle[sel] = GetOpenAngle(Da.pos,Da.angle,sel); + if ((t = OnTrack(&p,FALSE,TRUE)) !=NULL ) { + if ((ep = PickUnconnectedEndPointSilent(pos,t))>=0) { + p = GetTrkEndPos(t,ep); + if (IsClose(FindDistance(p,pos)/2)) { + CreateCornuEndAnchor(p,FALSE); + } + } + } } - } 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); + } + } else { //Cornu with ends + if (inside) Da.pos[sel] = pos; + if (!GetConnectedTrackParms(Da.trk[sel],pos,sel,Da.ep[sel],inside?FALSE:TRUE)) { + 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 + wBeep(); + InfoMessage(_("Can't extend connected Bezier or Cornu")); + pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + return C_CONTINUE; } - 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 Da.pos[sel] = pos; + } + } else if (Da.selectMidPoint >=0){ + DYNARR_N(coOrd,Da.mid_points,Da.selectMidPoint) = pos; + } else if (Da.selectEndHandle >=0) { //Cornu has no end, so has handles + int end = Da.selectEndHandle/2; + if (Da.selectEndHandle%2 == 0) { //Radius + coOrd p0 = Da.pos[end]; //Start + coOrd p1 = Da.endHandle[end].end_curve; //End + ANGLE_T a0 = FindAngle( p1, p0 ); + DIST_T d0 = FindDistance( p0, p1 )/2.0; //Distance to Middle of Chord + coOrd pos2 = pos; //New pos + Rotate( &pos2, p1, -a0 ); + pos2.x -= p1.x; //Deflection at right angles to Chord + DIST_T r = 1000.0; + if ( fabs(pos2.x) >= 0.01 ) { //Not zero + double d2 = sqrt( d0*d0 + pos2.x*pos2.x )/2.0; + r = d2*d2*2.0/pos2.x; + if ( fabs(r) > 1000.0 ) { //Limit Radius + r = 0.0; + //r = ((r > 0) ? 1 : -1 ) *1000.0; } - - } else { //Bezier and Cornu that we are joining TO can't extend - DrawTempCornu(); //put back - wBeep(); - InfoMessage(_("Can't extend connected Bezier or Cornu")); - pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); - return C_CONTINUE; + } else { + r = 0.0; + //r = ((r > 0) ? 1 : -1 ) *1000.0; } + coOrd posx; //Middle of chord + posx.x = (p1.x-p0.x)/2.0 + p0.x; + posx.y = (p1.y-p0.y)/2.0 + p0.y; + a0 -= 90.0; + if (r<0) { //Negative radius means other side + coOrd pt = p0; + p0 = p1; + p1 = pt; + a0 += 180.0; + } + coOrd pc; + if (r == 0.0) { + Da.center[end] = zero; + Da.radius[end] = 0.0; + Da.angle[end] = FindAngle(Da.pos[end],Da.endHandle[end].end_curve); + } else { + Translate( &pc, posx, a0, fabs(r) - fabs(pos2.x) ); //Move Radius less Deflection to get to center + Da.center[end] = pc; + if (DifferenceBetweenAngles(FindAngle(Da.center[end],Da.pos[end]),FindAngle(Da.center[end],Da.endHandle[end].end_curve))>0.0) + Da.angle[end] = NormalizeAngle(FindAngle(Da.center[end],Da.pos[end])+90.0); + else + Da.angle[end] = NormalizeAngle(FindAngle(Da.center[end],Da.pos[end])-90.0); + Da.radius[end] = fabs(r); + } + } else { + Da.angle[end] = FindAngle(Da.pos[end],pos); + Da.radius[end] = 0.0; + Translate(&Da.center[end],Da.pos[end],NormalizeAngle(Da.angle[end]+90.0),Da.radius[end]); } } - - CreateBothEnds(Da.selectPoint); + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); 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; + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; else Da.crvSegs_da_cnt = 0; + for (int i=0;i<2;i++) { + if (Da.trk[i] || Da.ends[i]) continue; + coOrd p = Da.pos[i]; + Da.angle[i] = NormalizeAngle((i?0:180)+GetAngleSegs( Da.crvSegs_da_cnt, Da.crvSegs_da.ptr, &p, NULL, NULL, NULL, NULL, NULL)); + Da.radius[i] = 0.0; + } Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); DIST_T rin = Da.radius[0]; InfoMessage( _("Cornu : Min Radius=%s MaxRateofCurveChange/Scale=%s Length=%s Winding Arc=%s"), @@ -731,25 +1580,121 @@ EXPORT STATUS_T AdjustCornuCurve( FormatFloat(CornuMaxRateofChangeofCurvature(Da.pos,Da.crvSegs_da,&rin)*GetScaleRatio(GetLayoutCurScale())), 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; + DYNARR_RESET(trkSeg_t,anchors_da); + if (Da.state != POINT_PICKED) { + Da.state = PICK_POINT; + return C_CONTINUE; + } ep = 0; - DrawTempCornu(); //wipe out - Da.selectPoint = -1; - CreateBothEnds(Da.selectPoint); + if (Da.selectMidPoint!=-1) Da.prevSelected = Da.selectMidPoint; + else if (Da.selectEndPoint!=-1) { + if (!Da.trk[Da.selectEndPoint] && + (t=OnTrack(&pos,FALSE,TRUE)) != NULL && t != Da.selectTrack ) { + EPINX_T ep = PickUnconnectedEndPoint(pos,t); + if (ep>=0) { + 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(pos, t); //EP + if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) { + ep=-1; //Don't attach to Turntable + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + } + 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 Valid end point on that track")); + return C_CONTINUE; + } + if (GetTrkScale(t) != (char)GetLayoutCurScale()) { + wBeep(); + InfoMessage(_("Track is different scale")); + return C_CONTINUE; + } + } + if (ep>=0 && t) { //Real end point, real track + Da.trk[Da.selectEndPoint] = t; + Da.ep[Da.selectEndPoint] = ep; // Note: -1 for Turntable or Circle + pos = GetTrkEndPos(t,ep); + Da.pos[Da.selectEndPoint] = pos; + if (!GetConnectedTrackParms(t,pos,Da.selectEndPoint,ep,FALSE)) return C_CONTINUE; + } + } else { + cornuModCmdContext.angle = NormalizeAngle(Da.angle[Da.selectEndPoint]); + cornuModCmdContext.radius = Da.radius[Da.selectEndPoint]; + if (DifferenceBetweenAngles(FindAngle(Da.center[Da.selectEndPoint],Da.pos[Da.selectEndPoint]),Da.angle[Da.selectEndPoint])<0.0) + cornuModCmdContext.radius = -cornuModCmdContext.radius; + controls[0] = cornuModEndRadiusPD.control; + controls[1] = cornuModEndAnglePD.control; + controls[2] = NULL; + labels[0] = N_("End Radius"); + labels[1] = N_("End Angle"); + ParamLoadControls( &cornuModPG ); + InfoSubstituteControls( controls, labels ); + cornuModEndRadiusPD.option &= ~PDO_NORECORD; + cornuModEndAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + Da.prevSelected = Da.selectEndPoint; + Da.selectEndHandle = -1; + } + } else if (Da.selectEndHandle!=-1) { + Da.prevSelected = Da.selectEndHandle>2?1:0; + cornuModCmdContext.angle = NormalizeAngle(Da.angle[Da.prevSelected]); + cornuModCmdContext.radius = Da.radius[Da.prevSelected]; + if (DifferenceBetweenAngles(FindAngle(Da.center[Da.prevSelected],Da.pos[Da.prevSelected]),Da.angle[Da.prevSelected])<0.0) + cornuModCmdContext.radius = -cornuModCmdContext.radius; + controls[0] = cornuModEndRadiusPD.control; + controls[1] = cornuModEndAnglePD.control; + controls[2] = NULL; + labels[0] = N_("End Radius"); + labels[1] = N_("End Angle"); + ParamLoadControls( &cornuModPG ); + InfoSubstituteControls( controls, labels ); + cornuModEndRadiusPD.option &= ~PDO_NORECORD; + cornuModEndAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + Da.selectEndHandle = -1; + } + Da.selectEndPoint = -1; Da.selectMidPoint = -1; + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); SetUpCornuParms(&cp); - if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) 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(); + InfoMessage(_("Pick on point to adjust it along track - Delete to remove, Enter to confirm, ESC to abort")); Da.state = PICK_POINT; return C_CONTINUE; + case C_TEXT: + DYNARR_RESET(trkSeg_t,anchors_da); + //Delete or backspace deletes last selected index + if (action>>8 == 127 || action>>8 == 8) { + if ((Da.state == PICK_POINT) && Da.prevSelected !=-1) { + for (int i=Da.prevSelected;i<Da.mid_points.cnt;i++) { + DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i+1); + } + Da.mid_points.cnt--; + } + Da.prevSelected = -1; + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + cornuParm_t cp; + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + return C_CONTINUE; + } + return C_CONTINUE; + case C_OK: //C_OK is not called by Modify. + DYNARR_RESET(trkSeg_t,anchors_da); if ( Da.state == PICK_POINT ) { Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); if (CornuTotalWindingArc(Da.pos,Da.crvSegs_da)>4*360) { @@ -762,63 +1707,109 @@ EXPORT STATUS_T AdjustCornuCurve( return C_CONTINUE; } for (int i=0;i<2;i++) { - if (!(QueryTrack(Da.trk[i],Q_CAN_ADD_ENDPOINTS))) { // Not Turntable + if (Da.trk[i] && !(QueryTrack(Da.trk[i],Q_CAN_ADD_ENDPOINTS))) { // Not Turntable 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); + InfoMessage(_("Cornu point %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; + UndoStart( _("Create Cornu"),"newCornu curves"); + BOOL_T end_point[2]; + end_point[0] = TRUE; + end_point[1] = FALSE; + coOrd sub_pos[2]; + sub_pos[0] = Da.pos[0]; + if (Da.radius[0] == -1) end_point[0] = FALSE; + track_p first_trk= NULL,trk1=NULL,trk2 = NULL; + + for (int i=0;i<Da.mid_points.cnt;i++) { + sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i); + if ((trk1 = CreateCornuFromPoints(sub_pos,end_point))== NULL) return C_TERMINATE; + if (Da.trk[0]) { + CopyAttributes( Da.trk[0], trk1 ); + } else if (Da.trk[1]) { + CopyAttributes( Da.trk[1], trk1 ); + } else { + SetTrkScale( trk1, GetLayoutCurScale() ); + SetTrkBits( trk1, TB_HIDEDESC ); + } + DrawNewTrack(trk1); + if (first_trk == NULL) first_trk = trk1; + if (trk2) ConnectTracks(trk1,0,trk2,1); + trk2 = trk1; + end_point[0] = FALSE; + sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i); } - - CopyAttributes( Da.trk[0], t ); + sub_pos[1] = Da.pos[1]; + end_point[1] = TRUE; + if (Da.radius[1] == -1) end_point[1] = FALSE; + if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == NULL) return C_TERMINATE; + if (Da.trk[0]) { + CopyAttributes( Da.trk[0], trk1 ); + } else if (Da.trk[1]){ + CopyAttributes( Da.trk[1], trk1 ); + } else { + SetTrkScale( trk1, GetLayoutCurScale() ); + SetTrkBits( trk1, TB_HIDEDESC ); + } + if (trk2) ConnectTracks(trk1,0,trk2,1); + if (first_trk == NULL) first_trk = trk1; + //t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius,(trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt); 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]); + if (Da.trk[i]) { + UndoModify(Da.trk[i]); + MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0); + //End position not precise, so readjust Cornu + GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i],FALSE); 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]); + SetCornuEndPt(i==0?first_trk:trk1,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],i==0?first_trk:trk1,i); } - if (Da.ep[i]>=0) - ConnectTracks(Da.trk[i],Da.ep[i],t,i); } UndoEnd(); - DrawNewTrack(t); + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } Da.state = NONE; - MainRedraw(); - MapRedraw(); return C_TERMINATE; } return C_CONTINUE; case C_REDRAW: + if (Da.state == NONE) return C_CONTINUE; DrawTempCornu(); + if (anchors_da.cnt) { + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + } return C_CONTINUE; + case C_CANCEL: + case C_FINISH: + break; default: return C_CONTINUE; } + return C_CONTINUE; } +static void cornuModDlgUpdate( + paramGroup_p pg, + int inx, + void * valueP ) +{ + AdjustCornuCurve(C_UPDATE, zero, InfoMessage); + ParamLoadControl(&cornuModPG,cornuModEndRadius); // Make sure Radius updated + ParamLoadControl(&cornuModPG,cornuModEndAngle); //Relative Angle as well + TempRedraw(); + +} /** * CmdCornuModify @@ -835,11 +1826,12 @@ EXPORT STATUS_T AdjustCornuCurve( * */ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG ) { - track_p t; struct extraData *xx = GetTrkExtraData(trk); Da.trackGauge = trackG; + Da.commandType = CORNU_MODIFY; + switch (action&0xFF) { case C_START: Da.state = NONE; @@ -847,42 +1839,90 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG Da.ep1Segs_da_cnt = 0; Da.ep2Segs_da_cnt = 0; Da.crvSegs_da_cnt = 0; + Da.midSegs.cnt = 0; Da.extend[0] = FALSE; Da.extend[1] = FALSE; - Da.selectPoint = -1; + Da.selectEndPoint = -1; Da.selectTrack = NULL; + DYNARR_RESET(coOrd,Da.mid_points); + DYNARR_RESET(track_p,Da.tracks); Da.selectTrack = trk; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = trk; Da.trk[0] = GetTrkEndTrk( trk, 0 ); + track_p prior = trk; 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); + EPINX_T ep0 = 0; + //Move down the LHS adding tracks until no more Cornu + while (Da.trk[0] && QueryTrack(Da.trk[0],Q_IS_CORNU)) { + prior = Da.trk[0]; + ep0 = 1-Da.ep[0]; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = prior; + DYNARR_APPEND(coOrd,Da.mid_points,1); + for (int i=Da.mid_points.cnt-1;i>0;i--) { + DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i-1); + } + DYNARR_N(coOrd,Da.mid_points,0) = GetTrkEndPos(prior,1-ep0); + Da.trk[0] = GetTrkEndTrk( prior, ep0 ); + if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],prior); + else Da.ep[0] = -1; + } + if (prior) { + struct extraData *xx0 = GetTrkExtraData(prior); + Da.pos[0] = xx0->cornuData.pos[ep0]; //Copy parms from FIRST CORNU trk + Da.radius[0] = xx0->cornuData.r[ep0]; + Da.angle[0] = xx0->cornuData.a[ep0]; + Da.center[0] = xx0->cornuData.c[ep0]; + } - 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]; - } + //Move to RHS + Da.trk[1] = GetTrkEndTrk( trk, 1 ); + track_p next = trk; + EPINX_T ep1 = 1; + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk); + //Move down RHS adding tracks until no more Cornu + while (Da.trk[1] && QueryTrack(Da.trk[1],Q_IS_CORNU)) { + next = Da.trk[1]; + ep1 = 1-Da.ep[1]; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = next; + DYNARR_APPEND(coOrd,Da.mid_points,1); + DYNARR_LAST(coOrd,Da.mid_points) = GetTrkEndPos(next,1-ep1); + Da.trk[1] = GetTrkEndTrk( next, ep1 ); + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],next); + } - 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; - } + if (next) { + struct extraData *xx1 = GetTrkExtraData(next); + Da.pos[1] = xx1->cornuData.pos[ep1]; //Copy parms from LAST CORNU trk + Da.radius[1] = xx1->cornuData.r[ep1]; + Da.angle[1] = xx1->cornuData.a[ep1]; + Da.center[1] = xx1->cornuData.c[ep1]; + } - InfoMessage(_("Track picked - now select a Point")); + InfoMessage(_("Now Select or Add (+Shift) a Point")); Da.state = TRACK_SELECTED; - DrawTrack(Da.selectTrack,&mainD,wDrawColorWhite); //Wipe out real track, draw replacement + for (int i=0;i<Da.tracks.cnt;i++) { + DrawTrack(DYNARR_N(track_p,Da.tracks,i),&mainD,wDrawColorWhite); //Wipe out real tracks, draw replacement + } return AdjustCornuCurve(C_START, pos, InfoMessage); + case wActionMove: + return AdjustCornuCurve(wActionMove, pos, InfoMessage); + break; + case C_DOWN: if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up return AdjustCornuCurve(C_DOWN, pos, InfoMessage); + case C_LCLICK: + if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up + AdjustCornuCurve(C_DOWN, pos, InfoMessage); + return AdjustCornuCurve(C_UP, pos, InfoMessage); case C_MOVE: if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up and down @@ -895,10 +1935,19 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG return AdjustCornuCurve(C_UP, pos, InfoMessage); //Run Adjust case C_TEXT: - if ((action>>8) != 32) + //Delete or backspace deletes last selected index + if (action>>8 == 127 || action>>8 == 8) { + return AdjustCornuCurve(action, pos, InfoMessage); + } + //Space bar or enter means done + if ( (action>>8 != ' ') && (action>>8 != 13) ) return C_CONTINUE; /* no break */ case C_OK: + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } if (Da.state != PICK_POINT) { //Too early - abandon InfoMessage(_("No changes made")); Da.state = NONE; @@ -928,23 +1977,59 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG } 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 (FindDistance(GetTrkEndPos(Da.trk[i],0),Da.pos[i])<=connectDistance) { + Da.ep[i] = 0; + } else Da.ep[i] = 1; } if (!Da.trk[i]) { wBeep(); InfoMessage(_("Cornu Extension Create Failed for end %d"),i); + Da.state = NONE; 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) { + BOOL_T end_point[2]; + end_point[0] = TRUE; + end_point[1] = FALSE; + coOrd sub_pos[2]; + sub_pos[0] = Da.pos[0]; + + track_p first_trk= NULL,trk1=NULL,trk2 = NULL; + for (int i=0;i<Da.mid_points.cnt;i++) { + sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i); + if ((trk1 = CreateCornuFromPoints(sub_pos, end_point))== 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(); + Da.state = NONE; + return C_TERMINATE; + } + if (Da.trk[0]) { + CopyAttributes( Da.trk[0], trk1 ); + } else if (Da.trk[1]) { + CopyAttributes( Da.trk[1], trk1 ); + } else { + SetTrkScale( trk1, GetLayoutCurScale() ); + SetTrkBits( trk1, TB_HIDEDESC ); + } + DrawNewTrack(trk1); + if (first_trk == NULL) first_trk = trk1; + if (trk2) ConnectTracks(trk1,0,trk2,1); + trk2 = trk1; + end_point[0] = FALSE; + sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i); + } + sub_pos[1] = Da.pos[1]; + end_point[1] = TRUE; + if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == 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, @@ -954,15 +2039,26 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG Da.angle[0],Da.angle[1], FormatDistance(Da.radius[0]),FormatDistance(Da.radius[1])); UndoUndo(); - MainRedraw(); - MapRedraw(); - //DYNARR_FREE(trkSeg_t,Da.crvSegs_da); + Da.state = NONE; return C_TERMINATE; } + DrawNewTrack(trk1); + if (Da.trk[0]) { + CopyAttributes( Da.trk[0], trk1 ); + } else if (Da.trk[1]) { + CopyAttributes( Da.trk[1], trk1 ); + } else { + SetTrkScale( trk1, GetLayoutCurScale() ); + SetTrkBits( trk1, TB_HIDEDESC ); + } + if (trk2) ConnectTracks(trk1,0,trk2,1); + if (first_trk == NULL) first_trk = trk1; - CopyAttributes( trk, t ); + Da.state = NONE; //Must do before Delete - DeleteTrack(trk, TRUE); + for (int i=0;i<Da.tracks.cnt;i++) { + DeleteTrack(DYNARR_N(track_p,Da.tracks,i), TRUE); + } if (Da.trk[0]) UndoModify(Da.trk[0]); if (Da.trk[1]) UndoModify(Da.trk[1]); @@ -970,13 +2066,12 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG for (int i=0;i<2;i++) { //Attach new track if (Da.trk[i] && Da.ep[i] != -1) { //Like the old track if (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]); - } + //Bezier split position not precise, so readjust Cornu + GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i],FALSE); + ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180); + SetCornuEndPt(i==0?first_trk:trk1,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]); + ConnectTracks(i==0?first_trk:trk1,i,Da.trk[i],Da.ep[i]); } else { UndoUndo(); wBeep(); @@ -986,18 +2081,18 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG } } UndoEnd(); - MainRedraw(); - MapRedraw(); Da.state = NONE; - //DYNARR_FREE(trkSeg_t,Da.crvSegs_da); + //DYNARR_FREE(trkSeg_t,Da.crvSegs_da) return C_TERMINATE; case C_CANCEL: InfoMessage(_("Modify Cornu Cancelled")); Da.state = NONE; + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } //DYNARR_FREE(trkSeg_t,Da.crvSegs_da); - MainRedraw(); - MapRedraw(); return C_TERMINATE; case C_REDRAW: @@ -1028,6 +2123,22 @@ DIST_T CornuLength(coOrd pos[4],dynArr_t segs) { return dd; } +DIST_T CornuOffsetLength(dynArr_t segs, double offset) { + 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+(t.u.c.radius>0?offset:-offset))*D2R(t.u.c.a1)); + } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) { + dd +=CornuOffsetLength(t.bezSegs,offset); + } 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; @@ -1081,6 +2192,9 @@ DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4], dynArr_t segs, DIST_T * las return r_max; } + + + /* * Create a Cornu Curve Track * Sequence is @@ -1091,167 +2205,359 @@ DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4], dynArr_t segs, DIST_T * las */ STATUS_T CmdCornu( wAction_t action, coOrd pos ) { - track_p t; + track_p t = NULL; cornuParm_t cp; - Da.color = lineColor; + Da.commandType = CORNU_CREATE; + Da.width = (double)lineWidth/mainD.dpi; Da.trackGauge = trackGauge; + Da.selectTrack = NULL; switch (action&0xFF) { case C_START: + Da.cmdType = (long)commandContext; Da.state = NONE; - Da. selectPoint = -1; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.endHandle[0].end_valid = FALSE; + Da.endHandle[1].end_valid = FALSE; for (int i=0;i<2;i++) { + Da.ends[i] = FALSE; Da.pos[i] = zero; + Da.angle[i] = 0.0; + Da.radius[i] = -1.0; } 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.crvSegs_da_cnt = 0; + Da.midSegs.cnt = 0; + DYNARR_RESET(coOrd,Da.mid_points); + DYNARR_RESET(track_p,Da.tracks); + DYNARR_RESET(trkSeg_t,anchors_da); 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") ); + if (Da.cmdType == cornuCmdCreateTrack) + InfoMessage( _("Left click - Start Cornu track") ); + else if (Da.cmdType == cornuCmdHotBar) { + InfoMessage( _("Left click - Place Flextrack") ); + } else { + 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: + DYNARR_RESET(trkSeg_t,anchors_da); 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)) { + t = NULL; + int end = 0; + if (Da.state != NONE) end=1; + EPINX_T ep = -1; + //Lock to endpoint if one is available and under pointer + if ((t = OnTrack(&p, FALSE, TRUE)) != NULL && t != Da.selectTrack) { + 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)) { + wBeep(); InfoMessage(_("Helix Already Connected")); - return C_CONTINUE; + t= NULL; } 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; + } else if (QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) { + ep=-1; //Don't attach to existing Turntable ep + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + p = pos; //Fix to wall of turntable initially + } else ep = PickUnconnectedEndPointSilent(p, t); //EP + if ( t && 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 valid open endpoint on that track")); + t = NULL; + } + if (t && GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) { + wBeep(); + InfoMessage(_("Track is different gauge")); + t = NULL; } + } + if (ep>=0 && t) { //Real end point, real track Da.trk[end] = t; Da.ep[end] = ep; // Note: -1 for Turntable or Circle - if (ep ==-1) pos = p; - else pos = GetTrkEndPos(t,ep); + pos = GetTrkEndPos(t,ep); Da.pos[end] = pos; - InfoMessage( _("Place 2nd end point of Cornu track on track with an unconnected end-point") ); - } else { + Da.angle[end] = GetTrkEndAngle(t,ep); + } else if (t == NULL) { //end not on Track, OK for CreateCornu -> empty end point + pos = p; //Reset to initial + SnapPos( &pos ); + if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) { + Da.trk[end] = NULL; + Da.pos[end] = pos; + Da.radius[end] = -1.0; //No End Rad for open + if (Da.state == NONE ) { + Da.state = POS_1; + Da.angle[0] = 270.0; + Da.radius[0] = 0.0; + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,TRUE,TRUE,FALSE,Da.angle[0],Da.radius[0],zero,&Da.endHandle[0]); + Da.ep2Segs_da_cnt = 0; + InfoMessage( _("Drag arm in the direction of track") ); + return C_CONTINUE; + } + Da.state = POS_2; //Now this is second end and it is open + Da.selectEndPoint = 1; + Da.mid_points.cnt=0; + Da.angle[1] = GetOpenAngle(Da.pos,Da.angle,1); + Da.radius[1] = 0.0; + CreateBothEnds(1,-1,-1,-1); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) + Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + InfoMessage( _("Drag arm in the direction of track") ); + return C_CONTINUE; + } wBeep(); - InfoMessage(_("No Unconnected Track End there")); + InfoMessage(_("No Unconnected Track End there")); //Not creating a Cornu - Join can't be open return C_CONTINUE; + } else { + Da.pos[end] = p; + //Either a real end or a track but no end } if (Da.state == NONE) { - if (!GetConnectedTrackParms(t, pos, 0, Da.ep[0])) { + if (!GetConnectedTrackParms(t, pos, 0, Da.ep[0],FALSE)) { //Must get parms Da.trk[0] = NULL; + Da.ep[0] = -1; + wBeep(); + InfoMessage(_("No Valid Track End there")); return C_CONTINUE; } + if (ep<0) { + Da.trk[0] = t; + Da.pos[0] = p; + Da.ep[0] = ep; + } 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) { + Da.selectEndPoint = 0; //Select first 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), + Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL); + InfoMessage( _("Locked - Move 1st end point of Cornu track along track 1") ); + return C_CONTINUE; + } else { //Second Point + if (Da.trk[0] == t) { ErrorMessage( MSG_JOIN_CORNU_SAME ); Da.trk[1] = NULL; + Da.ep[1] = -1; return C_CONTINUE; } - if (!GetConnectedTrackParms(t, pos, 1, Da.ep[1])) { + if (!GetConnectedTrackParms(t, pos, 1, Da.ep[1],FALSE)) { Da.trk[1] = NULL; //Turntable Fail + wBeep(); + InfoMessage(_("No Valid Track End there")); return C_CONTINUE; } + if (ep<0) { + Da.trk[1] = t; + Da.pos[1] = p; + Da.ep[1] = -1; + Da.radius[1] = 0.0; + } CorrectHelixAngles(); - Da.selectPoint = 1; + Da.selectEndPoint = 1; //Select second end point 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") ); + InfoMessage( _("Locked - Move 2nd end point of Cornu track along track 2") ); } + CreateBothEnds(1,-1,-1,-1); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) + Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; return C_CONTINUE; - } else { + } else { //This is after both ends exist return AdjustCornuCurve( action&0xFF, pos, InfoMessage ); } return C_CONTINUE; + + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if (Da.state != NONE && Da.state != LOC_2) return C_CONTINUE; + if (Da.trk[0] && Da.trk[1]) return C_CONTINUE; + EPINX_T ep = -1; + t = NULL; + if (((MyGetKeyState() & WKEY_ALT) == 0) == magneticSnap) { + //Lock to endpoint if one is available and under pointer + if ((t = OnTrack(&pos, FALSE, TRUE)) != NULL && t != Da.selectTrack) { + 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)) { + return C_CONTINUE; + } + ep = -1; //Not a real ep yet + } else ep = PickUnconnectedEndPointSilent(pos, t); //EP + if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) ep=-1; //Don't attach to Turntable + if ( ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle + return C_CONTINUE; + } + if (GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) { + return C_CONTINUE; + } + if (Da.state != NONE && t==Da.trk[0]) return C_CONTINUE; + } + } + if (ep>=0 && t) { + pos = GetTrkEndPos(t,ep); + CreateCornuEndAnchor(pos,TRUE); + } else if (t) { + trackParams_t tp; //Turntable or extendable track + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + if (QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) { + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + CreateCornuEndAnchor(pos,TRUE); + } else CreateCornuEndAnchor(pos,TRUE); + } + + return C_CONTINUE; case C_MOVE: - if (Da.state == NONE) { - InfoMessage("Place 1st end point of Cornu track on unconnected end-point"); + if (Da.state == NONE) { //First point not created + if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) { + InfoMessage("Place 1st end point of Cornu track"); + } else + InfoMessage("Place 1st end point of Cornu track on unconnected end-point"); return C_CONTINUE; } - if (Da.state == POS_1) { + if (Da.state == POS_1) { //First point has been created + if ((Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) && !Da.trk[0]) { //OK for CreateCornu -> No track selected + if (IsClose(FindDistance(pos,Da.pos[0]))) return C_CONTINUE; + Da.selectEndPoint = 0; + Da.angle[0] = NormalizeAngle(FindAngle(Da.pos[0],pos)+180); + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],TRUE,TRUE,TRUE,FALSE,Da.angle[0],0.0,zero,&Da.endHandle[0]); + Da.radius[1] = -1.0; /*No end*/ + return C_CONTINUE; + } 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")); + InfoMessage(_("Track can't be split - so locked to endpoint")); 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; + Da.selectEndPoint = 0; 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])) { + if (!GetConnectedTrackParms(t, pos, ep, Da.ep[ep],FALSE)) { Da.state = POS_1; - Da.selectPoint = 1; + Da.selectEndPoint = 0; 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 { + 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), + Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL); + } else if (Da.state == POS_2 && + (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) && !Da.trk[1]) { //OK for CreateCornu -> No track selected + if (IsClose(FindDistance(pos,Da.pos[1]))) return C_CONTINUE; + Da.selectEndPoint = 1; + Da.angle[1] = NormalizeAngle(FindAngle(Da.pos[1],pos)+180); + Da.radius[1] = 0.0; /*No end*/ + Da.ep1Segs_da_cnt = createEndPoint(Da.ep2Segs,Da.pos[1],TRUE,TRUE,TRUE,FALSE,Da.angle[1],0.0,zero,&Da.endHandle[1]); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + CreateBothEnds(-1,-1,-1,-1); + Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); + return C_CONTINUE; + } else { //Second Point Has Been Created and aligned 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); + if (Da.state == POS_1 && (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar || Da.trk[0])) { Da.state = LOC_2; + Da.selectEndPoint = -1; + if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) { + if (Da.cmdType == cornuCmdCreateTrack) + InfoMessage( _("Pick other end of Cornu") ); + else + InfoMessage( _("Select flextrack ends or anchors and drag, Enter to approve, Esc to Cancel") ); + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,TRUE,TRUE,FALSE,0.0,0.0,zero,NULL); + return C_CONTINUE; + } 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); + if (Da.trk[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), + Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL); + else + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,TRUE,TRUE,FALSE, Da.angle[0],Da.radius[0],Da.center[0],&Da.endHandle[0]); + return C_CONTINUE; + } else if (Da.state == POS_2 && (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar || Da.trk[1] )){ + Da.state = PICK_POINT; + Da.selectEndPoint = -1; + Da.prevEndPoint = 1; + Da.prevSelected = -1; + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + CreateBothEnds(-1,-1,-1,-1); + Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); return C_CONTINUE; } else { return AdjustCornuCurve( action&0xFF, pos, InfoMessage ); } + return C_CONTINUE; + break; case C_TEXT: - if (Da.state != PICK_POINT || (action>>8) != 32) //Space is same as Enter. + if (Da.state != PICK_POINT) return C_CONTINUE; + if ((action>>8 == 127) || (action>>8 == 8)) // + return AdjustCornuCurve(action, pos, InfoMessage); + if (!(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); + STATUS_T rc = AdjustCornuCurve( C_OK, pos, InfoMessage); + if (rc == C_TERMINATE) { + Da.state = NONE; + 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; + Da.endHandle[i].end_valid = FALSE; + } + } + return rc; 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.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,Da.color); + 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.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,(trkSeg_t *)Da.midSegs.ptr,Da.midSegs.cnt,wDrawColorBlack); } + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + if (MyGetKeyState()&WKEY_SHIFT) DrawHighlightBoxes(FALSE,FALSE,NULL); + 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.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,Da.color); Da.ep1Segs_da_cnt = 0; Da.ep2Segs_da_cnt = 0; Da.crvSegs_da_cnt = 0; @@ -1262,21 +2568,486 @@ STATUS_T CmdCornu( wAction_t action, coOrd pos ) Da.trk[i] = NULL; Da.ep[i] = -1; Da.pos[i] = zero; + Da.endHandle[i].end_valid = FALSE; } //DYNARR_FREE(trkSeg_t,Da.crvSegs_da); } Da.state = NONE; + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } return C_CONTINUE; default: return C_CONTINUE; } + return C_CONTINUE; +} +BOOL_T GetTracksFromCornuTrack(track_p trk, track_p newTracks[2]) { + track_p trk_old = NULL; + newTracks[0] = NULL, newTracks[1] = NULL; + struct extraData * xx = GetTrkExtraData(trk); + if (!IsTrack(trk)) return FALSE; + for (int i=0; i<xx->cornuData.arcSegs.cnt;i++) { + track_p bezTrack[2]; + bezTrack[0] = NULL, bezTrack[1] = NULL; + trkSeg_p seg = &DYNARR_N(trkSeg_t,xx->cornuData.arcSegs,i); + if (seg->type == SEG_BEZTRK) { + DYNARR_RESET(trkSeg_t,seg->bezSegs); + FixUpBezierSeg(seg->u.b.pos,seg,TRUE); + GetTracksFromBezierSegment(seg, bezTrack, trk); + if (newTracks[0] == NULL) newTracks[0] = bezTrack[0]; + newTracks[1] = bezTrack[1]; + if (trk_old) { + for (int i=0;i<2;i++) { + if (GetTrkEndTrk(trk_old,i)==NULL) { + coOrd pos = GetTrkEndPos(trk_old,i); + EPINX_T ep_n = PickUnconnectedEndPoint(pos,bezTrack[0]); + if ((connectDistance >= FindDistance(GetTrkEndPos(trk_old,i),GetTrkEndPos(bezTrack[0],ep_n))) && + (connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(trk_old,i),GetTrkEndAngle(bezTrack[0],ep_n)+180))) ) { + ConnectTracks(trk_old,i,bezTrack[0],ep_n); + break; + } + } + } + } + trk_old = newTracks[1]; + } else { + track_p new_trk; + if (seg->type == SEG_CRVTRK) + new_trk = NewCurvedTrack(seg->u.c.center,seg->u.c.radius,seg->u.c.a0,seg->u.c.a1,0); + else if (seg->type == SEG_STRTRK) + new_trk = NewStraightTrack(seg->u.l.pos[0],seg->u.l.pos[1]); + if (newTracks[0] == NULL) newTracks[0] = new_trk; + CopyAttributes( trk, new_trk ); + newTracks[1] = new_trk; + if (trk_old) { + for (int i=0;i<2;i++) { + if (GetTrkEndTrk(trk_old,i)==NULL) { + coOrd pos = GetTrkEndPos(trk_old,i); + EPINX_T ep_n = PickUnconnectedEndPoint(pos,new_trk); + if ((connectDistance >= FindDistance(GetTrkEndPos(trk_old,i),GetTrkEndPos(new_trk,ep_n))) && + (connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(trk_old,i),GetTrkEndAngle(new_trk,ep_n)+180)))) { + ConnectTracks(trk_old,i,new_trk,ep_n); + break; + } + } + } + } + trk_old = new_trk; + } + } + return TRUE; + +} + +static STATUS_T cmdCornuCreate( + wAction_t action, + coOrd pos ) { + static int createState = 0; + int rc = 0; + + switch(action&0xFF) { + + case C_DOWN: + return CmdCornu(C_DOWN,pos); + case C_UP: + rc = CmdCornu(C_UP,pos); + return rc; + case C_FINISH: + if (createState != 0 ) { + createState = 0; + CmdCornu( C_OK, pos ); + } else + CmdCornu( C_CANCEL, pos ); + Da.prevSelected = -1; + Da.selectEndHandle = -1; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.selectTrack = NULL; + Da.trk[0] = NULL; Da.trk[1] = NULL; + Da.radius[0] = Da.radius[1] = -1.0; + Da.angle[0] = Da.angle[1] = 0.0; + Da.ends[0] = Da.ends[1] = FALSE; + Da.endHandle[0].end_valid = Da.endHandle[1].end_valid = FALSE; + return C_TERMINATE; + case C_TEXT: + if ((action>>8) != ' ' && (action>>8) != 32) + return CmdCornu(action,pos); + /*no break*/ + case C_OK: + CmdCornu(C_OK,pos); + MainRedraw(); + return C_CONTINUE; + case C_CANCEL: + HotBarCancel(); + CmdCornu(C_CANCEL, pos); + createState = 0; + rc = C_TERMINATE; + /* no break */ + case C_START: + createState = 0; + commandContext = (void *)cornuCmdHotBar; + rc = CmdCornu(C_START, pos); + Da.prevSelected = -1; + Da.selectEndHandle = -1; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.selectTrack = NULL; + Da.trk[0] = NULL; Da.trk[1] = NULL; + Da.radius[0] = Da.radius[1] = -1.0; + Da.angle[0] = Da.angle[1] = 0.0; + Da.ends[0] = Da.ends[1] = FALSE; + Da.endHandle[0].end_valid = Da.endHandle[1].end_valid = FALSE; + return rc; + default: + return CmdCornu(action,pos); + } + return C_CONTINUE; } +static STATUS_T CmdConvertTo( + wAction_t action, + coOrd pos ) +{ + static track_p trk; + cornuParm_t cp; + switch (action) { + + case wActionMove: + if ((trk = OnTrack(&pos,FALSE,TRUE)) == NULL) return C_CONTINUE; + if (!QueryTrack(trk, Q_CORNU_CAN_MODIFY) && //Not Fixed Track/Turnout/Turntable + !QueryTrack(trk, Q_IGNORE_EASEMENT_ON_EXTEND )) + trk = NULL; + return C_CONTINUE; + + case C_LCLICK: + if ((trk = OnTrack(&pos,FALSE,TRUE))!=NULL) { + SetTrkBits(trk,TB_SELECTED); + selectedTrackCount = 1; + } else { + wBeep(); + InfoMessage( _("Not on a Track") ); + return C_CONTINUE; + } + trk = NULL; + + /* no break */ + case C_START: + if (selectedTrackCount==0) { + InfoMessage( _("Select a Track To Convert") ); + return C_CONTINUE; + } + else if (selectedTrackCount>1) { + if (NoticeMessage(_("Convert all Selected Tracks to Cornu Tracks?"), _("Yes"), _("No"))<=0) { + SetAllTrackSelect(FALSE); + return C_TERMINATE; + } + } + UndoStart( _("Convert Cornu"),"newCornu curves"); + trk = NULL; + int converted=0, not_convertable = 0, created=0, deleted=0; + DYNARR_RESET(track_p,Da.tracks); + while ( TrackIterate( &trk ) ) { + if (!GetTrkSelected( trk )) continue; //Only selected + if (!QueryTrack(trk, Q_CORNU_CAN_MODIFY) && //Not Fixed Track/Turnout/Turntable + !QueryTrack( trk, Q_IGNORE_EASEMENT_ON_EXTEND )) { //But Yes to Easement + not_convertable++; + continue; + } + converted++; + DYNARR_RESET(trkSeg_t,Da.crvSegs_da); + Da.ep1Segs_da_cnt = 0; + Da.ep2Segs_da_cnt = 0; + Da.midSegs.cnt = 0; + Da.extend[0] = FALSE; + Da.extend[1] = FALSE; + Da.selectEndPoint = -1; + Da.selectTrack = NULL; + DYNARR_RESET(coOrd,Da.mid_points); + ClrTrkBits( trk, TB_SELECTED ); //Done with this one + Da.selectTrack = trk; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = trk; + Da.trk[0] = GetTrkEndTrk( trk, 0 ); + track_p prior = trk; + if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk); + else Da.ep[0] = -1; + EPINX_T ep0 = 0; + //Move down the LHS adding tracks until no more Selected or not modifyable + while (Da.trk[0] && GetTrkSelected( Da.trk[0]) && IsTrack(Da.trk[0]) && (QueryTrack(Da.trk[0], Q_CORNU_CAN_MODIFY) || QueryTrack(Da.trk[0], Q_IS_CORNU)) ) { + prior = Da.trk[0]; + ep0 = 1-Da.ep[0]; + ClrTrkBits( Da.trk[0], TB_SELECTED ); //Done with this one + if (selectedTrackCount>0) selectedTrackCount--; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = prior; + DYNARR_APPEND(coOrd,Da.mid_points,1); + for (int i=Da.mid_points.cnt-1;i>1;i--) { + DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i-1); + } + DYNARR_N(coOrd,Da.mid_points,0) = GetTrkEndPos(prior,1-ep0); + Da.trk[0] = GetTrkEndTrk( prior, ep0 ); + if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],prior); + else Da.ep[0] = -1; + converted++; + } + Da.radius[0] = -1.0; //Initialize with no end + Da.ends[0] = FALSE; + Da.center[0] = zero; + Da.pos[0] = GetTrkEndPos(prior,ep0); + if (Da.trk[0] && Da.ep[0]>=0) { + GetConnectedTrackParms(Da.trk[0],GetTrkEndPos(Da.trk[0],Da.ep[0]),0,Da.ep[0],FALSE); + } + + //Move to RHS + + Da.trk[1] = GetTrkEndTrk( trk, 1 ); + track_p next = trk; + EPINX_T ep1 = 1; + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk); + else Da.ep[1] = -1; + //Move down RHS adding tracks until no more Selected or not modifyable + while (Da.trk[1] && GetTrkSelected( Da.trk[1]) && (QueryTrack(Da.trk[1], Q_CORNU_CAN_MODIFY) || QueryTrack(Da.trk[1], Q_IS_CORNU))) { + next = Da.trk[1]; + ep1 = 1-Da.ep[1]; + if (selectedTrackCount>0) selectedTrackCount--; + ClrTrkBits( Da.trk[1], TB_SELECTED ); //Done with this one + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = next; + DYNARR_APPEND(coOrd,Da.mid_points,1); + DYNARR_LAST(coOrd,Da.mid_points) = GetTrkEndPos(next,1-ep1); + Da.trk[1] = GetTrkEndTrk( next, ep1 ); + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],next); + converted++; + } + Da.radius[1] = -1.0; //Initialize with no end + Da.ends[1] = FALSE; + Da.center[1] = zero; + Da.pos[1] = GetTrkEndPos(next,ep1); + if (Da.trk[1] && Da.ep[1]>=0) { + GetConnectedTrackParms(Da.trk[1],GetTrkEndPos(Da.trk[1],Da.ep[1]),1,Da.ep[1],FALSE); + } + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else continue; //Checks that a solution can be found + + // Do the deed - Create a replacement Cornu + + BOOL_T end_point[2]; + end_point[0] = TRUE; + end_point[1] = FALSE; + coOrd sub_pos[2]; + sub_pos[0] = Da.pos[0]; + if (Da.radius[0] == -1) end_point[0] = FALSE; + track_p first_trk= NULL,trk1=NULL,trk2 = NULL; + + for (int i=0;i<Da.mid_points.cnt;i++) { + sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i); + if ((trk1 = CreateCornuFromPoints(sub_pos,end_point))== NULL) continue; + if (Da.trk[0]) { + CopyAttributes( Da.trk[0], trk1 ); + } else if (Da.trk[1]) { + CopyAttributes( Da.trk[1], trk1 ); + } else { + SetTrkScale( trk1, GetLayoutCurScale() ); + SetTrkBits( trk1, TB_HIDEDESC ); + } + DrawNewTrack(trk1); + if (first_trk == NULL) first_trk = trk1; + if (trk2) ConnectTracks(trk1,0,trk2,1); + trk2 = trk1; + end_point[0] = FALSE; + sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i); + } + sub_pos[1] = Da.pos[1]; + end_point[1] = TRUE; + if (Da.radius[1] == -1) end_point[1] = FALSE; + if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == NULL) continue; + created++; + DrawNewTrack(trk1); + if (Da.trk[0]) { + CopyAttributes( Da.trk[0], trk1 ); + } else if (Da.trk[1]){ + CopyAttributes( Da.trk[1], trk1 ); + } else { + SetTrkScale( trk1, GetLayoutCurScale() ); + SetTrkBits( trk1, TB_HIDEDESC ); + } + if (trk2) ConnectTracks(trk1,0,trk2,1); + if (first_trk == NULL) first_trk = trk1; + + for (int i=0;i<2;i++) { + if (Da.ep[i]>=0 && Da.trk[i]) { + track_p trk_old = GetTrkEndTrk(Da.trk[i],Da.ep[i]); + EPINX_T old_ep = GetEndPtConnectedToMe(trk_old,Da.trk[i]); + DisconnectTracks(Da.trk[i],Da.ep[i],trk_old,old_ep); + if (Da.ep[i]>=0 && Da.trk[i]) + ConnectTracks(Da.trk[i],Da.ep[i],i==0?first_trk:trk1,i); + } + } + + } //Find next track + SetAllTrackSelect(FALSE); + //Get rid of old tracks + for (int i = 0; i<Da.tracks.cnt;i++) { + DeleteTrack(DYNARR_N(track_p,Da.tracks,i),FALSE); + deleted++; + } + + UndoEnd(); //Stop accumulating + NoticeMessage(_("Tracks Counts: %d converted %d unconvertible %d created %d deleted"),_("OK"),NULL,converted,not_convertable,created,deleted); + + return C_TERMINATE; + + case C_REDRAW: + if (trk) { + DrawTrack(trk,&tempD,wDrawColorPreviewSelected); + } + return C_CONTINUE; + + case C_CANCEL: + return C_TERMINATE; + + case C_OK: + return C_TERMINATE; + + case C_CONFIRM: + return C_CONTINUE; + + default: + return C_CONTINUE; + } +} +static STATUS_T CmdConvertFrom( + wAction_t action, + coOrd pos ) +{ + static track_p trk; + track_p trk1,trk2; + switch (action) { + + case wActionMove: + if ((trk = OnTrack(&pos,FALSE,TRUE)) == NULL) return C_CONTINUE; + if ((!(GetTrkType(trk) == T_CORNU)) || + (!(GetTrkType(trk) == T_BEZIER))) + trk = NULL; + return C_CONTINUE; + + case C_LCLICK: + if ((trk = OnTrack(&pos,FALSE,TRUE))!=NULL) { + SetTrkBits(trk,TB_SELECTED); + selectedTrackCount = 1; + trk = NULL; + } else { + wBeep(); + InfoMessage( _("Not on a Track") ); + trk = NULL; + return C_CONTINUE; + } + /* no break */ + case C_START: + if (selectedTrackCount==0) { + InfoMessage( _("Select a Cornu or Bezier Track To Convert to Fixed") ); + return C_CONTINUE; + } + else if (selectedTrackCount>1) { + if (NoticeMessage(_("Convert all Selected Tracks to Fixed Tracks?"), _("Yes"), _("No"))<=0) { + SetAllTrackSelect(FALSE); + return C_TERMINATE; + } + } + dynArr_t trackSegs_da; + DYNARR_RESET(trkSeg_t,trackSegs_da); + trk1 = NULL; + trk2 = NULL; + trk = NULL; + UndoStart( _("Convert Bezier and Cornu"),"Try to convert all selected tracks"); + track_p tracks[2]; + DYNARR_RESET(track_p,Da.tracks); + int converted=0, not_convertable = 0, created=0, deleted=0; + while ( TrackIterate( &trk1 ) ) { + if ( GetTrkSelected( trk1 ) && IsTrack( trk1 ) ) { + //Only Cornu or Bezier + tracks[0] = NULL, tracks[1] = NULL; + if (selectedTrackCount>0) selectedTrackCount--; + ClrTrkBits( trk1, TB_SELECTED ); //Done with this one + if (GetTrkType(trk1) == T_CORNU) { + GetTracksFromCornuTrack(trk1,tracks); + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = trk1; + converted++; + } else if (GetTrkType(trk1) == T_BEZIER) { + GetTracksFromBezierTrack(trk1,tracks); + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = trk1; + converted++; + } else { + not_convertable++; + continue; + } + for (int i=0;i<2;i++) { + track_p trk2 = GetTrkEndTrk(trk1,i); + if (trk2) { + EPINX_T ep1 = GetEndPtConnectedToMe( trk2, trk1 ); + DisconnectTracks(trk2,ep1,trk1,i); + pos = GetTrkEndPos(trk2,ep1); + for (int j=0;j<2;j++) { + EPINX_T ep2 = PickUnconnectedEndPointSilent( pos, tracks[j] ); + coOrd ep_pos; + if (ep2<0) continue; + ep_pos = GetTrkEndPos(tracks[j],ep2); + if (connectDistance>=FindDistance(pos,ep_pos) && + connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(tracks[j],ep2),GetTrkEndAngle(trk2,ep1)+180))) { + ConnectTracks(trk2,ep1,tracks[j],ep2); + break; + } + } + } + } + } + } + SetAllTrackSelect(FALSE); + for (int i = 0; i<Da.tracks.cnt;i++) { + DeleteTrack(DYNARR_N(track_p,Da.tracks,i),FALSE); + deleted++; + } + UndoEnd(); + NoticeMessage(_("Tracks Counts: %d converted %d unconvertible %d deleted"),_("OK"),NULL,converted,not_convertable,deleted); + return C_TERMINATE; + + case C_REDRAW: + if (trk) { + DrawTrack(trk,&tempD,wDrawColorPreviewSelected); + } + return C_CONTINUE; + + case C_CANCEL: + return C_TERMINATE; + + case C_OK: + return C_TERMINATE; + + case C_CONFIRM: + return C_CONTINUE; + + default: + return C_CONTINUE; + } +} + +#include "bitmaps/convertto.xpm" +#include "bitmaps/convertfr.xpm" EXPORT void InitCmdCornu( wMenu_p menu ) { - + ButtonGroupBegin( _("Convert"), "cmdConvertSetCmd", _("Convert") ); + AddMenuButton( menu, CmdConvertTo, "cmdConvertTo", _("Convert To Cornu"), wIconCreatePixMap(convertto_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP3|IC_WANT_MOVE,ACCL_CONVERTTO, NULL ); + AddMenuButton( menu, CmdConvertFrom, "cmdConvertFrom", _("Convert From Cornu"), wIconCreatePixMap(convertfr_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP3|IC_WANT_MOVE,ACCL_CONVERTFR, NULL ); + cornuHotBarCmdInx = AddMenuButton(menu, cmdCornuCreate, "cmdCornuCreate", "", NULL, LEVEL0_50, IC_STICKY|IC_POPUP3|IC_WANT_MOVE, 0, NULL); + ButtonGroupEnd(); + ParamCreateControls( &cornuModPG, cornuModDlgUpdate) ; } diff --git a/app/bin/ccornu.h b/app/bin/ccornu.h index b279cb4..2bd1f49 100644 --- a/app/bin/ccornu.h +++ b/app/bin/ccornu.h @@ -11,13 +11,24 @@ typedef void (*cornuMessageProc)( char *, ... ); +#define cornuCmdNone (0) +#define cornuJoinTrack (1) +#define cornuCmdCreateTrack (2) +#define cornuCmdHotBar (3) + #endif /* APP_BIN_CCORNU_H_ */ STATUS_T CmdCornu( wAction_t action, coOrd pos ); +BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p, BOOL_T spots); 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 CornuOffsetLength(dynArr_t segs, double offset); DIST_T CornuTotalWindingArc(coOrd pos[4],dynArr_t segs); STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG); + +void InitCmdCornu( wMenu_p menu ); + +void AddHotBarCornu( void ); diff --git a/app/bin/ccurve.c b/app/bin/ccurve.c index 58bb5c1..e119610 100644 --- a/app/bin/ccurve.c +++ b/app/bin/ccurve.c @@ -39,57 +39,102 @@ #include "utility.h" #include "wlib.h" #include "cbezier.h" +#include "ccornu.h" +#include "layout.h" /* * STATE INFO */ +typedef enum createState_e {NOCURVE,FIRSTEND_DEF,SECONDEND_DEF,CENTER_DEF} createState_e; + static struct { STATE_T state; + createState_e create_state; coOrd pos0; coOrd pos1; curveData_t curveData; track_p trk; EPINX_T ep; BOOL_T down; + BOOL_T lock0; + coOrd middle; + coOrd end0; + coOrd end1; } Da; static long curveMode; +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) +#define array_anchor(N) DYNARR_N(trkSeg_t,*anchor_array,N) + -EXPORT void DrawArrowHeads( +EXPORT int DrawArrowHeads( trkSeg_p sp, coOrd pos, ANGLE_T angle, BOOL_T bidirectional, wDrawColor color ) { - coOrd p0, p1; - DIST_T d, w; - int inx; - d = mainD.scale*0.25; - w = mainD.scale/mainD.dpi*2; - for ( inx=0; inx<5; inx++ ) { - sp[inx].type = SEG_STRLIN; - sp[inx].width = w; - sp[inx].color = color; - } - Translate( &p0, pos, angle, d ); - Translate( &p1, pos, angle+180, bidirectional?d:(d/2.0) ); - sp[0].u.l.pos[0] = p0; - sp[0].u.l.pos[1] = p1; - sp[1].u.l.pos[0] = p0; - Translate( &sp[1].u.l.pos[1], p0, angle+135, d/2.0 ); - sp[2].u.l.pos[0] = p0; - Translate( &sp[2].u.l.pos[1], p0, angle-135, d/2.0 ); - if (bidirectional) { - sp[3].u.l.pos[0] = p1; - Translate( &sp[3].u.l.pos[1], p1, angle-45, d/2.0 ); - sp[4].u.l.pos[0] = p1; - Translate( &sp[4].u.l.pos[1], p1, angle+45, d/2.0 ); - } + coOrd p0, p1; + DIST_T d, w; + int inx; + d = mainD.scale*0.25; + w = mainD.scale/mainD.dpi*2; + for ( inx=0; inx<5; inx++ ) { + sp[inx].type = SEG_STRLIN; + sp[inx].width = w; + sp[inx].color = color; + } + Translate( &p0, pos, angle, d ); + Translate( &p1, pos, angle+180, bidirectional?d:(d/2.0) ); + sp[0].u.l.pos[0] = p0; + sp[0].u.l.pos[1] = p1; + sp[1].u.l.pos[0] = p0; + Translate( &sp[1].u.l.pos[1], p0, angle+135, d/2.0 ); + sp[2].u.l.pos[0] = p0; + Translate( &sp[2].u.l.pos[1], p0, angle-135, d/2.0 ); + if (bidirectional) { + sp[3].u.l.pos[0] = p1; + Translate( &sp[3].u.l.pos[1], p1, angle-45, d/2.0 ); + sp[4].u.l.pos[0] = p1; + Translate( &sp[4].u.l.pos[1], p1, angle+45, d/2.0 ); + } else { + sp[3].u.l.pos[0] = p1; + sp[3].u.l.pos[1] = p1; + sp[4].u.l.pos[0] = p1; + sp[4].u.l.pos[1] = p1; + } + return 5; } +EXPORT int DrawArrowHeadsArray( + dynArr_t *anchor_array, + coOrd pos, + ANGLE_T angle, + BOOL_T bidirectional, + wDrawColor color ) +{ + int i = (*anchor_array).cnt; + DYNARR_SET(trkSeg_t,*anchor_array,i+5) + return DrawArrowHeads(&DYNARR_N(trkSeg_t,*anchor_array,i),pos,angle,bidirectional,color); + +} + +static void CreateEndAnchor(coOrd p, dynArr_t * anchor_array, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,*anchor_array,1); + int i = (*anchor_array).cnt-1; + array_anchor(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + array_anchor(i).color = wDrawColorBlue; + array_anchor(i).u.c.center = p; + array_anchor(i).u.c.radius = d/2; + array_anchor(i).u.c.a0 = 0.0; + array_anchor(i).u.c.a1 = 360.0; + array_anchor(i).width = 0; +} @@ -100,6 +145,7 @@ EXPORT STATUS_T CreateCurve( wDrawColor color, DIST_T width, long mode, + dynArr_t * anchor_array, curveMessageProc message ) { track_p t; @@ -110,23 +156,28 @@ EXPORT STATUS_T CreateCurve( switch ( action ) { case C_START: - DYNARR_SET( trkSeg_t, tempSegs_da, 8 ); + DYNARR_RESET(trkSeg_t,*anchor_array); + DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); + Da.create_state = NOCURVE; + tempSegs_da.cnt = 0; Da.down = FALSE; //Not got a valid start yet + Da.pos0 = zero; + Da.pos1 = zero; switch ( curveMode ) { case crvCmdFromEP1: if (track) - message(_("Drag from End-Point in direction of curve - Shift locks to track open end-point") ); + message(_("Drag from endpoint in direction of curve - lock to track open endpoint") ); else - message (_("Drag from End-Point in direction of curve") ); + message (_("Drag from endpoint in direction of curve") ); break; case crvCmdFromTangent: if (track) - message(_("Drag from End-Point to Center - Shift locks to track open end-point") ); + message(_("Drag from endpoint to center - lock to track open endpoint") ); else - message(_("Drag from End-Point to Center") ); + message(_("Drag from endpoint to center") ); break; case crvCmdFromCenter: - message(_("Drag from Center to End-Point") ); + message(_("Drag from center to endpoint") ); break; case crvCmdFromChord: message(_("Drag from one to other end of chord") ); @@ -134,6 +185,7 @@ EXPORT STATUS_T CreateCurve( } return C_CONTINUE; case C_DOWN: + DYNARR_RESET(trkSeg_t, *anchor_array); for ( inx=0; inx<8; inx++ ) { tempSegs(inx).color = wDrawColorBlack; tempSegs(inx).width = 0; @@ -141,150 +193,212 @@ EXPORT STATUS_T CreateCurve( tempSegs_da.cnt = 0; 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.trk = NULL; + if (track) { + if ((mode == crvCmdFromEP1 || mode == crvCmdFromTangent || (mode == crvCmdFromChord)) && + ((MyGetKeyState() & WKEY_ALT) == 0 ) == magneticSnap) { + if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) { + EPINX_T ep = PickUnconnectedEndPointSilent(p, t); + if (ep != -1) { + if (GetTrkScale(t) != (char)GetLayoutCurScale()) { + wBeep(); + InfoMessage(_("Track is different gauge")); + return C_CONTINUE; + } + Da.trk = t; + Da.ep = ep; + pos = GetTrkEndPos(t, ep); + found = TRUE; + } + } } - Da.down = TRUE; - } + } else { + if ((t = OnTrack(&p, FALSE, FALSE)) != NULL) { + if (!IsTrack(t)) { + pos = p; + found = TRUE; + } + } + } Da.down = TRUE; if (!found) SnapPos( &pos ); - pos0 = pos; - Da.pos0 = pos; + Da.lock0 = found; + + if (Da.create_state == NOCURVE) + Da.pos0 = pos; + else + Da.pos1 = pos; + + tempSegs_da.cnt = 1; switch (mode) { case crvCmdFromEP1: tempSegs(0).type = (track?SEG_STRTRK:SEG_STRLIN); tempSegs(0).color = color; tempSegs(0).width = width; - if (Da.trk) message(_("End Locked: Drag out curve start")); + Da.create_state = FIRSTEND_DEF; + Da.end0 = pos; + CreateEndAnchor(pos,anchor_array,found); + if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) message(_("End locked: Drag out curve start")); + else if (Da.trk) message(_("End Position locked: Drag out curve start with Shift")); else message(_("Drag along curve start") ); break; case crvCmdFromTangent: + Da.create_state = FIRSTEND_DEF; + tempSegs(0).type = SEG_STRLIN; + tempSegs(0).color = color; + Da.create_state = CENTER_DEF; + CreateEndAnchor(pos,anchor_array,found); + if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) message(_("End locked: Drag out curve center")); + else if (Da.trk) message(_("End Position locked: Drag out curve start with Shift")); + else message(_("Drag out curve center") ); + break; case crvCmdFromCenter: tempSegs(0).type = SEG_STRLIN; - tempSegs(1).type = SEG_CRVLIN; - tempSegs(1).u.c.radius = mainD.scale*0.05; - tempSegs(1).u.c.a0 = 0; - tempSegs(1).u.c.a1 = 360; - tempSegs(2).type = SEG_STRLIN; - 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") ); + tempSegs(0).color = color; + Da.create_state = CENTER_DEF; + CreateEndAnchor(pos,anchor_array,FALSE); + message(_("Drag out from center to endpoint")); break; case crvCmdFromChord: tempSegs(0).type = (track?SEG_STRTRK:SEG_STRLIN); tempSegs(0).color = color; tempSegs(0).width = width; - message( _("Drag to other end of chord") ); + CreateEndAnchor(pos,anchor_array,FALSE); + Da.create_state = FIRSTEND_DEF; + if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) + message( _("End locked: Drag to other end of chord") ); + else if (Da.trk) message(_("End Position locked: Drag out curve start with Shift")); + else + message( _("Drag to other end of chord") ); break; } - tempSegs(0).u.l.pos[0] = pos; + tempSegs(0).u.l.pos[0] = tempSegs(0).u.l.pos[1] = pos; return C_CONTINUE; case C_MOVE: + DYNARR_RESET(trkSeg_t,*anchor_array); + DYNARR_APPEND(trkSeg_t,*anchor_array,1); if (!Da.down) return C_CONTINUE; - if (Da.trk) { + if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) { //Shift inhibits direction lock angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk, Da.ep)); - angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1); - if (mode ==crvCmdFromEP1) { + angle2 = NormalizeAngle(FindAngle(pos, Da.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 ); + Translate( &pos, Da.pos0, angle1, -FindDistance( Da.pos0, pos )*cos(D2R(angle2)) ); + else pos = Da.pos0; + } else if ( mode == crvCmdFromChord ) { + DIST_T dp = -FindDistance(Da.pos0, pos)*sin(D2R(angle2)); + if (DifferenceBetweenAngles(FindAngle(Da.pos0,pos),angle1)>0) + Translate( &pos, Da.pos0, angle1+90, dp ); + else + Translate( &pos, Da.pos0, angle1-90, -dp ); + } else if (mode == crvCmdFromCenter) { + DIST_T dp = -FindDistance(Da.pos0, pos)*sin(D2R(angle2)); + if (angle2 > 90 && angle2 < 270.0) + Translate( &pos, Da.pos0, angle1+90.0, dp ); else - Translate( &pos, pos0, angle1-90.0, dp ); + Translate( &pos, Da.pos0, angle1-90.0, dp ); + } else if (mode == crvCmdFromTangent) { + DIST_T dp = FindDistance(Da.pos0, pos)*sin(D2R(angle2)); + Translate( &pos, Da.pos0, angle1-90.0, dp ); } } else SnapPos(&pos); - tempSegs(0).u.l.pos[1] = pos; - d = FindDistance( pos0, pos ); - a = FindAngle( pos0, pos ); + tempSegs_da.cnt =1; + if (Da.trk && mode == crvCmdFromChord) { + tempSegs(0).type = SEG_CRVTRK; + tempSegs(0).u.c.center.x = (pos.x+Da.pos0.x)/2.0; + tempSegs(0).u.c.center.y = (pos.y+Da.pos0.y)/2.0; + tempSegs(0).u.c.radius = FindDistance(pos,Da.pos0)/2; + ANGLE_T a0 = FindAngle(tempSegs(0).u.c.center,Da.pos0); + ANGLE_T a1 = FindAngle(tempSegs(0).u.c.center,pos); + if (NormalizeAngle(a0+90-GetTrkEndAngle(Da.trk,Da.ep))<90) { + tempSegs(0).u.c.a0 = a0; + } else { + tempSegs(0).u.c.a0 = a1; + } + tempSegs(0).u.c.a1 = 180.0; + } else tempSegs(0).u.l.pos[1] = pos; + Da.pos1 = pos; + + d = FindDistance( Da.pos0, Da.pos1 ); + a = FindAngle( Da.pos0, Da.pos1 ); switch ( mode ) { case crvCmdFromEP1: 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) ); + CreateEndAnchor(Da.pos0,anchor_array,Da.lock0); + DrawArrowHeadsArray( anchor_array, pos, FindAngle(Da.pos0,Da.pos1)+90, TRUE, wDrawColorBlue ); tempSegs_da.cnt = 1; break; case crvCmdFromTangent: - if (Da.trk) message( _("Tangent Locked: Drag out center - 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; + CreateEndAnchor(Da.pos1,anchor_array,TRUE); + DrawArrowHeadsArray( anchor_array, Da.pos0, FindAngle(Da.pos0,Da.pos1)+90, TRUE, wDrawColorBlue ); + tempSegs_da.cnt = 1; break; case crvCmdFromCenter: - message( _("Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); - tempSegs(1).u.c.center = pos0; - DrawArrowHeads( &tempSegs(2), pos, FindAngle(pos,pos0)+90, TRUE, wDrawColorBlack ); - tempSegs_da.cnt = 7; + message( _("Drag to Edge: Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + CreateEndAnchor(Da.pos0,anchor_array,Da.lock0); + DrawArrowHeadsArray( anchor_array, Da.pos1, FindAngle(Da.pos1,Da.pos0)+90, TRUE, wDrawColorBlue ); + tempSegs_da.cnt = 1; break; case crvCmdFromChord: - message( _("Length=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); - if ( d > mainD.scale*0.25 ) { - pos.x = (pos.x+pos0.x)/2.0; - pos.y = (pos.y+pos0.y)/2.0; - DrawArrowHeads( &tempSegs(1), pos, FindAngle(pos,pos0)+90, TRUE, wDrawColorBlack ); - tempSegs_da.cnt = 6; - } else { - tempSegs_da.cnt = 1; + if (Da.trk) message( _("Start locked: Drag out chord length=%s angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + else message( _("Drag out chord length=%s angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + Da.middle.x = (Da.pos1.x+Da.pos0.x)/2.0; + Da.middle.y = (Da.pos1.y+Da.pos0.y)/2.0; + if (track && Da.trk) { + ANGLE_T ea = GetTrkEndAngle(Da.trk,Da.ep); + Translate(&Da.middle,Da.middle,ea,FindDistance(Da.middle,Da.pos0)); } + CreateEndAnchor(Da.pos0,anchor_array,TRUE); + CreateEndAnchor(Da.pos1,anchor_array,FALSE); + if (!track || !Da.trk) + DrawArrowHeadsArray( anchor_array, Da.middle, FindAngle(Da.pos0,Da.pos1)+90, TRUE, wDrawColorBlue ); break; } return C_CONTINUE; case C_UP: + /* Note - no anchor reset - assumes run after Down/Move */ if (!Da.down) return C_CONTINUE; if (Da.trk) { angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk, Da.ep)); - angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1); + angle2 = NormalizeAngle(FindAngle(pos, Da.pos0)-angle1); if (mode == crvCmdFromEP1) { if (angle2 > 90.0 && angle2 < 270.0) { - Translate( &pos, pos0, angle1, -FindDistance( pos0, pos )*cos(D2R(angle2)) ); + Translate( &pos, Da.pos0, angle1, -FindDistance( Da.pos0, pos )*cos(D2R(angle2)) ); Da.pos1 = pos; } else { ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(0.0) ); return C_TERMINATE; } + } else if (mode == crvCmdFromTangent) { + DIST_T dp = FindDistance(Da.pos0, pos)*sin(D2R(angle2)); + Translate( &pos, Da.pos0, angle1-90.0, dp ); + Da.pos1 = pos; } else { - DIST_T dp = -FindDistance(pos0, pos)*sin(D2R(angle2)); + DIST_T dp = -FindDistance(Da.pos0, pos)*sin(D2R(angle2)); if (angle2 > 180.0) - Translate( &pos, pos0, angle1+90.0, dp ); + Translate( &pos, Da.pos0, angle1+90.0, dp ); else - Translate( &pos, pos0, angle1-90.0, dp ); + Translate( &pos, Da.pos0, angle1-90.0, dp ); Da.pos1 = pos; } + if (FindDistance(Da.pos0,Da.pos1)<minLength) { + ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(FindDistance(Da.pos0,Da.pos1)) ); + return C_TERMINATE; + } } switch (mode) { case crvCmdFromEP1: - DrawArrowHeads( &tempSegs(1), pos, FindAngle(pos,pos0)+90, TRUE, drawColorRed ); - tempSegs_da.cnt = 6; - break; - case crvCmdFromChord: - tempSegs(1).color = drawColorRed; case crvCmdFromTangent: case crvCmdFromCenter: - tempSegs(2).color = drawColorRed; - tempSegs(3).color = drawColorRed; - tempSegs(4).color = drawColorRed; - tempSegs(5).color = drawColorRed; - tempSegs(6).color = drawColorRed; - break; + case crvCmdFromChord: + for (int i=0;i<(*anchor_array).cnt;i++) { + DYNARR_N(trkSeg_t,*anchor_array,i).color = drawColorRed; + } + break; } message( _("Drag on Red arrows to adjust curve") ); return C_CONTINUE; @@ -296,6 +410,7 @@ EXPORT STATUS_T CreateCurve( } + static STATUS_T CmdCurve( wAction_t action, coOrd pos ) { track_p t; @@ -310,38 +425,71 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) Da.state = -1; Da.pos0 = pos; tempSegs_da.cnt = 0; + segCnt = 0; STATUS_T rcode; - return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); - - case C_TEXT: - if ( Da.state == 0 ) - return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); - else - return C_CONTINUE; + DYNARR_RESET(trkSeg_t,anchors_da); + return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage ); case C_DOWN: - if ( Da.state == -1 ) { - //SnapPos( &pos ); - Da.pos0 = pos; + if (Da.state == -1) { + BOOL_T found = FALSE; + if (curveMode != crvCmdFromCenter ) { + if (((MyGetKeyState() & WKEY_ALT)==0) == magneticSnap) { + if ((t = OnTrack(&pos,FALSE,TRUE))!=NULL) { + EPINX_T ep = PickUnconnectedEndPointSilent(pos, t); + if (ep != -1) { + if (GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) { + wBeep(); + InfoMessage(_("Track is different gauge")); + return C_CONTINUE; + } + pos = GetTrkEndPos(t, ep); + found = TRUE; + } + } + } + } + if (!found) SnapPos( &pos ); + Da.pos0 = Da.pos1 = pos; Da.state = 0; - rcode = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); + rcode = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage ); + segCnt = tempSegs_da.cnt ; if (!Da.down) Da.state = -1; return rcode; //Da.pos0 = pos; - } else { - tempSegs_da.cnt = segCnt; - return C_CONTINUE; } + //This is where the user could adjust - if we allow that? + tempSegs_da.cnt = segCnt; + return C_CONTINUE; + + + case wActionMove: + if ((Da.state<0) && (curveMode != crvCmdFromCenter)) { + DYNARR_RESET(trkSeg_t,anchors_da); + if (((MyGetKeyState() & WKEY_ALT)==0) == magneticSnap) { + if ((t=OnTrack(&pos,FALSE,TRUE))!= NULL) { + if (GetTrkGauge(t) == GetScaleTrackGauge(GetLayoutCurScale())) { + EPINX_T ep = PickUnconnectedEndPointSilent(pos, t); + if (ep != -1) { + pos = GetTrkEndPos(t, ep); + CreateEndAnchor(pos,&anchors_da,FALSE); + } + } + } + } + } + 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 ) { Da.pos1 = pos; - rc = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); + rc = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage ); + segCnt = tempSegs_da.cnt ; } else { + DYNARR_RESET(trkSeg_t,anchors_da); // SnapPos( &pos ); + tempSegs_da.cnt = segCnt; 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) { @@ -349,11 +497,14 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) tempSegs(0).u.l.pos[0] = Da.pos0; tempSegs(0).u.l.pos[1] = Da.curveData.pos1; tempSegs_da.cnt = 1; + segCnt = 1; InfoMessage( _("Straight Track: Length=%s Angle=%0.3f"), FormatDistance(FindDistance( Da.pos0, Da.curveData.pos1 )), PutAngle(FindAngle( Da.pos0, Da.curveData.pos1 )) ); + DrawArrowHeadsArray(&anchors_da,Da.curveData.pos1,FindAngle(Da.pos0, Da.curveData.pos1)+90,TRUE,wDrawColorRed); } else if (Da.curveData.type == curveTypeNone) { tempSegs_da.cnt = 0; + segCnt = 0; InfoMessage( _("Back") ); } else if (Da.curveData.type == curveTypeCurve) { tempSegs(0).type = SEG_CRVTRK; @@ -362,6 +513,7 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) tempSegs(0).u.c.a0 = Da.curveData.a0; tempSegs(0).u.c.a1 = Da.curveData.a1; tempSegs_da.cnt = 1; + segCnt = 1; d = D2R(Da.curveData.a1); if (d < 0.0) d = 2*M_PI+d; @@ -375,80 +527,101 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) InfoMessage( _("Curved Track: Radius=%s Angle=%0.3f Length=%s"), FormatDistance(Da.curveData.curveRadius), Da.curveData.a1, FormatDistance(Da.curveData.curveRadius*d) ); + coOrd pos1; + Translate(&pos1,Da.curveData.curvePos,Da.curveData.a0+Da.curveData.a1,Da.curveData.curveRadius); + if (curveMode == crvCmdFromEP1 || curveMode == crvCmdFromChord) + DrawArrowHeadsArray(&anchors_da,pos,FindAngle(Da.curveData.curvePos,pos),TRUE,wDrawColorRed); + else if (curveMode == crvCmdFromTangent || curveMode == crvCmdFromCenter) { + CreateEndAnchor(Da.curveData.pos2,&anchors_da,FALSE); + DrawArrowHeadsArray(&anchors_da,Da.curveData.pos2,FindAngle(Da.curveData.curvePos,Da.curveData.pos2)+90,TRUE,wDrawColorRed); + } + CreateEndAnchor(Da.curveData.curvePos,&anchors_da,TRUE); } } - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); mainD.funcs->options = 0; return rc; - - + case C_TEXT: + if ( Da.state == 0 ) + return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage ); + /*no break*/ 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) { + if (Da.state == 0 && ((curveMode != crvCmdFromChord) || (curveMode == crvCmdFromChord && !Da.trk))) { SnapPos( &pos ); Da.pos1 = pos; + if ((d = FindDistance(Da.pos0,Da.pos1))<minLength) { + ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); + return C_TERMINATE; + } Da.state = 1; - CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); + CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage ); + tempSegs_da.cnt = 1; mainD.funcs->options = 0; segCnt = tempSegs_da.cnt; InfoMessage( _("Drag on Red arrows to adjust curve") ); return C_CONTINUE; - } else { - mainD.funcs->options = 0; - tempSegs_da.cnt = 0; - Da.state = -1; - if (Da.curveData.type == curveTypeStraight) { - if ((d=FindDistance( Da.pos0, Da.curveData.pos1 )) <= minLength) { - ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); - return C_TERMINATE; - } - 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) { - ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); - return C_TERMINATE; - } - 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; + } else if ((curveMode == crvCmdFromChord && Da.state == 0 && Da.trk)) { + pos = Da.middle; + if ((d = FindDistance(Da.pos0,Da.pos1))<minLength) { + ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); + return C_TERMINATE; + } + PlotCurve( curveMode, Da.pos0, Da.pos1, Da.middle, &Da.curveData, TRUE ); + } + mainD.funcs->options = 0; + tempSegs_da.cnt = 0; + segCnt = 0; + Da.state = -1; + DYNARR_RESET(trkSeg_t,anchors_da); // No More anchors for this one + if (Da.curveData.type == curveTypeStraight) { + if ((d = FindDistance( Da.pos0, Da.curveData.pos1 )) < minLength) { + ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); + return C_TERMINATE; + } + UndoStart( _("Create Straight Track"), "newCurve - straight" ); + t = NewStraightTrack( Da.pos0, Da.curveData.pos1 ); + if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) { + 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) { + ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); + return C_TERMINATE; + } + UndoStart( _("Create Curved Track"), "newCurve - curve" ); + t = NewCurvedTrack( Da.curveData.curvePos, Da.curveData.curveRadius, + Da.curveData.a0, Da.curveData.a1, 0 ); + if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) { + EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t); + if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep); } - DrawNewTrack( t ); - return C_TERMINATE; + UndoEnd(); + } else { + return C_ERROR; } + DrawNewTrack( t ); + return C_TERMINATE; case C_REDRAW: if ( Da.state >= 0 ) { - mainD.funcs->options = wDrawOptTemp; - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); + DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); mainD.funcs->options = 0; } + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; case C_CANCEL: if (Da.state == 1) { - mainD.funcs->options = wDrawOptTemp; - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - mainD.funcs->options = 0; tempSegs_da.cnt = 0; Da.trk = NULL; } + DYNARR_RESET(trkSeg_t,anchors_da); + DYNARR_RESET(trkSeg_t,tempSegs_da); Da.state = -1; + segCnt = 0; return C_CONTINUE; } @@ -581,7 +754,6 @@ static void ComputeHelix( static void HelixCancel( wWin_p win ) { wHide( helixW ); - Reset(); } @@ -610,30 +782,30 @@ static STATUS_T CmdCircleCommon( wAction_t action, coOrd pos, BOOL_T helix ) case C_START: if (helix) { if (helixW == NULL) - helixW = ParamCreateDialog( &helixPG, MakeWindowTitle(_("Helix")), NULL, NULL, HelixCancel, TRUE, NULL, 0, ComputeHelix ); - ParamLoadControls( &helixPG ); - ParamGroupRecord( &helixPG ); - ComputeHelix( NULL, 6, NULL ); - wShow( helixW ); - memset( h_orders, 0, sizeof h_orders ); + helixW = ParamCreateDialog(&helixPG, MakeWindowTitle(_("Helix")), NULL, NULL, HelixCancel, TRUE, NULL, 0, ComputeHelix); + ParamLoadControls(&helixPG); + ParamGroupRecord(&helixPG); + ComputeHelix(NULL, 6, NULL); + wShow(helixW); + memset(h_orders, 0, sizeof h_orders); h_clock = 0; } else { - ParamLoadControls( &circleRadiusPG ); - ParamGroupRecord( &circleRadiusPG ); - switch ( circleMode ) { + ParamLoadControls(&circleRadiusPG); + ParamGroupRecord(&circleRadiusPG); + switch (circleMode) { case circleCmdFixedRadius: controls[0] = circleRadiusPLs[0].control; controls[1] = NULL; labels[0] = N_("Circle Radius"); - InfoSubstituteControls( controls, labels ); + InfoSubstituteControls(controls, labels); break; case circleCmdFromTangent: - InfoSubstituteControls( NULL, NULL ); - InfoMessage( _("Click on Circle Edge") ); + InfoSubstituteControls(NULL, NULL); + InfoMessage(_("Click on Circle Edge")); break; case circleCmdFromCenter: - InfoSubstituteControls( NULL, NULL ); - InfoMessage( _("Click on Circle Center") ); + InfoSubstituteControls(NULL, NULL); + InfoMessage(_("Click on Circle Center")); break; } } @@ -641,98 +813,95 @@ static STATUS_T CmdCircleCommon( wAction_t action, coOrd pos, BOOL_T helix ) return C_CONTINUE; case C_DOWN: - DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); + DYNARR_SET(trkSeg_t, tempSegs_da, 1); tempSegs_da.cnt = 0; if (helix) { if (helixRadius <= 0.0) { - ErrorMessage( MSG_RADIUS_GTR_0 ); + ErrorMessage(MSG_RADIUS_GTR_0); return C_ERROR; } if (helixTurns <= 0) { - ErrorMessage( MSG_HELIX_TURNS_GTR_0 ); + ErrorMessage(MSG_HELIX_TURNS_GTR_0); return C_ERROR; } - ParamLoadData( &helixPG ); + ParamLoadData(&helixPG); } else { - ParamLoadData( &circleRadiusPG ); - switch( circleMode ) { + ParamLoadData(&circleRadiusPG); + switch (circleMode) { case circleCmdFixedRadius: if (circleRadius <= 0.0) { - ErrorMessage( MSG_RADIUS_GTR_0 ); + ErrorMessage(MSG_RADIUS_GTR_0); return C_ERROR; } break; case circleCmdFromTangent: - InfoSubstituteControls( NULL, NULL ); - InfoMessage( _("Drag to Center") ); + InfoSubstituteControls(NULL, NULL); + InfoMessage(_("Drag to Center")); break; case circleCmdFromCenter: - InfoSubstituteControls( NULL, NULL ); - InfoMessage( _("Drag to Edge") ); + InfoSubstituteControls(NULL, NULL); + InfoMessage(_("Drag to Edge")); break; } } - SnapPos( &pos ); + SnapPos(&pos); tempSegs(0).u.c.center = pos0 = pos; tempSegs(0).color = wDrawColorBlack; tempSegs(0).width = 0; return C_CONTINUE; case C_MOVE: - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - SnapPos( &pos ); + SnapPos(&pos); tempSegs(0).u.c.center = pos; - if ( !helix ) { - switch ( circleMode ) { + if (!helix) { + switch (circleMode) { case circleCmdFixedRadius: break; case circleCmdFromCenter: tempSegs(0).u.c.center = pos0; - circleRadius = FindDistance( tempSegs(0).u.c.center, pos ); - InfoMessage( _("Radius=%s"), FormatDistance(circleRadius) ); + circleRadius = FindDistance(tempSegs(0).u.c.center, pos); + InfoMessage(_("Radius=%s"), FormatDistance(circleRadius)); break; case circleCmdFromTangent: - circleRadius = FindDistance( tempSegs(0).u.c.center, pos0 ); - InfoMessage( _("Radius=%s"), FormatDistance(circleRadius) ); + circleRadius = FindDistance(tempSegs(0).u.c.center, pos0); + InfoMessage(_("Radius=%s"), FormatDistance(circleRadius)); break; } } tempSegs(0).type = SEG_CRVTRK; - tempSegs(0).u.c.radius = helix?helixRadius:circleRadius; + tempSegs(0).u.c.radius = helix ? helixRadius : circleRadius; tempSegs(0).u.c.a0 = 0.0; tempSegs(0).u.c.a1 = 360.0; tempSegs_da.cnt = 1; - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; 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 (helix) { + if (helixRadius > mapD.size.x || helixRadius > mapD.size.y) { + ErrorMessage(MSG_RADIUS_TOO_BIG); + return C_ERROR; + } if (helixRadius > 10000) { - ErrorMessage( MSG_RADIUS_GTR_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 ); + UndoStart(_("Create Helix Track"), "newHelix"); + t = NewCurvedTrack(tempSegs(0).u.c.center, helixRadius, 0.0, 0.0, helixTurns); } else { - if ( circleRadius <= 0 ) { - ErrorMessage( MSG_RADIUS_GTR_0 ); + if (circleRadius > mapD.size.x || circleRadius > mapD.size.y) { + ErrorMessage(MSG_RADIUS_TOO_BIG); + return C_ERROR; + } + if (circleRadius <= 0) { + ErrorMessage(MSG_RADIUS_GTR_0); return C_ERROR; } if ((circleRadius > 100000) || (helixRadius > 10000)) { - ErrorMessage( MSG_RADIUS_GTR_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 ); + UndoStart(_("Create Circle Track"), "newCircle"); + t = NewCurvedTrack(tempSegs(0).u.c.center, circleRadius, 0.0, 0.0, 0); } UndoEnd(); DrawNewTrack(t); @@ -779,19 +948,21 @@ static STATUS_T CmdHelix( wAction_t action, coOrd pos ) #include "bitmaps/curve3.xpm" #include "bitmaps/curve4.xpm" #include "bitmaps/bezier.xpm" +#include "bitmaps/cornu.xpm" #include "bitmaps/circle1.xpm" #include "bitmaps/circle2.xpm" #include "bitmaps/circle3.xpm" EXPORT void InitCmdCurve( wMenu_p menu ) { + AddMenuButton( menu, CmdCornu, "cmdCornu", _("Cornu Curve"), wIconCreatePixMap(cornu_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CORNU, (void*)cornuCmdCreateTrack); ButtonGroupBegin( _("Curve Track"), "cmdCircleSetCmd", _("Curve Tracks") ); - AddMenuButton( menu, CmdCurve, "cmdCurveEndPt", _("Curve from End-Pt"), wIconCreatePixMap( curve1_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE1, (void*)0 ); - 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 ); + AddMenuButton( menu, CmdCurve, "cmdCurveEndPt", _("Curve from End-Pt"), wIconCreatePixMap( curve1_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CURVE1, (void*)0 ); + AddMenuButton( menu, CmdCurve, "cmdCurveTangent", _("Curve from Tangent"), wIconCreatePixMap( curve2_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CURVE2, (void*)1 ); + AddMenuButton( menu, CmdCurve, "cmdCurveCenter", _("Curve from Center"), wIconCreatePixMap( curve3_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CURVE3, (void*)2 ); + AddMenuButton( menu, CmdCurve, "cmdCurveChord", _("Curve from Chord"), wIconCreatePixMap( curve4_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CURVE4, (void*)3 ); + AddMenuButton( menu, CmdBezCurve, "cmdBezier", _("Bezier Curve"), wIconCreatePixMap(bezier_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_BEZIER, (void*)bezCmdCreateTrack ); ButtonGroupEnd(); ButtonGroupBegin( _("Circle Track"), "cmdCurveSetCmd", _("Circle Tracks") ); @@ -816,7 +987,7 @@ EXPORT void InitCmdCurve( wMenu_p menu ) void InitCmdHelix(wMenu_p menu) { AddMenuButton(menu, CmdHelix, "cmdHelix", _("Helix"), NULL, LEVEL0_50, - IC_STICKY|IC_POPUP2, ACCL_HELIX, NULL); + IC_STICKY|IC_INITNOTSTICKY|IC_POPUP2, ACCL_HELIX, NULL); ParamRegister(&helixPG); RegisterChangeNotification(ChangeHelixW); } diff --git a/app/bin/ccurve.h b/app/bin/ccurve.h index c9d1c8c..0c00c46 100644 --- a/app/bin/ccurve.h +++ b/app/bin/ccurve.h @@ -32,6 +32,7 @@ typedef struct { curveType_e type; coOrd curvePos; coOrd pos1; + coOrd pos2; DIST_T curveRadius; ANGLE_T a0, a1; BOOL_T negative; @@ -48,13 +49,14 @@ typedef struct { #define circleCmdFromCenter (2) typedef void (*curveMessageProc)( char *, ... ); -STATUS_T CreateCurve( wAction_t, coOrd, BOOL_T, wDrawColor, DIST_T, long, curveMessageProc ); +STATUS_T CreateCurve( wAction_t, coOrd, BOOL_T, wDrawColor, DIST_T, long, dynArr_t *,curveMessageProc ); int IsCurveCircle( track_p ); 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 ); +DIST_T CurveDescriptionDistance( coOrd, track_p, coOrd *, BOOL_T, BOOL_T * ); STATUS_T CurveDescriptionMove( track_p, wAction_t, coOrd ); BOOL_T GetCurveMiddle( track_p , coOrd * ); -void DrawArrowHeads(trkSeg_p sp, coOrd pos, ANGLE_T angle, BOOL_T bidirectional, wDrawColor color ); +int DrawArrowHeads(trkSeg_p sp, coOrd pos, ANGLE_T angle, BOOL_T bidirectional, wDrawColor color ); +int DrawArrowHeadsArray(dynArr_t *anchor_array,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 9bddcaf..6bb4c4a 100644 --- a/app/bin/cdraw.c +++ b/app/bin/cdraw.c @@ -23,6 +23,7 @@ #include <math.h> #include <stdint.h> #include <string.h> +#include "wlib.h" #include "ccurve.h" #include "cbezier.h" @@ -37,7 +38,31 @@ extern TRKTYP_T T_BZRLIN; -extern void wSetSelectedFontSize(int size); +static wMenu_p drawModDelMI; +static wMenu_p drawModLinMI; +static wMenuPush_p drawModDel; +static wMenuPush_p drawModSmooth; +static wMenuPush_p drawModVertex; +static wMenuPush_p drawModRound; +static wMenuPush_p drawModriginMode; +static wMenuPush_p drawModPointsMode; +static wMenuPush_p drawModOrigin; +static wMenuPush_p drawModLast; +static wMenuPush_p drawModCenter; +static wMenuPush_p drawModClose; +static wMenuPush_p drawModOpen; +static wMenuPush_p drawModFill; +static wMenuPush_p drawModEmpty; +static wMenuPush_p drawModSolid; +static wMenuPush_p drawModDot; +static wMenuPush_p drawModDash; +static wMenuPush_p drawModDashDot; +static wMenuPush_p drawModDashDotDot; +static wMenuPush_p drawModCenterDot; +static wMenuPush_p drawModPhantom; + + +extern void wSetSelectedFontSize(wFontSize_t size); static long fontSizeList[] = { 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, @@ -111,7 +136,7 @@ EXPORT void UpdateFontSizeList( *fontSizeR = fontSize; /* inform gtkfont dialog from change */ - wSetSelectedFontSize((int)fontSize); + wSetSelectedFontSize((wFontSize_t)fontSize); /*LoadFontSizeList( list, *fontSizeR );*/ } else { sprintf( message, "%ld", *fontSizeR ); @@ -128,9 +153,11 @@ EXPORT void UpdateFontSizeList( * */ + struct extraData { coOrd orig; ANGLE_T angle; + drawLineType_e lineType; wIndex_t segCnt; trkSeg_t segs[1]; }; @@ -167,12 +194,13 @@ static track_p MakeDrawFromSeg1( xx->orig = pos; xx->angle = angle; xx->segCnt = 1; + xx->lineType = DRAWLINESOLID; memcpy( xx->segs, sp, sizeof *(trkSeg_p)0 ); if (xx->segs[0].type == SEG_POLY || - xx->segs[0].type == SEG_FILPOLY) { - xx->segs[0].u.p.pts = (coOrd*)MyMalloc( (sp->u.p.cnt) * sizeof (coOrd) ); - memcpy(xx->segs[0].u.p.pts, sp->u.p.pts, sp->u.p.cnt * sizeof (coOrd) ); + xx->segs[0].type == SEG_FILPOLY ) { + xx->segs[0].u.p.pts = (pts_t*)MyMalloc( (sp->u.p.cnt) * sizeof (pts_t) ); + memcpy(xx->segs[0].u.p.pts, sp->u.p.pts, sp->u.p.cnt * sizeof (pts_t) ); } if (xx->segs[0].type == SEG_TEXT) { xx->segs[0].u.t.string = MyStrdup(sp->u.t.string); @@ -189,6 +217,254 @@ EXPORT track_p MakeDrawFromSeg( return MakeDrawFromSeg1( 0, pos, angle, sp ); } +int SliceCuts(ANGLE_T a, DIST_T radius) { + double Error = 0.05; + double Error_angle = acos(1-(Error/fabs(radius))); + if (Error_angle <0.0001) return 0; + return (int)(floor(D2R(a)/(2*Error_angle))); +} + +/* Only straight, curved and PolyLine */ +EXPORT track_p MakePolyLineFromSegs( + coOrd pos, + ANGLE_T angle, + dynArr_t * segsArr) +{ + struct extraData * xx; + track_p trk; + trk = NewTrack( 0, T_DRAW, 0, sizeof *xx ); + xx = GetTrkExtraData( trk ); + xx->orig = pos; + xx->angle = angle; + xx->lineType = DRAWLINESOLID; + xx->segCnt = 1; + xx->segs[0].type = SEG_POLY; + xx->segs[0].width = 0; + xx->segs[0].u.p.polyType = POLYLINE; + xx->segs[0].color = wDrawColorBlack; + coOrd last; + BOOL_T first = TRUE; + int cnt = 0; + for (int i=0;i<segsArr->cnt;i++) { + trkSeg_p sp = &DYNARR_N(trkSeg_t,*segsArr,i); + if (sp->type == SEG_BEZLIN || sp->type == SEG_BEZTRK ) { + for (int j=0;j<sp->bezSegs.cnt;j++) { + trkSeg_p spb = &DYNARR_N(trkSeg_t,sp->bezSegs,j); + if (spb->type == SEG_STRLIN || spb->type == SEG_STRTRK) { + if (!first && IsClose(FindDistance(spb->u.l.pos[0], last))) + cnt++; + else + cnt=cnt+2; + last = spb->u.l.pos[1]; + first = FALSE; + } + else if (spb->type == SEG_CRVLIN || spb->type == SEG_CRVTRK) { + coOrd this; + if (spb->u.c.radius >= 0.0) + Translate(&this, spb->u.c.center, spb->u.c.a0, fabs(spb->u.c.radius)); + else + Translate(&this, spb->u.c.center, spb->u.c.a0+spb->u.c.a1, fabs(spb->u.c.radius)); + if (first || !IsClose(FindDistance(this, last))) { + cnt++; //Add first point + } + cnt += 1 + SliceCuts(spb->u.c.a1,spb->u.c.radius); + if (spb->u.c.radius >= 0.0) + Translate(&last, spb->u.c.center, spb->u.c.a0+spb->u.c.a1, fabs(spb->u.c.radius)); + else + Translate(&last, spb->u.c.center, spb->u.c.a0, fabs(spb->u.c.radius)); + first = FALSE; + } + } + } + else if (sp->type == SEG_STRLIN || sp->type == SEG_STRTRK) { + if (!first && IsClose(FindDistance(sp->u.l.pos[0], last))) + cnt++; + else + cnt=cnt+2; + last = sp->u.l.pos[1]; + first = FALSE; + } + else if (sp->type == SEG_CRVLIN || sp->type == SEG_CRVTRK) { + coOrd this; + if (sp->u.c.radius >= 0.0) + Translate(&this, sp->u.c.center, sp->u.c.a0, fabs(sp->u.c.radius)); + else + Translate(&this, sp->u.c.center, sp->u.c.a0+sp->u.c.a1, fabs(sp->u.c.radius)); + if (first || !IsClose(FindDistance(this, last))) { + cnt++; //Add first point + } + cnt += 1+ SliceCuts(sp->u.c.a1,sp->u.c.radius); + if (sp->u.c.radius >= 0.0) + Translate(&last, sp->u.c.center, sp->u.c.a0+sp->u.c.a1, fabs(sp->u.c.radius)); + else + Translate(&last, sp->u.c.center, sp->u.c.a0, fabs(sp->u.c.radius)); + first = FALSE; + } + else if (sp->type == SEG_POLY) { + if (!first && IsClose(FindDistance(sp->u.p.pts[0].pt, last))) + cnt = cnt + sp->u.p.cnt-1; + else + cnt = cnt + sp->u.p.cnt; + last = sp->u.p.pts[sp->u.p.cnt-1].pt; + first = FALSE; + } + } + xx->segs[0].u.p.cnt = cnt; + xx->segs[0].u.p.pts = (pts_t*)MyMalloc( (cnt) * sizeof (pts_t) ); + first = TRUE; + int j =0; + for (int i=0;i<segsArr->cnt;i++) { + trkSeg_p sp = &DYNARR_N(trkSeg_t,*segsArr,i); + if (sp->type == SEG_BEZLIN || sp->type == SEG_BEZTRK ) { + for (int l=0;l<sp->bezSegs.cnt;l++) { + trkSeg_p spb = &DYNARR_N(trkSeg_t,sp->bezSegs,l); + if (spb->type == SEG_STRLIN || spb->type == SEG_STRTRK) { + if (first || !IsClose(FindDistance(spb->u.l.pos[0], last))) { + xx->segs[0].u.p.pts[j].pt = spb->u.l.pos[0]; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + j++; + } + xx->segs[0].u.p.pts[j].pt = spb->u.l.pos[1]; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + last = xx->segs[0].u.p.pts[j].pt; + j ++; + first = FALSE; + } + if (spb->type == SEG_CRVLIN || spb->type == SEG_CRVTRK) { + coOrd this; + if (spb->u.c.radius>=0.0) + Translate(&this, spb->u.c.center, spb->u.c.a0, fabs(spb->u.c.radius)); + else + Translate(&this, spb->u.c.center, spb->u.c.a0+spb->u.c.a1, fabs(spb->u.c.radius)); + if (first || !IsClose(FindDistance(this, last))) { + xx->segs[0].u.p.pts[j].pt= this; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + j++; + } + int slices = SliceCuts(spb->u.c.a1,spb->u.c.radius); + for (int k=1; k<slices;k++) { + if (spb->u.c.radius>=0.0) + Translate(&xx->segs[0].u.p.pts[j].pt, spb->u.c.center, spb->u.c.a0+(k*(spb->u.c.a1/(slices))), fabs(spb->u.c.radius)); + else + Translate(&xx->segs[0].u.p.pts[j].pt, spb->u.c.center, spb->u.c.a0+((slices-k)*(spb->u.c.a1/(slices))), fabs(spb->u.c.radius)); + xx->segs[0].u.p.pts[j].pt_type = wPolyLineSmooth; + j++; + } + if (spb->u.c.radius>=0.0) + Translate(&xx->segs[0].u.p.pts[j].pt, spb->u.c.center, spb->u.c.a0+spb->u.c.a1, fabs(spb->u.c.radius)); + else + Translate(&xx->segs[0].u.p.pts[j].pt, spb->u.c.center, spb->u.c.a0, fabs(spb->u.c.radius)); + + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + last = xx->segs[0].u.p.pts[j].pt; + j++; + first = FALSE; + } + } + } + if (sp->type == SEG_STRLIN || sp->type == SEG_STRTRK) { + if (first || !IsClose(FindDistance(sp->u.l.pos[0], last))) { + xx->segs[0].u.p.pts[j].pt = sp->u.l.pos[0]; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + j++; + } + xx->segs[0].u.p.pts[j].pt = last = sp->u.l.pos[1]; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + last = xx->segs[0].u.p.pts[j].pt; + j++; + first = FALSE; + } + if (sp->type == SEG_CRVLIN || sp->type == SEG_CRVTRK) { + coOrd this; + if (sp->u.c.radius>0) + Translate(&this, sp->u.c.center, sp->u.c.a0, fabs(sp->u.c.radius)); + else + Translate(&this, sp->u.c.center, sp->u.c.a0+sp->u.c.a1, fabs(sp->u.c.radius)); + if (first || !IsClose(FindDistance(this, last))) { + xx->segs[0].u.p.pts[j].pt= this; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + j++; + } + int slices = SliceCuts(sp->u.c.a1,sp->u.c.radius); + + for (int k=1; k<slices;k++) { + if (sp->u.c.radius>0) + Translate(&xx->segs[0].u.p.pts[j].pt, sp->u.c.center, sp->u.c.a0+(k*(sp->u.c.a1/(slices))), fabs(sp->u.c.radius)); + else + Translate(&xx->segs[0].u.p.pts[j].pt, sp->u.c.center, sp->u.c.a0+((slices-k)*(sp->u.c.a1/(slices))), fabs(sp->u.c.radius)); + xx->segs[0].u.p.pts[j].pt_type = wPolyLineSmooth; + j++; + } + if (sp->u.c.radius>0) + Translate(&xx->segs[0].u.p.pts[j].pt, sp->u.c.center, sp->u.c.a0+sp->u.c.a1, fabs(sp->u.c.radius)); + else + Translate(&xx->segs[0].u.p.pts[j].pt, sp->u.c.center, sp->u.c.a0, fabs(sp->u.c.radius)); + + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + last = xx->segs[0].u.p.pts[j].pt; + j++; + first = FALSE; + } + if (sp->type == SEG_POLY) { + if (first || !IsClose(FindDistance(sp->u.p.pts[0].pt, last))) { + xx->segs[0].u.p.pts[j] = sp->u.p.pts[0]; + j++; + } + memcpy(&xx->segs[0].u.p.pts[j],&sp->u.p.pts[1], (sp->u.p.cnt-1) * sizeof (pts_t)); + last = xx->segs[0].u.p.pts[sp->u.p.cnt-1].pt; + j +=sp->u.p.cnt-1; + first = FALSE; + } + ASSERT(j<=cnt); + + } + xx->segs[0].u.p.cnt = j; + + if (IsClose(FindDistance(xx->segs[0].u.p.pts[0].pt,xx->segs[0].u.p.pts[xx->segs[0].u.p.cnt-1].pt))) { + xx->segs[0].u.p.polyType = FREEFORM; + xx->segs[0].u.p.cnt = xx->segs[0].u.p.cnt-1; + } + + ComputeDrawBoundingBox( trk ); + return trk; +} + + +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) + +void static CreateOriginAnchor(coOrd origin, wBool_t trans_selected) { + double d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,anchors_da,2); + int i = anchors_da.cnt-1; + coOrd p0,p1; + Translate(&p0,origin,0,d*4); + Translate(&p1,origin,0,-d*4); + anchors(i).type = SEG_STRLIN; + anchors(i).u.l.pos[0] = p0; + anchors(i).u.l.pos[1] = p1; + anchors(i).color = wDrawColorBlue; + anchors(i).width = 0; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + Translate(&p0,origin,90,d*4); + Translate(&p1,origin,90,-d*4); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).u.l.pos[0] = p0; + anchors(i).u.l.pos[1] = p1; + anchors(i).color = wDrawColorBlue; + anchors(i).width = 0; +} + +EXPORT void DrawOriginAnchor(track_p trk) { + if (!trk || GetTrkType(trk) != T_DRAW) return; + struct extraData * xx = GetTrkExtraData(trk); + if ((xx->orig.x != 0.0) || (xx->orig.y !=0.0) ) { + DYNARR_RESET(trkSeg_t,anchors_da); + CreateOriginAnchor(xx->orig,FALSE); + DrawSegs(&tempD, zero, 0.0, anchors_da.ptr, anchors_da.cnt, trackGauge, wDrawColorBlue); + } +} @@ -204,15 +480,27 @@ static DIST_T DistanceDraw( track_p t, coOrd * p ) static struct { - coOrd endPt[2]; + coOrd endPt[4]; + coOrd origin; + coOrd oldOrigin; + coOrd oldE0; + coOrd oldE1; FLOAT_T length; + FLOAT_T height; + FLOAT_T width; coOrd center; DIST_T radius; ANGLE_T angle0; ANGLE_T angle1; ANGLE_T angle; + ANGLE_T rotate_angle; + ANGLE_T oldAngle; long pointCount; long lineWidth; + BOOL_T boxed; + BOOL_T filled; + BOOL_T open; + BOOL_T lock_origin; wDrawColor color; wIndex_t benchChoice; wIndex_t benchOrient; @@ -221,21 +509,31 @@ static struct { wIndex_t fontSizeInx; char text[STR_LONG_SIZE]; unsigned int layer; - char polyType[STR_SIZE]; + wIndex_t lineType; } drawData; -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; +typedef enum { E0, E1, PP, CE, AL, A1, A2, RD, LN, HT, WT, LK, OI, RA, VC, LW, LT, CO, FL, OP, BX, BE, OR, DS, TP, TA, TS, TX, PV, LY } drawDesc_e; static descData_t drawDesc[] = { /*E0*/ { DESC_POS, N_("End Pt 1: X,Y"), &drawData.endPt[0] }, /*E1*/ { DESC_POS, N_("End Pt 2: X,Y"), &drawData.endPt[1] }, +/*PP*/ { DESC_POS, N_("First Point: X,Y"), &drawData.endPt[0] }, /*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 }, /*A1*/ { DESC_ANGLE, N_("CCW Angle"), &drawData.angle0 }, /*A2*/ { DESC_ANGLE, N_("CW Angle"), &drawData.angle1 }, +/*RD*/ { DESC_DIM, N_("Radius"), &drawData.radius }, +/*LN*/ { DESC_DIM, N_("Length"), &drawData.length }, +/*HT*/ { DESC_DIM, N_("Height"), &drawData.height }, +/*WT*/ { DESC_DIM, N_("Width"), &drawData.width }, +/*LK*/ { DESC_BOXED, N_("Keep Origin Relative"), &drawData.lock_origin}, +/*OI*/ { DESC_POS, N_("Rot Origin: X,Y"), &drawData.origin }, +/*RA*/ { DESC_FLOAT, N_("Rotate Angle"), &drawData.angle }, /*VC*/ { DESC_LONG, N_("Point Count"), &drawData.pointCount }, /*LW*/ { DESC_LONG, N_("Line Width"), &drawData.lineWidth }, +/*LT*/ { DESC_LIST, N_("Line Type"), &drawData.lineType }, /*CO*/ { DESC_COLOR, N_("Color"), &drawData.color }, +/*FL*/ { DESC_BOXED, N_("Filled"), &drawData.filled }, +/*OP*/ { DESC_BOXED, N_("Open End"), &drawData.open }, +/*BX*/ { DESC_BOXED, N_("Boxed"), &drawData.boxed }, /*BE*/ { DESC_LIST, N_("Lumber"), &drawData.benchChoice }, /*OR*/ { DESC_LIST, N_("Orientation"), &drawData.benchOrient }, /*DS*/ { DESC_LIST, N_("Size"), &drawData.dimenSize }, @@ -245,9 +543,8 @@ static descData_t drawDesc[] = { /*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; +static int drawSegInx; #define UNREORIGIN( Q, P, A, O ) { \ (Q) = (P); \ @@ -257,6 +554,23 @@ int drawSegInx; Rotate( &(Q), zero, -(A) ); \ } +/* + * Notes - + * + * In V5.1, Origin was always {0,0} and Angle 0.0 after editing a Draw object. + * This did not allow for the use of the objects in other contexts (such as Signal Arms). + * + * In V5.2 - + * + * OI - Origin will be adjusted if it is locked to remain relative to the end point - this equally applies when moving the object points. + * If not locked, the object points will be set relative to the new origin value, + * so that the object remains at the same place as the user specifies. + * If the edit starts with origin {0,0}, it will be set unlocked, otherwise set locked. + * + * AL- Angle will be set to 0.0 when the object is modified. The points of the objects will be rotated so that + * rotated and adjusted so they don't need rotation to lie where the user left them. + * + */ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) { struct extraData *xx = GetTrkExtraData(trk); @@ -271,9 +585,9 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) if (segPtr->type != SEG_TEXT) return; else inx = TX; //Always look at TextField for SEG_TEXT on "Done" } - MainRedraw(); - MapRedraw(); UndrawNewTrack( trk ); + coOrd pt; + coOrd off; switch ( inx ) { case LW: segPtr->width = drawData.lineWidth/mainD.dpi; @@ -284,37 +598,251 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) case E0: case E1: if ( inx == E0 ) { - UNREORIGIN( segPtr->u.l.pos[0], drawData.endPt[0], xx->angle, xx->orig ); - } else { - UNREORIGIN( segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + coOrd off; + off.x = drawData.endPt[0].x - drawData.oldE0.x; + off.y = drawData.endPt[0].y - drawData.oldE0.y; + if (drawData.lock_origin) { + xx->orig.x +=off.x; + xx->orig.y +=off.y; + drawDesc[OI].mode |= DESC_CHANGE; + } else { + switch(segPtr->type) { //E0 does not alter length - translates + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + UNREORIGIN( segPtr->u.l.pos[0], drawData.endPt[0], xx->angle, xx->orig ); + drawData.endPt[1].x = off.x+drawData.endPt[1].x; + drawData.endPt[1].y = off.y+drawData.endPt[1].y; + UNREORIGIN( segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + drawDesc[E1].mode |= DESC_CHANGE; + break; + case SEG_CRVLIN: + case SEG_FILCRCL: + UNREORIGIN( segPtr->u.c.center, drawData.endPt[0], xx->angle, xx->orig ); + break; + case SEG_TEXT: + UNREORIGIN( segPtr->u.t.pos, drawData.endPt[0], xx->angle, xx->orig ); + break; + case SEG_POLY: + case SEG_FILPOLY: + break; //Note not used by POLYGONS + default:; + } + } + } else { //E1 - alters length + off.x = drawData.endPt[1].x - drawData.oldE1.x; + off.y = drawData.endPt[1].y - drawData.oldE1.y; + drawDesc[E1].mode |= DESC_CHANGE; + if (drawData.lock_origin) { + xx->orig.x +=off.x; + xx->orig.y +=off.y; + drawDesc[OI].mode |= DESC_CHANGE; + } else { + UNREORIGIN( segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + } } drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] ); - drawData.angle = FindAngle( drawData.endPt[0], drawData.endPt[1] ); drawDesc[LN].mode |= DESC_CHANGE; - drawDesc[AL].mode |= DESC_CHANGE; break; - case LN: - case AL: - if ( segPtr->type == SEG_CRVLIN && inx == AL ) { - if ( drawData.angle <= 0.0 || drawData.angle >= 360.0 ) { - ErrorMessage( MSG_CURVE_OUT_OF_RANGE ); - drawData.angle = segPtr->u.c.a1; - drawDesc[AL].mode |= DESC_CHANGE; + case OI: + off.x = drawData.origin.x - drawData.oldOrigin.x; + off.y = drawData.origin.y - drawData.oldOrigin.y; + xx->orig = drawData.origin; + if (!drawData.lock_origin) { + switch(segPtr->type) { + case SEG_POLY: + case SEG_FILPOLY: + for (int i=0;i<segPtr->u.p.cnt;i++) { + REORIGIN( pt, segPtr->u.p.pts[i].pt, xx->angle, drawData.oldOrigin); + UNREORIGIN( segPtr->u.p.pts[i].pt, pt, xx->angle, xx->orig ); + } break; + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + for (int i=0;i<2;i++) { + UNREORIGIN( segPtr->u.l.pos[i], drawData.endPt[i], xx->angle, xx->orig ); + } + break; + case SEG_CRVLIN: + case SEG_FILCRCL: + UNREORIGIN( segPtr->u.c.center, drawData.center, xx->angle, xx->orig ); + break; + case SEG_TEXT: + UNREORIGIN( segPtr->u.t.pos, drawData.endPt[0], xx->angle, xx->orig ); + break; + default:; } } else { - if ( drawData.length <= minLength ) { - ErrorMessage( MSG_OBJECT_TOO_SHORT ); - if ( segPtr->type != SEG_CRVLIN ) { - drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] ); + drawData.endPt[0].x += off.x; + drawData.endPt[0].y += off.y; + switch(segPtr->type) { + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + drawDesc[E0].mode |= DESC_CHANGE; + UNREORIGIN( segPtr->u.l.pos[0], drawData.endPt[0], xx->angle, xx->orig ); + drawData.endPt[1].x = off.x+drawData.endPt[1].x; + drawData.endPt[1].y = off.y+drawData.endPt[1].y; + UNREORIGIN( segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + drawDesc[E1].mode |= DESC_CHANGE; + break; + case SEG_CRVLIN: + case SEG_FILCRCL: + UNREORIGIN( segPtr->u.c.center, drawData.endPt[0], xx->angle, xx->orig ); + drawDesc[E0].mode |= DESC_CHANGE; + break; + case SEG_TEXT: + UNREORIGIN( segPtr->u.t.pos, drawData.endPt[0], xx->angle, xx->orig ); + drawDesc[E0].mode |= DESC_CHANGE; + break; + case SEG_POLY: + case SEG_FILPOLY: + for (int i=0;i<segPtr->u.p.cnt;i++) { + REORIGIN( pt, segPtr->u.p.pts[i].pt, xx->angle, drawData.oldOrigin); + pt.x += off.x; + pt.y += off.y; + UNREORIGIN( segPtr->u.p.pts[i].pt, pt, xx->angle, xx->orig ); + } + drawDesc[PP].mode |= DESC_CHANGE; + break; + default:; + } + } + break; + case HT: + case WT: + if ((segPtr->type == SEG_POLY) || (segPtr->type == SEG_FILPOLY)) { + if (segPtr->u.p.polyType == RECTANGLE) { + if (inx == HT) { + ANGLE_T angle = NormalizeAngle(FindAngle(drawData.endPt[0],drawData.endPt[3])); + Translate( &drawData.endPt[3], drawData.endPt[0], angle, drawData.height); + UNREORIGIN( segPtr->u.p.pts[3].pt, drawData.endPt[3], xx->angle, xx->orig ); + Translate( &drawData.endPt[2], drawData.endPt[1], angle, drawData.height); + UNREORIGIN( segPtr->u.p.pts[2].pt, drawData.endPt[2], xx->angle, xx->orig ); } else { - drawData.length = fabs(segPtr->u.c.radius)*2*M_PI*segPtr->u.c.a1/360.0; + ANGLE_T angle = NormalizeAngle(FindAngle(drawData.endPt[0],drawData.endPt[1]));; + Translate( &drawData.endPt[1], drawData.endPt[0], angle, drawData.width); + UNREORIGIN( segPtr->u.p.pts[1].pt, drawData.endPt[1], xx->angle, xx->orig ); + Translate( &drawData.endPt[2], drawData.endPt[3], angle, drawData.width); + UNREORIGIN( segPtr->u.p.pts[2].pt, drawData.endPt[2], xx->angle, xx->orig ); } - drawDesc[LN].mode |= DESC_CHANGE; + drawDesc[E0].mode |= DESC_CHANGE; + } + } + break; + case RA:; + ANGLE_T angle = NormalizeAngle(drawData.rotate_angle); + switch(segPtr->type) { + case SEG_POLY: + case SEG_FILPOLY: + for (int i=0;i<segPtr->u.p.cnt;i++) { + REORIGIN(pt,segPtr->u.p.pts[i].pt, angle, xx->orig); + if (i == 0) drawData.endPt[0] = pt; + UNREORIGIN(segPtr->u.p.pts[i].pt, pt, 0.0, xx->orig); + } + drawDesc[PP].mode |= DESC_CHANGE; break; + case SEG_CRVLIN:; + coOrd end0, end1; + Translate(&end0,segPtr->u.c.center,segPtr->u.c.a0,segPtr->u.c.radius); + Translate(&end1,segPtr->u.c.center,segPtr->u.c.a0+segPtr->u.c.a1,segPtr->u.c.radius); + REORIGIN(end0, end0, angle, xx->orig ); + REORIGIN(end1, end1, angle, xx->orig ); + REORIGIN( drawData.center,segPtr->u.c.center, angle, xx->orig ); + drawData.angle0 = FindAngle( drawData.center, end0); + drawData.angle1 = FindAngle( drawData.center, end1); + drawDesc[CE].mode |= DESC_CHANGE; + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + /*no break*/ + case SEG_FILCRCL: + REORIGIN( drawData.center,segPtr->u.c.center, angle, xx->orig ); + UNREORIGIN( segPtr->u.c.center, drawData.center, 0.0, xx->orig); //Remove angle + drawDesc[CE].mode |= DESC_CHANGE; + break; + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + for (int i=0;i<2;i++) { + REORIGIN( drawData.endPt[i], segPtr->u.l.pos[i], angle, xx->orig ); + UNREORIGIN(segPtr->u.l.pos[i], drawData.endPt[i], 0.0, xx->orig ); + } + drawDesc[E0].mode |= DESC_CHANGE; + drawDesc[E1].mode |= DESC_CHANGE; + break; + case SEG_TEXT: + + break; + default:; + } + xx->angle = drawData.rotate_angle = 0.0; + drawDesc[RA].mode |= DESC_CHANGE; + break; + case AL:; + angle = NormalizeAngle(drawData.angle); + switch(segPtr->type) { + case SEG_POLY: + case SEG_FILPOLY: + break; //Doesn't Use + case SEG_CRVLIN: + switch ( drawData.pivot ) { + case DESC_PIVOT_FIRST: + segPtr->u.c.a1 = drawData.angle; + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A2].mode |= DESC_CHANGE; + break; + case DESC_PIVOT_SECOND: + segPtr->u.c.a0 = NormalizeAngle( segPtr->u.c.a1+segPtr->u.c.a0-drawData.angle); + segPtr->u.c.a1 = drawData.angle; + drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + break; + case DESC_PIVOT_MID: + segPtr->u.c.a0 = NormalizeAngle( segPtr->u.c.a0+segPtr->u.c.a1/2.0-drawData.angle/2.0); + segPtr->u.c.a1 = drawData.angle; + drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + break; + default: + break; + } + break; + case SEG_FILCRCL: + break; //Doesn't Use + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + Translate(&drawData.endPt[1],drawData.endPt[0],angle,drawData.length); + UNREORIGIN(segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + drawDesc[E1].mode |= DESC_CHANGE; + break; + case SEG_TEXT: + break; //Doesnt Use + default:; + } + break; + case LN: + if ( drawData.length <= minLength ) { + ErrorMessage( MSG_OBJECT_TOO_SHORT ); + if ( segPtr->type != SEG_CRVLIN ) { + drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] ); + } else { + drawData.length = fabs(segPtr->u.c.radius)*2*M_PI*segPtr->u.c.a1/360.0; } + drawDesc[LN].mode |= DESC_CHANGE; + break; } - if ( segPtr->type != SEG_CRVLIN ) { + if ( segPtr->type != SEG_CRVLIN ) { switch ( drawData.pivot ) { case DESC_PIVOT_FIRST: Translate( &drawData.endPt[1], drawData.endPt[0], drawData.angle, drawData.length ); @@ -340,6 +868,7 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) break; } } else { + if ( drawData.angle < 0.0 || drawData.angle >= 360.0 ) { ErrorMessage( MSG_CURVE_OUT_OF_RANGE ); drawData.angle = segPtr->u.c.a1; @@ -357,13 +886,44 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) case CE: UNREORIGIN( segPtr->u.c.center, drawData.center, xx->angle, xx->orig ); break; - case RA: + case RD: + if ( drawData.pivot == DESC_PIVOT_FIRST ) { + Translate( &segPtr->u.c.center, segPtr->u.c.center, segPtr->u.c.a0, segPtr->u.c.radius-drawData.radius ); + } else if ( drawData.pivot == DESC_PIVOT_SECOND ) { + Translate( &segPtr->u.c.center, segPtr->u.c.center, segPtr->u.c.a0+segPtr->u.c.a1, segPtr->u.c.radius-drawData.radius ); + } else { + Translate( &segPtr->u.c.center, segPtr->u.c.center, (segPtr->u.c.a0+segPtr->u.c.a1)/2.0, segPtr->u.c.radius-drawData.radius ); + } + drawDesc[CE].mode |= DESC_CHANGE; segPtr->u.c.radius = drawData.radius; + drawDesc[LN].mode |= DESC_CHANGE; break; case A1: - segPtr->u.c.a0 = NormalizeAngle( drawData.angle0-xx->angle ); - drawData.angle1 = NormalizeAngle( drawData.angle0+drawData.angle ); - drawDesc[A2].mode |= DESC_CHANGE; + switch ( drawData.pivot ) { + case DESC_PIVOT_FIRST: + segPtr->u.c.a1 = drawData.angle; + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A2].mode |= DESC_CHANGE; + break; + case DESC_PIVOT_SECOND: + segPtr->u.c.a0 = NormalizeAngle( segPtr->u.c.a1+segPtr->u.c.a0-drawData.angle); + segPtr->u.c.a1 = drawData.angle; + drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + break; + case DESC_PIVOT_MID: + segPtr->u.c.a0 = NormalizeAngle( segPtr->u.c.a0+segPtr->u.c.a1/2.0-drawData.angle/2.0); + segPtr->u.c.a1 = drawData.angle; + drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + break; + default: + break; + } break; case A2: segPtr->u.c.a0 = NormalizeAngle( drawData.angle1-segPtr->u.c.a1-xx->angle ); @@ -387,6 +947,28 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) case TP: UNREORIGIN( segPtr->u.t.pos, drawData.endPt[0], xx->angle, xx->orig ); break; + case PP: + off.x = drawData.endPt[0].x - drawData.oldE0.x; + off.y = drawData.endPt[0].y - drawData.oldE0.y; + if (drawData.lock_origin) { + xx->orig.x +=off.x; + xx->orig.y +=off.y; + drawData.origin = xx->orig; + drawDesc[OI].mode |= DESC_CHANGE; + drawDesc[E0].mode |= DESC_CHANGE; + break; + } else { + for (int i=0;i<segPtr->u.p.cnt;i++) { + REORIGIN( pt, segPtr->u.p.pts[i].pt, xx->angle, xx->orig ); + pt.x += off.x; + pt.y += off.y; + if (i<5) drawData.endPt[i] = pt; + UNREORIGIN( segPtr->u.p.pts[i].pt, pt, 0.0, xx->orig ); + } + xx->angle = 0.0; + drawDesc[AL].mode |= DESC_CHANGE; + } + break; case TA: //segPtr->u.t.angle = NormalizeAngle( drawData.angle ); xx->angle = NormalizeAngle( drawData.angle ); @@ -396,6 +978,39 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) UpdateFontSizeList( &fontSize, (wList_p)drawDesc[TS].control0, drawData.fontSizeInx ); segPtr->u.t.fontSize = fontSize; break; + case FL: + if (segPtr->type == SEG_POLY && drawData.open) { + drawData.filled = FALSE; + drawDesc[FL].mode |= DESC_CHANGE; + break; + } + if(drawData.filled) { + if (segPtr->type == SEG_POLY) segPtr->type = SEG_FILPOLY; + if (segPtr->type == SEG_CRVLIN) segPtr->type = SEG_FILCRCL; + } else { + if (segPtr->type == SEG_FILPOLY) segPtr->type = SEG_POLY; + if (segPtr->type == SEG_FILCRCL) { + segPtr->type = SEG_CRVLIN; + segPtr->u.c.a0 = 0.0; + segPtr->u.c.a1 = 360.0; + } + } + break; + case OP: + if (drawData.filled || (segPtr->type != SEG_POLY)) { + drawData.open = FALSE; + drawDesc[OP].mode |= DESC_CHANGE; + break; + } + if (drawData.open) { + if (segPtr->type == SEG_POLY && segPtr->u.p.polyType == FREEFORM) segPtr->u.p.polyType = POLYLINE; + } else { + if (segPtr->type == SEG_POLY && segPtr->u.p.polyType == POLYLINE) segPtr->u.p.polyType = FREEFORM; + } + break; + case BX: + segPtr->u.t.boxed = drawData.boxed; + break; case TX: if ( wTextGetModified((wText_p)drawDesc[TX].control0 )) { int len = wTextGetSize((wText_p)drawDesc[TX].control0); @@ -409,14 +1024,25 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) case LY: SetTrkLayer( trk, drawData.layer); break; + case LK: + break; + case LT: + xx->lineType = drawData.lineType; + break; default: AbortProg( "bad op" ); } + drawData.oldE0 = drawData.endPt[0]; + drawData.oldE1 = drawData.endPt[1]; + drawData.oldAngle = drawData.angle; + drawData.oldOrigin = drawData.origin; ComputeDrawBoundingBox( trk ); DrawNewTrack( trk ); - DoCurCommand( C_REDRAW, zero ); + TempRedraw(); // UpdateDraw } +extern BOOL_T inDescribeCmd; + static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) { struct extraData *xx = GetTrkExtraData(trk); @@ -443,8 +1069,17 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) drawDesc[LY].mode = DESC_NOREDRAW; drawDesc[BE].mode = drawDesc[OR].mode = + drawDesc[LT].mode = drawDesc[DS].mode = DESC_IGNORE; drawData.pivot = DESC_PIVOT_MID; + + if ((xx->orig.x == 0.0) && (xx->orig.y == 0.0)) drawData.lock_origin = FALSE; + else drawData.lock_origin = TRUE; + + drawData.rotate_angle = xx->angle; + + drawDesc[LK].mode = 0; + switch ( segPtr->type ) { case SEG_STRLIN: case SEG_DIMLIN: @@ -454,24 +1089,35 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) REORIGIN( drawData.endPt[1], segPtr->u.l.pos[1], xx->angle, xx->orig ); drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] ); drawData.angle = FindAngle( drawData.endPt[0], drawData.endPt[1] ); + drawData.origin = xx->orig; drawDesc[LN].mode = drawDesc[AL].mode = drawDesc[PV].mode = 0; drawDesc[E0].mode = + drawDesc[OI].mode = 0; drawDesc[E1].mode = 0; + drawDesc[RA].mode = 0; switch (segPtr->type) { case SEG_STRLIN: title = _("Straight Line"); + drawDesc[LT].mode = 0; + drawData.lineType = (wIndex_t)xx->lineType; break; case SEG_DIMLIN: title = _("Dimension Line"); - drawDesc[CO].mode = DESC_IGNORE; - drawDesc[LW].mode = DESC_IGNORE; + drawDesc[CO].mode = + drawDesc[LW].mode = + drawDesc[LK].mode = + drawDesc[OI].mode = + drawDesc[RA].mode = DESC_IGNORE; drawData.dimenSize = (wIndex_t)segPtr->u.l.option; drawDesc[DS].mode = 0; break; case SEG_BENCH: title = _("Lumber"); + drawDesc[LK].mode = + drawDesc[OI].mode = + drawDesc[RA].mode = drawDesc[LW].mode = DESC_IGNORE; drawDesc[BE].mode = drawDesc[OR].mode = 0; @@ -480,6 +1126,9 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) break; case SEG_TBLEDGE: title = _("Table Edge"); + drawDesc[LK].mode = + drawDesc[OI].mode = + drawDesc[RA].mode = DESC_IGNORE; drawDesc[CO].mode = DESC_IGNORE; drawDesc[LW].mode = DESC_IGNORE; break; @@ -488,10 +1137,17 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) case SEG_CRVLIN: REORIGIN( drawData.center, segPtr->u.c.center, xx->angle, xx->orig ); drawData.radius = fabs(segPtr->u.c.radius); + drawData.origin = xx->orig; + drawDesc[OI].mode = 0; + drawDesc[RA].mode = drawDesc[CE].mode = - drawDesc[RA].mode = 0; + drawDesc[RD].mode = 0; + drawDesc[LT].mode = 0; + drawData.lineType = (wIndex_t)xx->lineType; if ( segPtr->u.c.a1 >= 360.0 ) { title = _("Circle"); + drawDesc[FL].mode = 0; + drawData.filled = FALSE; } else { drawData.angle = segPtr->u.c.a1; drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); @@ -499,64 +1155,127 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) drawDesc[AL].mode = drawDesc[A1].mode = drawDesc[A2].mode = 0; + drawDesc[PV].mode = 0; title = _("Curved Line"); } break; case SEG_FILCRCL: REORIGIN( drawData.center, segPtr->u.c.center, xx->angle, xx->orig ); drawData.radius = fabs(segPtr->u.c.radius); + drawData.origin = xx->orig; + drawDesc[OI].mode = + drawDesc[RA].mode = + drawDesc[FL].mode = 0; + drawData.filled = TRUE; drawDesc[CE].mode = - drawDesc[RA].mode = 0; + drawDesc[RD].mode = 0; + drawDesc[PV].mode = 0; + drawDesc[OI].mode = 0; drawDesc[LW].mode = DESC_IGNORE; title = _("Filled Circle"); break; case SEG_POLY: + REORIGIN(drawData.endPt[0],segPtr->u.p.pts[0].pt, xx->angle, xx->orig); + drawDesc[PP].mode = 0; drawData.pointCount = segPtr->u.p.cnt; drawDesc[VC].mode = DESC_RO; - drawDesc[PT].mode = DESC_RO; + drawData.filled = FALSE; + drawDesc[FL].mode = 0; + drawData.angle = 0.0; + drawDesc[RA].mode = 0; + drawData.origin = xx->orig; + drawDesc[OI].mode = 0; + drawData.open=FALSE; + drawDesc[OP].mode = 0; + drawDesc[LT].mode = 0; + drawData.lineType = (wIndex_t)xx->lineType; switch (segPtr->u.p.polyType) { case RECTANGLE: - polyType = _("Rectangle"); + title = _("Rectangle"); + drawDesc[OP].mode = DESC_IGNORE; + drawDesc[VC].mode = DESC_IGNORE; + drawData.width = FindDistance(segPtr->u.p.pts[0].pt, segPtr->u.p.pts[1].pt); + drawDesc[WT].mode = 0; + drawData.height = FindDistance(segPtr->u.p.pts[0].pt, segPtr->u.p.pts[3].pt); + drawDesc[HT].mode = 0; + for(int i=0;i<4;i++) { + REORIGIN( drawData.endPt[i], segPtr->u.p.pts[i].pt, xx->angle, xx->orig ); + } + drawDesc[E0].mode = DESC_IGNORE; + drawData.origin = xx->orig; + break; + case POLYLINE: + title = _("Polyline"); + drawData.open=TRUE; break; default: - polyType = _("Freeform"); + title = _("Polygon"); } - strncpy( drawData.polyType, polyType, sizeof drawData.polyType ); - title = _("Polygonal Line"); break; case SEG_FILPOLY: + REORIGIN(drawData.endPt[0],segPtr->u.p.pts[0].pt, xx->angle, xx->orig); + drawDesc[PP].mode = 0; drawData.pointCount = segPtr->u.p.cnt; drawDesc[VC].mode = DESC_RO; + drawData.filled = TRUE; + drawDesc[FL].mode = 0; drawDesc[LW].mode = DESC_IGNORE; - drawDesc[PT].mode = DESC_RO; + drawData.angle = xx->angle; + drawDesc[RA].mode = 0; + drawData.origin = xx->orig; + drawDesc[OI].mode = DESC_RO; + drawData.open = FALSE; switch (segPtr->u.p.polyType) { case RECTANGLE: - polyType =_("Rectangle"); + title =_("Filled Rectangle"); + drawDesc[VC].mode = DESC_IGNORE; + drawData.width = FindDistance(segPtr->u.p.pts[0].pt, segPtr->u.p.pts[1].pt); + drawDesc[WT].mode = 0; + drawData.height = FindDistance(segPtr->u.p.pts[0].pt, segPtr->u.p.pts[3].pt); + drawDesc[HT].mode = 0; + for(int i=0;i<4;i++) { + REORIGIN( drawData.endPt[i], segPtr->u.p.pts[i].pt, xx->angle, xx->orig ); + } + drawDesc[E0].mode = DESC_IGNORE; + drawData.origin = xx->orig; break; default: - polyType = _("Freeform"); + title = _("Filled Polygon"); } - 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( xx->angle ); strncpy( drawData.text, segPtr->u.t.string, sizeof drawData.text ); drawData.text[sizeof drawData.text-1] ='\0'; + drawData.boxed = segPtr->u.t.boxed; + drawData.origin = xx->orig; + drawDesc[E0].mode = drawDesc[TP].mode = drawDesc[TS].mode = drawDesc[TX].mode = - drawDesc[TA].mode = + drawDesc[TA].mode = + drawDesc[BX].mode = + drawDesc[RA].mode = + drawDesc[OI].mode = 0; drawDesc[CO].mode = 0; /*Allow Text color setting*/ drawDesc[LW].mode = DESC_IGNORE; title = _("Text"); break; default: - AbortProg( "bad seg type" ); + ; } - sprintf( str, _("%s: Layer=%d"), title, GetTrkLayer(trk)+1 ); + snprintf( str, len, _("%s(%d) Layer=%d"), title, GetTrkIndex(trk), GetTrkLayer(trk)+1 ); + + if (!inDescribeCmd) return; + + drawData.oldE0 = drawData.endPt[0]; + drawData.oldE1 = drawData.endPt[1]; + drawData.oldAngle = drawData.angle; + drawData.oldOrigin = drawData.origin; + + DoDescribe( title, trk, drawDesc, UpdateDraw ); if ( segPtr->type==SEG_BENCH && drawDesc[BE].control0!=NULL && drawDesc[OR].control0!=NULL) { @@ -565,6 +1284,17 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) BenchUpdateOrientationList( (long)wListGetItemContext((wList_p)drawDesc[BE].control0, drawData.benchChoice ), (wList_p)drawDesc[OR].control0 ); wListSetIndex( (wList_p)drawDesc[OR].control0, drawData.benchOrient ); } + if ( (segPtr->type==SEG_STRLIN || segPtr->type==SEG_CRVLIN || segPtr->type==SEG_POLY) && drawDesc[LT].control0!=NULL) { + wListClear( (wList_p)drawDesc[LT].control0 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("Solid"), NULL, (void*)0 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("Dash"), NULL, (void*)1 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("Dot"), NULL, (void*)2 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("DashDot"), NULL, (void*)3 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("DashDotDot"), NULL, (void*)4 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("CenterDot"), NULL, (void*)5 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("PhantomDot"), NULL, (void*)6 ); + wListSetIndex( (wList_p)drawDesc[LT].control0, drawData.lineType ); + } if ( segPtr->type==SEG_DIMLIN && drawDesc[DS].control0!=NULL ) { wListClear( (wList_p)drawDesc[DS].control0 ); wListAddValue( (wList_p)drawDesc[DS].control0, _("Tiny"), NULL, (void*)0 ); @@ -582,8 +1312,17 @@ 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->funcs->options&DC_QUICK) == 0 ) - DrawSegs( d, xx->orig, xx->angle, xx->segs, xx->segCnt, 0.0, color ); + unsigned long NotSolid = ~(DC_NOTSOLIDLINE); + d->options &= NotSolid; + if (xx->lineType == DRAWLINESOLID) {} + else if (xx->lineType == DRAWLINEDASH) d->options |= DC_DASH; + else if (xx->lineType == DRAWLINEDOT) d->options |= DC_DOT; + else if (xx->lineType == DRAWLINEDASHDOT) d->options |= DC_DASHDOT; + else if (xx->lineType == DRAWLINEDASHDOTDOT) d->options |= DC_DASHDOTDOT; + else if (xx->lineType == DRAWLINECENTER) d->options |= DC_CENTER; + else if (xx->lineType == DRAWLINEPHANTOM) d->options |= DC_PHANTOM; + DrawSegs( d, xx->orig, xx->angle, xx->segs, xx->segCnt, 0.0, color ); + d->options = d->options&~(DC_NOTSOLIDLINE); } @@ -594,6 +1333,7 @@ static void DeleteDraw( track_p t ) if (xx->segs[0].type == SEG_POLY || xx->segs[0].type == SEG_FILPOLY) { MyFree(xx->segs[0].u.p.pts); + xx->segs[0].u.p.pts = NULL; } } @@ -602,14 +1342,15 @@ static BOOL_T WriteDraw( track_p t, FILE * f ) { struct extraData * xx = GetTrkExtraData(t); BOOL_T rc = TRUE; - rc &= fprintf(f, "DRAW %d %d 0 0 0 %0.6f %0.6f 0 %0.6f\n", GetTrkIndex(t), GetTrkLayer(t), + rc &= fprintf(f, "DRAW %d %d %d 0 0 %0.6f %0.6f 0 %0.6f\n", GetTrkIndex(t), GetTrkLayer(t), + xx->lineType, xx->orig.x, xx->orig.y, xx->angle )>0; rc &= WriteSegs( f, xx->segCnt, xx->segs ); return rc; } -static void ReadDraw( char * header ) +static BOOL_T ReadDraw( char * header ) { track_p trk; wIndex_t index; @@ -617,12 +1358,14 @@ static void ReadDraw( char * header ) DIST_T elev; ANGLE_T angle; wIndex_t layer; + int lineType; struct extraData * xx; - if ( !GetArgs( header+5, paramVersion<3?"dXpYf":paramVersion<9?"dL000pYf":"dL000pff", - &index, &layer, &orig, &elev, &angle ) ) - return; - ReadSegs(); + if ( !GetArgs( header+5, paramVersion<3?"dXXpYf":paramVersion<9?"dLX00pYf":"dLd00pff", + &index, &layer, &lineType, &orig, &elev, &angle ) ) + return FALSE; + if ( !ReadSegs() ) + return FALSE; if (tempSegs_da.cnt == 1) { trk = MakeDrawFromSeg1( index, orig, angle, &tempSegs(0) ); SetTrkLayer( trk, layer ); @@ -633,9 +1376,11 @@ static void ReadDraw( char * header ) xx->orig = orig; xx->angle = angle; xx->segCnt = tempSegs_da.cnt; + xx->lineType = lineType; memcpy( xx->segs, tempSegs_da.ptr, tempSegs_da.cnt * sizeof *(trkSeg_p)0 ); ComputeDrawBoundingBox( trk ); } + return TRUE; } @@ -665,22 +1410,283 @@ static void RescaleDraw( track_p trk, FLOAT_T ratio ) RescaleSegs( xx->segCnt, xx->segs, ratio, ratio, ratio ); } +static void DoConvertFill(void) { + +} + +static drawModContext_t drawModCmdContext = { + InfoMessage, + DoRedraw, + &mainD}; + + +static BOOL_T infoSubst = FALSE; + +static paramIntegerRange_t i0_100 = { 0, 100, 25 }; +static paramFloatRange_t r1_10000 = { 1, 10000 }; +static paramFloatRange_t r0_10000 = { 0, 10000 }; +static paramFloatRange_t r10000_10000 = {-10000, 10000}; +static paramFloatRange_t r360_360 = { -360, 360, 80 }; +static paramFloatRange_t r0_360 = { 0, 360, 80 }; +static paramData_t drawModPLs[] = { + +#define drawModLengthPD (drawModPLs[0]) + { PD_FLOAT, &drawModCmdContext.length, "Length", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Length") }, +#define drawModAnglePD (drawModPLs[1]) + { PD_FLOAT, &drawModCmdContext.abs_angle, "Angle", PDO_NORECORD|BO_ENTER, &r360_360, N_("Angle") }, +#define drawModRelAnglePD (drawModPLs[2]) +#define drawModRelAngle 2 + { PD_FLOAT, &drawModCmdContext.rel_angle, "Rel Angle", PDO_NORECORD|BO_ENTER, &r360_360, N_("Relative Angle") }, +#define drawModWidthPD (drawModPLs[3]) + { PD_FLOAT, &drawModCmdContext.width, "Width", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Width") }, +#define drawModHeightPD (drawModPLs[4]) + { PD_FLOAT, &drawModCmdContext.height, "Height", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Height") }, +#define drawModRadiusPD (drawModPLs[5]) +#define drawModRadius 5 + { PD_FLOAT, &drawModCmdContext.radius, "Radius", PDO_DIM|PDO_NORECORD|BO_ENTER, &r10000_10000, N_("Radius") }, +#define drawModArcAnglePD (drawModPLs[6]) + { PD_FLOAT, &drawModCmdContext.arc_angle, "ArcAngle", PDO_NORECORD|BO_ENTER, &r360_360, N_("Arc Angle") }, +#define drawModRotAnglePD (drawModPLs[7) + { PD_FLOAT, &drawModCmdContext.rot_angle, "Rot Angle", PDO_NORECORD|BO_ENTER, &r0_360, N_("Rotate Angle") }, +#define drawModRotCenterXPD (drawModPLs[8]) +#define drawModRotCenterInx 8 + { PD_FLOAT, &drawModCmdContext.rot_center.x, "Rot Center X,Y", PDO_NORECORD|BO_ENTER, &r0_10000, N_("Rot Center X") }, +#define drawModRotCenterYPD (drawModPLs[9]) + { PD_FLOAT, &drawModCmdContext.rot_center.y, " ", PDO_NORECORD|BO_ENTER, &r0_10000, N_("Rot Center Y") }, + +}; +static paramGroup_t drawModPG = { "drawMod", 0, drawModPLs, sizeof drawModPLs/sizeof drawModPLs[0] }; + +static void DrawModDlgUpdate( + paramGroup_p pg, + int inx, + void * valueP ) +{ + DrawGeomModify(C_UPDATE,zero,&drawModCmdContext); + ParamLoadControl(&drawModPG,drawModRotCenterInx-1); //Make sure the angle is updated in case center moved + ParamLoadControl(&drawModPG,drawModRadius); // Make sure Radius updated + ParamLoadControl(&drawModPG,drawModRelAngle); //Relative Angle as well + MainRedraw(); + +} static STATUS_T ModifyDraw( track_p trk, wAction_t action, coOrd pos ) { struct extraData * xx = GetTrkExtraData(trk); - STATUS_T rc; + STATUS_T rc = C_CONTINUE; - if (action == C_DOWN) { - //UndrawNewTrack( trk ); - } - if ( action == C_MOVE ) + wControl_p controls[5]; //Always needs a NULL last entry + char * labels[4]; + + drawModCmdContext.trk = trk; + drawModCmdContext.orig = xx->orig; + drawModCmdContext.angle = xx->angle; + drawModCmdContext.segCnt = xx->segCnt; + drawModCmdContext.segPtr = xx->segs; + drawModCmdContext.selected = GetTrkSelected(trk); + + + switch(action&0xFF) { //Remove Text value + case C_START: + drawModCmdContext.type = xx->segs[0].type; + switch(drawModCmdContext.type) { + case SEG_POLY: + case SEG_FILPOLY: + drawModCmdContext.filled = (drawModCmdContext.type==SEG_FILPOLY)?TRUE:FALSE; + drawModCmdContext.subtype = xx->segs[0].u.p.polyType; + drawModCmdContext.open = (drawModCmdContext.subtype==POLYLINE)?TRUE:FALSE; + break; + case SEG_TEXT: + InfoMessage("Text can only be modified in Describe Mode"); + wBeep(); + return C_ERROR; + default: + break; + + } + drawModCmdContext.rot_moved = FALSE; + drawModCmdContext.rotate_state = FALSE; + + infoSubst = FALSE; + rc = DrawGeomModify( C_START, pos, &drawModCmdContext ); + break; + case C_DOWN: + rc = DrawGeomModify( C_DOWN, pos, &drawModCmdContext ); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + case C_LDOUBLE: + rc = DrawGeomModify( C_LDOUBLE, pos, &drawModCmdContext ); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + case wActionMove: + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + break; + case C_REDRAW: + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + break; + case C_MOVE: + ignoredDraw = trk; + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + ignoredDraw = NULL; + break; + case C_UP: + ignoredDraw = trk; + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + ignoredDraw = NULL; + ComputeDrawBoundingBox( trk ); + if (drawModCmdContext.state == MOD_AFTER_PT) { + switch(drawModCmdContext.type) { + case SEG_POLY: + case SEG_FILPOLY: + if (xx->segs[0].u.p.polyType != RECTANGLE) { + if (drawModCmdContext.prev_inx >= 0) { + controls[0] = drawModLengthPD.control; + controls[1] = drawModRelAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Seg Lth"); + labels[1] = N_("Rel Ang"); + ParamLoadControls( &drawModPG ); + InfoSubstituteControls( controls, labels ); + drawModLengthPD.option &= ~PDO_NORECORD; + drawModRelAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + } + } else { + controls[0] = drawModWidthPD.control; + controls[1] = drawModHeightPD.control; + controls[2] = NULL; + labels[0] = N_("Width"); + labels[1] = N_("Height"); + ParamLoadControls( &drawModPG ); + InfoSubstituteControls( controls, labels ); + drawModWidthPD.option &= ~PDO_NORECORD; + drawModHeightPD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + } + break; + case SEG_STRLIN: + case SEG_BENCH: + case SEG_DIMLIN: + case SEG_TBLEDGE: + controls[0] = drawModLengthPD.control; + controls[1] = drawModAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Length"); + labels[1] = N_("Angle"); + ParamLoadControls( &drawModPG ); + InfoSubstituteControls( controls, labels ); + drawModLengthPD.option &= ~PDO_NORECORD; + drawModAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + case SEG_CRVLIN: + case SEG_FILCRCL: + controls[0] = drawModRadiusPD.control; + controls[1] = NULL; + labels[0] = N_("Radius"); + if ((drawModCmdContext.type == SEG_CRVLIN) && xx->segs[0].u.c.a1>0.0 && xx->segs[0].u.c.a1 <360.0) { + controls[1] = drawModArcAnglePD.control; + controls[2] = NULL; + labels[1] = N_("Arc Angle"); + } + ParamLoadControls( &drawModPG ); + InfoSubstituteControls( controls, labels ); + drawModArcAnglePD.option &= ~PDO_NORECORD; + if (drawModCmdContext.type == SEG_CRVLIN) + drawModArcAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + default: + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + break; + } + } else { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + case C_CMDMENU: + menuPos = pos; + wMenuPopupShow( drawModDelMI ); + wMenuPushEnable( drawModPointsMode,drawModCmdContext.rotate_state); + wMenuPushEnable( drawModriginMode,!drawModCmdContext.rotate_state); + wMenuPushEnable( drawModRound, FALSE); + wMenuPushEnable( drawModVertex, FALSE); + wMenuPushEnable( drawModSmooth, FALSE); + wMenuPushEnable( drawModDel, FALSE); + wMenuPushEnable( drawModFill, FALSE); + wMenuPushEnable( drawModEmpty, FALSE); + wMenuPushEnable( drawModClose, FALSE); + wMenuPushEnable( drawModOpen, FALSE); + wMenuPushEnable( drawModSolid, TRUE); + wMenuPushEnable( drawModDot, TRUE); + wMenuPushEnable( drawModDash, TRUE); + wMenuPushEnable( drawModDashDot, TRUE); + wMenuPushEnable( drawModDashDotDot, TRUE); + wMenuPushEnable( drawModCenterDot, TRUE); + wMenuPushEnable( drawModPhantom, TRUE); + if (!drawModCmdContext.rotate_state && (drawModCmdContext.type == SEG_POLY || drawModCmdContext.type == SEG_FILPOLY)) { + wMenuPushEnable( drawModDel,drawModCmdContext.prev_inx>=0); + if ((!drawModCmdContext.open && drawModCmdContext.prev_inx>=0) || + ((drawModCmdContext.prev_inx>0) && (drawModCmdContext.prev_inx<drawModCmdContext.max_inx))) { + wMenuPushEnable( drawModRound,TRUE); + wMenuPushEnable( drawModVertex, TRUE); + wMenuPushEnable( drawModSmooth, TRUE); + } + wMenuPushEnable( drawModFill, (!drawModCmdContext.open) && (!drawModCmdContext.filled)); + wMenuPushEnable( drawModEmpty, (!drawModCmdContext.open) && (drawModCmdContext.filled)); + wMenuPushEnable( drawModClose, drawModCmdContext.open); + wMenuPushEnable( drawModOpen, !drawModCmdContext.open); + } + wMenuPushEnable( drawModOrigin,drawModCmdContext.rotate_state); + wMenuPushEnable( drawModLast,drawModCmdContext.rotate_state && (drawModCmdContext.prev_inx>=0)); + wMenuPushEnable( drawModCenter,drawModCmdContext.rotate_state); + break; + case C_TEXT: + ignoredDraw = trk ; + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + ignoredDraw = NULL; + if (rc == C_CONTINUE) break; + /* no break*/ + case C_FINISH: ignoredDraw = trk; - rc = DrawGeomModify( xx->orig, xx->angle, xx->segCnt, xx->segs, action, pos, GetTrkSelected(trk) ); - ignoredDraw = NULL; - if (action == C_UP) { + rc = DrawGeomModify( C_FINISH, pos, &drawModCmdContext ); + xx->angle = drawModCmdContext.angle; + xx->orig = drawModCmdContext.orig; + ignoredDraw = NULL; ComputeDrawBoundingBox( trk ); - DrawNewTrack( trk ); + DYNARR_RESET(trkSeg_t,tempSegs_da); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + case C_CANCEL: + case C_CONFIRM: + case C_TERMINATE: + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + drawModCmdContext.state = MOD_NONE; + DYNARR_RESET(trkSeg_t,tempSegs_da); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + + default: + + break; } return rc; } @@ -768,7 +1774,7 @@ static BOOL_T StoreDraw( if (xx->segs[0].type == SEG_POLY || xx->segs[0].type == SEG_FILPOLY) { *data = xx->segs[0].u.p.pts; - *len = xx->segs[0].u.p.cnt* sizeof (coOrd); + *len = xx->segs[0].u.p.cnt* sizeof (pts_t); return TRUE; } return FALSE; @@ -789,6 +1795,275 @@ static BOOL_T ReplayDraw( return FALSE; } +static BOOL_T QueryDraw( track_p trk, int query ) +{ + struct extraData * xx = GetTrkExtraData(trk); + switch(query) { + case Q_IS_DRAW: + return TRUE; + case Q_IS_POLY: + if ((xx->segs[0].type == SEG_POLY) || (xx->segs[0].type == SEG_FILPOLY) ) { + return TRUE; + } + else + return FALSE; + case Q_IS_TEXT: + if (xx->segs[0].type== SEG_TEXT) return TRUE; + else return FALSE; + case Q_GET_NODES: + return TRUE; + case Q_CAN_PARALLEL: + if ((xx->segs[0].type == SEG_STRLIN) || (xx->segs[0].type == SEG_CRVLIN || + ((xx->segs[0].type == SEG_POLY) && (xx->segs[0].u.p.polyType == POLYLINE)) + )) return TRUE; + else return FALSE; + default: + return FALSE; + } +} + +static wBool_t CompareDraw( track_cp trk1, track_cp trk2 ) +{ + struct extraData *xx1 = GetTrkExtraData( trk1 ); + struct extraData *xx2 = GetTrkExtraData( trk2 ); + char * cp = message + strlen(message); + REGRESS_CHECK_POS( "Orig", xx1, xx2, orig ) + REGRESS_CHECK_ANGLE( "Angle", xx1, xx2, angle ) + REGRESS_CHECK_INT( "LineType", xx1, xx2, lineType ) + return CompareSegs( xx1->segs, xx1->segCnt, xx2->segs, xx2->segCnt ); +} + +static BOOL_T GetParamsDraw( int inx, track_p trk, coOrd pos, trackParams_t * params ) { + + struct extraData * xx = GetTrkExtraData(trk); + if (inx != PARAMS_NODES ) return FALSE; + DYNARR_RESET(coOrd,params->nodes); + BOOL_T back = FALSE; + coOrd start,end; + switch (xx->segs[0].type) { + case SEG_POLY: + if (xx->segs[0].u.p.polyType != POLYLINE) return FALSE; + REORIGIN(start,xx->segs[0].u.p.pts[0].pt,xx->angle,xx->orig); + REORIGIN(end,xx->segs[0].u.p.pts[xx->segs[0].u.p.cnt-1].pt,xx->angle,xx->orig); + if (FindDistance(pos,start)>FindDistance(pos,end)) back = TRUE; + for (int i=0;i<xx->segs[0].u.p.cnt;i++) { + DYNARR_APPEND(coOrd,params->nodes,xx->segs[0].u.p.cnt); + if (back) + DYNARR_LAST(coOrd,params->nodes) = xx->segs[0].u.p.pts[xx->segs[0].u.p.cnt-1-i].pt; + else + DYNARR_LAST(coOrd,params->nodes) = xx->segs[0].u.p.pts[i].pt; + REORIGIN(DYNARR_LAST(coOrd,params->nodes),DYNARR_LAST(coOrd,params->nodes),xx->angle,xx->orig); + } + params->lineOrig = DYNARR_N(coOrd,params->nodes,0); + params->lineEnd = DYNARR_LAST(coOrd,params->nodes); + return TRUE; + + case SEG_STRLIN:; + REORIGIN(start,xx->segs[0].u.l.pos[0],xx->angle,xx->orig); + REORIGIN(end,xx->segs[0].u.l.pos[1],xx->angle,xx->orig); + if (FindDistance(pos,start)>FindDistance(pos,end)) back = TRUE; + for (int i=0;i<2;i++) { + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),xx->segs[0].u.l.pos[back?1-i:i],xx->angle,xx->orig); + } + params->lineOrig = DYNARR_N(coOrd,params->nodes,0); + params->lineEnd = DYNARR_LAST(coOrd,params->nodes); + return TRUE; + + case SEG_CRVLIN:; + Translate(&start,xx->segs[0].u.c.center,xx->segs[0].u.c.a0,fabs(xx->segs[0].u.c.radius)); + REORIGIN(start,start,xx->angle,xx->orig); + Translate(&end,xx->segs[0].u.c.center,xx->segs[0].u.c.a0+xx->segs[0].u.c.a1,fabs(xx->segs[0].u.c.radius)); + REORIGIN(end,end,xx->angle,xx->orig); + if (FindDistance(start,pos) > FindDistance(end,pos)) back = TRUE; + if (fabs(xx->segs[0].u.c.radius) > 0.5) { + double min_angle = R2D(2*acos(1.0-(0.1/fabs(xx->segs[0].u.c.radius)))); //Error max is 0.1" + int number = (int) ceil(xx->segs[0].u.c.a1/min_angle); + double arc_size = xx->segs[0].u.c.a1/number; + for (int i=0;i<=number;i++) { + DYNARR_APPEND(coOrd,params->nodes,number); + if (back) + Translate(&DYNARR_LAST(coOrd,params->nodes),xx->segs[0].u.c.center,xx->segs[0].u.c.a0+xx->segs[0].u.c.a1-(i*arc_size),fabs(xx->segs[0].u.c.radius)); + else + Translate(&DYNARR_LAST(coOrd,params->nodes),xx->segs[0].u.c.center,xx->segs[0].u.c.a0+(i*arc_size),fabs(xx->segs[0].u.c.radius)); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),DYNARR_LAST(coOrd,params->nodes),xx->angle,xx->orig); + } + } else { + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),back?end:start,xx->angle,xx->orig); + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),back?start:end,xx->angle,xx->orig); + } + params->lineOrig = DYNARR_N(coOrd,params->nodes,0); + params->lineEnd = DYNARR_LAST(coOrd,params->nodes); + return TRUE; + + case SEG_BEZLIN: + REORIGIN(start,xx->segs[0].u.b.pos[0],xx->angle,xx->orig); + REORIGIN(end,xx->segs[0].u.b.pos[3],xx->angle,xx->orig); + if (FindDistance(pos,start) < FindDistance(pos,end)) + params->ep = 0; + else params->ep = 1; + BOOL_T back = FALSE; + coOrd curr_pos = params->bezierPoints[params->ep*3]; + BOOL_T first = TRUE; + for (int i = 0; i<xx->segs[0].bezSegs.cnt;i++) { + trkSeg_p segPtr = &DYNARR_N(trkSeg_t,xx->segs[0].bezSegs,params->ep?xx->segs[0].bezSegs.cnt-1-i:i); + if (segPtr->type == SEG_STRLIN) { + back = FindDistance(segPtr->u.l.pos[0],curr_pos)>FindDistance(segPtr->u.l.pos[1],curr_pos); + if (first) { + first = FALSE; + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),segPtr->u.l.pos[back],xx->angle,xx->orig); + } + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),segPtr->u.l.pos[1-back],xx->angle,xx->orig); + curr_pos = DYNARR_LAST(coOrd,params->nodes); + } else { + coOrd start,end; + Translate(&start,segPtr->u.c.center,segPtr->u.c.a0,segPtr->u.c.radius); + Translate(&end,segPtr->u.c.center,segPtr->u.c.a0+segPtr->u.c.a1,segPtr->u.c.radius); + back = FindDistance(start,curr_pos)>FindDistance(end,curr_pos); + if (fabs(segPtr->u.c.radius) > 0.2) { + double min_angle = 360*acos(1.0-(0.1/fabs(segPtr->u.c.radius)))/M_PI; //Error max is 0.1" + int number = (int)ceil(segPtr->u.c.a1/min_angle); + double arc_size = segPtr->u.c.a1/number; + for (int j=1-first;j<number;j++) { + DYNARR_APPEND(coOrd,params->nodes,number-first); + if (back == params->ep) + Translate(&DYNARR_LAST(coOrd,params->nodes),segPtr->u.c.center,segPtr->u.c.a0+(j*arc_size),fabs(segPtr->u.c.radius) ); + else + Translate(&DYNARR_LAST(coOrd,params->nodes),segPtr->u.c.center,segPtr->u.c.a0+segPtr->u.c.a1-(j*arc_size),fabs(segPtr->u.c.radius) ); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),DYNARR_LAST(coOrd,params->nodes),xx->angle,xx->orig); + } + first = FALSE; + } else { + if (first) { + first = FALSE; + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),start,xx->angle,xx->orig); + } + DYNARR_APPEND(coOrd,params->nodes,1); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),end,xx->angle,xx->orig); + first = FALSE; + } + curr_pos = DYNARR_LAST(coOrd,params->nodes); + } + } + params->lineOrig = DYNARR_N(coOrd,params->nodes,0); + params->lineEnd = DYNARR_LAST(coOrd,params->nodes); + return TRUE; + + default: + return FALSE; + } + return FALSE; + + +} + +static BOOL_T MakeParallelDraw( + track_p trk, + coOrd pos, + DIST_T sep, + DIST_T factor, + track_p * newTrkR, + coOrd * p0R, + coOrd * p1R, + BOOL_T track) +{ + if (track) return FALSE; + struct extraData * xx = GetTrkExtraData(trk); + + ANGLE_T angle; + DIST_T rad; + coOrd p0,p1; + + switch (xx->segs[0].type) { + case SEG_STRLIN: + angle = FindAngle(xx->segs[0].u.l.pos[0],xx->segs[0].u.l.pos[1]); + if ( NormalizeAngle( FindAngle( xx->segs[0].u.l.pos[0], pos ) - angle ) < 180.0 ) + angle += 90; + else + angle -= 90; + Translate(&p0,xx->segs[0].u.l.pos[0], angle, sep); + Translate(&p1,xx->segs[0].u.l.pos[1], angle, sep); + tempSegs(0).color = xx->segs[0].color; + tempSegs(0).width = xx->segs[0].width; + tempSegs_da.cnt = 1; + tempSegs(0).type = SEG_STRLIN; + tempSegs(0).u.l.pos[0] = p0; + tempSegs(0).u.l.pos[1] = p1; + if (newTrkR) { + *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) ); + struct extraData * yy = GetTrkExtraData(*newTrkR); + yy->lineType = xx->lineType; + } + + if ( p0R ) *p0R = p0; + if ( p1R ) *p1R = p1; + return TRUE; + break; + case SEG_CRVLIN: + rad = FindDistance( pos, xx->segs[0].u.c.center ); + if ( rad > xx->segs[0].u.c.radius ) + rad = xx->segs[0].u.c.radius + sep; + else + rad = xx->segs[0].u.c.radius - sep; + tempSegs(0).color = xx->segs[0].color; + tempSegs(0).width = xx->segs[0].width; + tempSegs_da.cnt = 1; + tempSegs(0).type = SEG_CRVLIN; + tempSegs(0).u.c.center = xx->segs[0].u.c.center; + tempSegs(0).u.c.radius = rad; + tempSegs(0).u.c.a0 = xx->segs[0].u.c.a0; + tempSegs(0).u.c.a1 = xx->segs[0].u.c.a1; + if (newTrkR) { + *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) ); + struct extraData * yy = GetTrkExtraData(*newTrkR); + yy->lineType = xx->lineType; + } + if ( p0R ) PointOnCircle( p0R, xx->segs[0].u.c.center, rad, xx->segs[0].u.c.a0 ); + if ( p1R ) PointOnCircle( p1R, xx->segs[0].u.c.center, rad, xx->segs[0].u.c.a0+xx->segs[0].u.c.a1 ); + return TRUE; + break; + case SEG_POLY: + if (xx->segs[0].u.p.polyType != POLYLINE) return FALSE; + int inx2; + coOrd p = pos; + angle = GetAngleSegs(1,&xx->segs[0],&p,NULL,NULL,NULL,&inx2,NULL); + if ( NormalizeAngle( FindAngle( p, pos ) - angle ) < 180.0 ) { + sep = sep*1.0; + angle += 90; + } else { + angle -= 90; + sep = sep*1.0; + } + tempSegs(0).color = xx->segs[0].color; + tempSegs(0).width = xx->segs[0].width; + tempSegs_da.cnt = 1; + tempSegs(0).type = SEG_POLY; + tempSegs(0).u.p.polyType = POLYLINE; + tempSegs(0).u.p.pts = memdup( xx->segs[0].u.p.pts, xx->segs[0].u.p.cnt*sizeof (pts_t) ); + tempSegs(0).u.p.cnt = xx->segs[0].u.p.cnt; + for (int i=0;i<xx->segs[0].u.p.cnt;i++) { + Translate(&tempSegs(0).u.p.pts[i].pt,tempSegs(0).u.p.pts[i].pt,angle,sep); + } + if (newTrkR) { + *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) ); + struct extraData * yy = GetTrkExtraData(*newTrkR); + yy->lineType = xx->lineType; + if (tempSegs(0).u.p.pts) MyFree(tempSegs(0).u.p.pts); + } + if (p0R) *p0R = tempSegs(0).u.p.pts[0].pt; + if (p1R) *p1R = tempSegs(0).u.p.pts[tempSegs(0).u.p.cnt-1].pt; + return TRUE; + break; + default: + return FALSE; + } + return FALSE; +} static trackCmd_t drawCmds = { "DRAW", @@ -811,19 +2086,21 @@ static trackCmd_t drawCmds = { NULL, /* merge */ ModifyDraw, NULL, /* getLength */ - NULL, /* getTrackParams */ + GetParamsDraw, /* getTrackParams */ NULL, /* moveEndPt */ - NULL, /* query */ + QueryDraw, /* query */ UngroupDraw, FlipDraw, NULL, NULL, NULL, - NULL, /*Parallel*/ + MakeParallelDraw, /*Parallel*/ NULL, NULL, /*MakeSegs*/ ReplayDraw, - StoreDraw + StoreDraw, + NULL, + CompareDraw }; EXPORT BOOL_T OnTableEdgeEndPt( track_p trk, coOrd * pos ) @@ -918,19 +2195,12 @@ EXPORT BOOL_T GetClosestEndPt( track_p trk, coOrd * pos) } -static void DrawRedraw(void); static drawContext_t drawCmdContext = { InfoMessage, - DrawRedraw, + DoRedraw, &mainD, OP_LINE }; -static void DrawRedraw( void ) -{ - MainRedraw(); - MapRedraw(); -} - static wIndex_t benchChoice; static wIndex_t benchOrient; static wIndex_t dimArrowSize; @@ -939,10 +2209,10 @@ long lineWidth = 0; static wDrawColor benchColor; -static paramIntegerRange_t i0_100 = { 0, 100, 25 }; + static paramData_t drawPLs[] = { -#define drawWidthPD (drawPLs[0]) - { PD_LONG, &drawCmdContext.Width, "linewidth", PDO_NORECORD, &i0_100, N_("Line Width") }, +#define drawLineWidthPD (drawPLs[0]) + { PD_LONG, &drawCmdContext.line_Width, "linewidth", PDO_NORECORD, &i0_100, N_("Line Width") }, #define drawColorPD (drawPLs[1]) { PD_COLORLIST, &lineColor, "linecolor", PDO_NORECORD, NULL, N_("Color") }, #define drawBenchColorPD (drawPLs[2]) @@ -960,7 +2230,19 @@ static paramData_t drawPLs[] = { { PD_DROPLIST, &benchOrient, "benchorient", PDO_NOPREF|PDO_NORECORD|PDO_LISTINDEX, (void*)105, "", 0 }, #endif #define drawDimArrowSizePD (drawPLs[5]) - { PD_DROPLIST, &dimArrowSize, "arrowsize", PDO_NORECORD|PDO_LISTINDEX, (void*)80, N_("Size") } }; + { PD_DROPLIST, &dimArrowSize, "arrowsize", PDO_NORECORD|PDO_LISTINDEX, (void*)80, N_("Size") }, +#define drawLengthPD (drawPLs[6]) + { PD_FLOAT, &drawCmdContext.length, "Length", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Length") }, +#define drawWidthPD (drawPLs[7]) + { PD_FLOAT, &drawCmdContext.width, "BoxWidth", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Width") }, +#define drawAnglePD (drawPLs[8]) +#define drawAngleInx 8 + { PD_FLOAT, &drawCmdContext.angle, "Angle", PDO_NORECORD|BO_ENTER, &r360_360, N_("Angle") }, +#define drawRadiusPD (drawPLs[9]) + { PD_FLOAT, &drawCmdContext.radius, "Radius", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Radius") }, +#define drawLineTypePD (drawPLs[10]) + { PD_DROPLIST, &drawCmdContext.lineType, "Type", PDO_DIM|PDO_NORECORD|BO_ENTER, (void*)0, N_("Line Type") }, +}; static paramGroup_t drawPG = { "draw", 0, drawPLs, sizeof drawPLs/sizeof drawPLs[0] }; static char * objectName[] = { @@ -976,21 +2258,22 @@ static char * objectName[] = { N_("Circle"), N_("Circle"), N_("Box"), - N_("Polyline"), + N_("Polygon"), N_("Filled Circle"), N_("Filled Circle"), N_("Filled Circle"), N_("Filled Box"), - N_("Polygon"), + N_("Filled Polygon"), N_("Bezier Line"), + N_("Polyline"), NULL}; static STATUS_T CmdDraw( wAction_t action, coOrd pos ) { static BOOL_T infoSubst = FALSE; - wControl_p controls[4]; - char * labels[3]; + wControl_p controls[5]; //Always needs a NULL last entry + char * labels[4]; static char labelName[40]; wAction_t act2 = (action&0xFF) | (bezCmdCreateLine<<8); @@ -1000,7 +2283,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) case C_START: ParamLoadControls( &drawPG ); /*drawContext = &drawCmdContext;*/ - drawWidthPD.option |= PDO_NORECORD; + drawLineWidthPD.option |= PDO_NORECORD; drawColorPD.option |= PDO_NORECORD; drawBenchColorPD.option |= PDO_NORECORD; drawBenchChoicePD.option |= PDO_NORECORD; @@ -1021,19 +2304,29 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) case OP_CURVE4: case OP_CIRCLE2: case OP_CIRCLE3: + case OP_BEZLIN: case OP_BOX: case OP_POLY: - case OP_BEZLIN: - controls[0] = drawWidthPD.control; + case OP_POLYLINE: + controls[0] = drawLineWidthPD.control; controls[1] = drawColorPD.control; + controls[2] = drawLineTypePD.control; controls[2] = NULL; sprintf( labelName, _("%s Line Width"), _(objectName[drawCmdContext.Op]) ); labels[0] = labelName; labels[1] = N_("Color"); + labels[2] = N_("Type"); + if ( wListGetCount( (wList_p)drawLineTypePD.control ) == 0 ) { + wListAddValue( (wList_p)drawLineTypePD.control, _("Solid"), NULL, NULL ); + wListAddValue( (wList_p)drawLineTypePD.control, _("Dot"), NULL, NULL ); + wListAddValue( (wList_p)drawLineTypePD.control, _("Dash"), NULL, NULL ); + wListAddValue( (wList_p)drawLineTypePD.control, _("Dash-Dot"), NULL, NULL ); + wListAddValue( (wList_p)drawLineTypePD.control, _("Dash-Dot-Dot"), NULL, NULL ); + } InfoSubstituteControls( controls, labels ); - drawWidthPD.option &= ~PDO_NORECORD; + drawLineWidthPD.option &= ~PDO_NORECORD; drawColorPD.option &= ~PDO_NORECORD; - lineWidth = drawCmdContext.Width; + drawLineTypePD.option &= ~PDO_NORECORD; break; case OP_FILLCIRCLE2: case OP_FILLCIRCLE3: @@ -1065,6 +2358,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) drawBenchColorPD.option &= ~PDO_NORECORD; drawBenchChoicePD.option &= ~PDO_NORECORD; drawBenchOrientPD.option &= ~PDO_NORECORD; + drawLengthPD.option &= ~PDO_NORECORD; break; case OP_DIMLINE: controls[0] = drawDimArrowSizePD.control; @@ -1081,9 +2375,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) drawDimArrowSizePD.option &= ~PDO_NORECORD; break; case OP_TBLEDGE: - InfoSubstituteControls( NULL, NULL ); InfoMessage( _("Drag to create Table Edge") ); - drawColorPD.option &= ~PDO_NORECORD; break; default: InfoSubstituteControls( NULL, NULL ); @@ -1091,8 +2383,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) } ParamGroupRecord( &drawPG ); if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - DrawGeomMouse( C_START, pos, &drawCmdContext ); - + DrawGeomMouse( C_START, pos, &drawCmdContext); return C_CONTINUE; case wActionLDown: @@ -1106,7 +2397,10 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) drawCmdContext.Color = benchColor; } else if ( drawCmdContext.Op == OP_DIMLINE ) { + drawCmdContext.Color = wDrawColorBlack; drawCmdContext.benchOption = dimArrowSize; + } else if ( drawCmdContext.Op == OP_TBLEDGE ) { + drawCmdContext.Color = wDrawColorBlack; } else { drawCmdContext.Color = lineColor; } @@ -1114,39 +2408,132 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) InfoSubstituteControls( NULL, NULL ); infoSubst = FALSE; } + /* no break */ case wActionLDrag: ParamLoadData( &drawPG ); + /* no break */ case wActionMove: - case wActionLUp: case wActionRDown: case wActionRDrag: - case wActionRUp: - case wActionText: - case C_CMDMENU: if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - if (!((MyGetKeyState() & WKEY_SHIFT) != 0)) { + if (!((MyGetKeyState() & WKEY_ALT) != magneticSnap)) { SnapPos( &pos ); } - return DrawGeomMouse( action, pos, &drawCmdContext ); + return DrawGeomMouse( action, pos, &drawCmdContext); + case wActionLUp: + case wActionRUp: + if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); + //if (!((MyGetKeyState() & WKEY_SHIFT) != 0)) { + // SnapPos( &pos ); Remove Snap at end of action - it will have been imposed in Geom if needed + //} + int rc = DrawGeomMouse( action, pos, &drawCmdContext); + // Put up text entry boxes ready for updates if the result was continue + if (rc == C_CONTINUE) { + switch( drawCmdContext.Op ) { + case OP_CIRCLE1: + case OP_CIRCLE2: + case OP_CIRCLE3: + case OP_FILLCIRCLE1: + case OP_FILLCIRCLE2: + case OP_FILLCIRCLE3: + controls[0] = drawRadiusPD.control; + controls[1] = NULL; + labels[0] = N_("Radius"); + ParamLoadControls( &drawPG ); + InfoSubstituteControls( controls, labels ); + drawRadiusPD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + case OP_CURVE1: + case OP_CURVE2: + case OP_CURVE3: + case OP_CURVE4: + if (drawCmdContext.ArcData.type == curveTypeCurve) { + controls[0] = drawRadiusPD.control; + controls[1] = drawAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Radius"); + labels[1] = N_("Arc Angle"); + } else { + controls[0] = drawLengthPD.control; + controls[1] = drawAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Length"); + labels[1] = N_("Angle"); + } + ParamLoadControls( &drawPG ); + InfoSubstituteControls( controls, labels ); + drawLengthPD.option &= ~PDO_NORECORD; + drawRadiusPD.option &= ~PDO_NORECORD; + drawAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + case OP_LINE: + case OP_BENCH: + case OP_TBLEDGE: + case OP_POLY: + case OP_FILLPOLY: + case OP_POLYLINE: + controls[0] = drawLengthPD.control; + controls[1] = drawAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Seg Length"); + if (drawCmdContext.Op == OP_LINE || drawCmdContext.Op == OP_BENCH || drawCmdContext.Op == OP_TBLEDGE) + labels[1] = N_("Angle"); + else if (drawCmdContext.index > 0 ) + labels[1] = N_("Rel Angle"); + else + labels[1] = N_("Angle"); + ParamLoadControls( &drawPG ); + InfoSubstituteControls( controls, labels ); + drawLengthPD.option &= ~PDO_NORECORD; + drawAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + case OP_BOX: + case OP_FILLBOX: + controls[0] = drawLengthPD.control; + controls[1] = drawWidthPD.control; + controls[2] = NULL; + labels[0] = N_("Length"); + labels[1] = N_("Width"); + ParamLoadControls( &drawPG ); + InfoSubstituteControls( controls, labels ); + drawLengthPD.option &= ~PDO_NORECORD; + drawWidthPD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + default: + break; + } + } + return rc; case C_CANCEL: InfoSubstituteControls( NULL, NULL ); if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - return DrawGeomMouse( action, pos, &drawCmdContext ); - + return DrawGeomMouse( action, pos, &drawCmdContext); + case C_TEXT: + if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(action, 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 ); + 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 ); + 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 ); + return DrawGeomMouse( action, pos, &drawCmdContext); + + case C_CMDMENU: + if (drawCmdContext.Op == OP_BEZLIN) return C_CONTINUE; + return DrawGeomMouse( action, pos, &drawCmdContext); default: return C_CONTINUE; @@ -1172,6 +2559,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) #include "bitmaps/dpoly.xpm" #include "bitmaps/dfilpoly.xpm" #include "bitmaps/dbezier.xpm" +#include "bitmaps/dpolyline.xpm" typedef struct { char **xpm; @@ -1195,16 +2583,18 @@ static drawData_t dcurveCmds[] = { { 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 }, - { dcircle3_xpm, OP_CIRCLE2, N_("Circle Center"), N_("Draw Circle from Center"), "cmdDrawCircleCenter", ACCL_DRAWCIRCLE3 }, + { dcircle3_xpm, OP_CIRCLE3, N_("Circle Tangent"), N_("Draw Circle from Tangent"), "cmdDrawCircleTangent", ACCL_DRAWCIRCLE2 }, + { dcircle2_xpm, OP_CIRCLE2, N_("Circle Center"), N_("Draw Circle from Center"), "cmdDrawCircleCenter", ACCL_DRAWCIRCLE3 }, /*{ dflcrcl1_xpm, OP_FILLCIRCLE1, "Circle Filled Fixed Radius", "Draw Fixed Radius Filled Circle", "cmdDrawFilledCircleFixedRadius", ACCL_DRAWFILLCIRCLE1 },*/ - { dflcrcl2_xpm, OP_FILLCIRCLE3, N_("Circle Filled Tangent"), N_("Draw Filled Circle from Tangent"), "cmdDrawFilledCircleTangent", ACCL_DRAWFILLCIRCLE2 }, - { dflcrcl3_xpm, OP_FILLCIRCLE2, N_("Circle Filled Center"), N_("Draw Filled Circle from Center"), "cmdDrawFilledCircleCenter", ACCL_DRAWFILLCIRCLE3 } }; + { dflcrcl3_xpm, OP_FILLCIRCLE3, N_("Circle Filled Tangent"), N_("Draw Filled Circle from Tangent"), "cmdDrawFilledCircleTangent", ACCL_DRAWFILLCIRCLE2 }, + { dflcrcl2_xpm, OP_FILLCIRCLE2, N_("Circle Filled Center"), N_("Draw Filled Circle from Center"), "cmdDrawFilledCircleCenter", ACCL_DRAWFILLCIRCLE3 } }; static drawData_t dshapeCmds[] = { { dbox_xpm, OP_BOX, N_("Box"), N_("Draw Box"), "cmdDrawBox", ACCL_DRAWBOX }, { dfilbox_xpm, OP_FILLBOX, N_("Filled Box"), N_("Draw Filled Box"), "cmdDrawFilledBox", ACCL_DRAWFILLBOX }, - { dpoly_xpm, OP_POLY, N_("Poly Line"), N_("Draw Polyline"), "cmdDrawPolyline", ACCL_DRAWPOLYLINE }, - { dfilpoly_xpm, OP_FILLPOLY, N_("Polygon"), N_("Draw Polygon"), "cmdDrawPolygon", ACCL_DRAWPOLYGON } }; + { dpoly_xpm, OP_POLY, N_("Polygon"), N_("Draw Polygon"), "cmdDrawPolygon", ACCL_DRAWPOLY }, + { dfilpoly_xpm, OP_FILLPOLY, N_("Filled Polygon"), N_("Draw Filled Polygon"), "cmdDrawFilledPolygon", ACCL_DRAWFILLPOLYGON }, + { dpolyline_xpm, OP_POLYLINE, N_("PolyLine"), N_("Draw PolyLine"), "cmdDrawPolyline", ACCL_DRAWPOLYLINE }, +}; typedef struct { char * helpKey; @@ -1223,7 +2613,7 @@ static drawStuff_t drawStuff[4] = { { "cmdDrawLineSetCmd", N_("Straight Objects"), N_("Draw Straight Objects"), 4, dlineCmds }, { "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} }; + { "cmdDrawShapeSetCmd", N_("Shapes"), N_("Draw Shapes"), 5, dshapeCmds} }; static void ChangeDraw( long changes ) @@ -1247,13 +2637,58 @@ 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==3) { + if (drawCmdContext.Op == OP_BEZLIN) { + if ( (inx == 0 && pg->paramPtr[inx].valueP == &drawCmdContext.line_Width) || + (inx == 1 && pg->paramPtr[inx].valueP == &lineColor)) + { + lineWidth = drawCmdContext.line_Width; + UpdateParms(lineColor, lineWidth); + } + } + } + if (inx >=6 ) { + if (drawCmdContext.Op == OP_CIRCLE1 || + drawCmdContext.Op == OP_FILLCIRCLE1 || + drawCmdContext.Op == OP_CIRCLE2 || + drawCmdContext.Op == OP_FILLCIRCLE2 || + drawCmdContext.Op == OP_CIRCLE3 || + drawCmdContext.Op == OP_FILLCIRCLE3) { + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + if (drawCmdContext.Op == OP_CURVE1 || + drawCmdContext.Op == OP_CURVE2 || + drawCmdContext.Op == OP_CURVE3 || + drawCmdContext.Op == OP_CURVE4 ) { + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + if (drawCmdContext.Op == OP_LINE || + drawCmdContext.Op == OP_BENCH|| + drawCmdContext.Op == OP_TBLEDGE) { + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + + if (drawCmdContext.Op == OP_BOX || + drawCmdContext.Op == OP_FILLBOX ){ + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + + if (drawCmdContext.Op == OP_POLY || + drawCmdContext.Op == OP_FILLPOLY || + drawCmdContext.Op == OP_POLYLINE) { + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + ParamLoadControl(&drawPG,drawAngleInx); //Force Angle change out + //if (pg->paramPtr[inx].enter_pressed) { + // coOrd pos = zero; + // DrawGeomMouse((0x0D<<8)|(C_TEXT&0xFF),pos,&drawCmdContext); + // CmdDraw(C_START,pos); + //} } if ( inx >= 0 && pg->paramPtr[inx].valueP == &benchChoice ) @@ -1272,13 +2707,15 @@ EXPORT void InitCmdDraw( wMenu_p menu ) benchColor = wDrawFindColor( wRGB(255,192,0) ); ParamCreateControls( &drawPG, DrawDlgUpdate ); + ParamCreateControls( &drawModPG, DrawModDlgUpdate) ; + for ( inx1=0; inx1<4; inx1++ ) { dsp = &drawStuff[inx1]; ButtonGroupBegin( _(dsp->menuTitle), dsp->helpKey, _(dsp->stickyLabel) ); for ( inx2=0; inx2<dsp->cnt; inx2++ ) { ddp = &dsp->data[inx2]; icon = wIconCreatePixMap( ddp->xpm ); - AddMenuButton( menu, CmdDraw, ddp->helpKey, _(ddp->cmdName), icon, LEVEL0_50, IC_STICKY|IC_POPUP2, ddp->acclKey, (void *)(intptr_t)ddp->OP ); + AddMenuButton( menu, CmdDraw, ddp->helpKey, _(ddp->cmdName), icon, LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ddp->acclKey, (void *)(intptr_t)ddp->OP ); } ButtonGroupEnd(); } @@ -1327,7 +2764,8 @@ EXPORT track_p NewText( ANGLE_T angle, char * text, CSIZE_T textSize, - wDrawColor color ) + wDrawColor color, + BOOL_T boxed) { trkSeg_t tempSeg; track_p trk; @@ -1339,6 +2777,7 @@ EXPORT track_p NewText( tempSeg.u.t.fontP = NULL; tempSeg.u.t.fontSize = textSize; tempSeg.u.t.string = MyStrdup( text ); + tempSeg.u.t.boxed = boxed; trk = MakeDrawFromSeg1( index, pos, angle, &tempSeg ); return trk; } @@ -1364,20 +2803,127 @@ EXPORT BOOL_T ReadText( char * line ) return FALSE; } - char * old = text; - text = ConvertFromEscapedText(text); - MyFree(old); - - trk = NewText( index, pos, angle, text, textSize, color ); + trk = NewText( index, pos, angle, text, textSize, color, FALSE ); SetTrkLayer( trk, layer ); MyFree(text); return TRUE; } +void MenuMode(int mode) { + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + if (mode == 1) { + DrawGeomOriginMove(C_START,zero,&drawModCmdContext); + InfoMessage("Origin Mode"); + } else { + DrawGeomModify(C_START,zero,&drawModCmdContext); + InfoMessage("Points Mode"); + } +} + +void MenuEnter(int key) { + int action; + action = C_TEXT; + action |= key<<8; + if (drawModCmdContext.rotate_state) + DrawGeomOriginMove(action,zero,&drawModCmdContext); + else + DrawGeomModify(action,zero,&drawModCmdContext); +} + +void MenuLine(int key) { + struct extraData * xx = GetTrkExtraData(drawModCmdContext.trk); + if ( drawModCmdContext.type==SEG_STRLIN || drawModCmdContext.type==SEG_CRVLIN || drawModCmdContext.type==SEG_POLY ) { + switch(key) { + case '0': + xx->lineType = DRAWLINESOLID; + break; + case '1': + xx->lineType = DRAWLINEDASH; + break; + case '2': + xx->lineType = DRAWLINEDOT; + break; + case '3': + xx->lineType = DRAWLINEDASHDOT; + break; + case '4': + xx->lineType = DRAWLINEDASHDOTDOT; + break; + case '5': + xx->lineType = DRAWLINECENTER; + break; + case '6': + xx->lineType = DRAWLINEPHANTOM; + break; + } + MainRedraw(); // MenuLine + } +} + +EXPORT void SetLineType( track_p trk, int width ) { + if (QueryTrack(trk, Q_IS_DRAW)) { + struct extraData * xx = GetTrkExtraData(trk); + if ( xx->segs[0].type==SEG_STRLIN || xx->segs[0].type==SEG_CRVLIN || xx->segs[0].type==SEG_POLY) { + switch(width) { + case 0: + xx->lineType = DRAWLINESOLID; + break; + case 1: + xx->lineType = DRAWLINEDASH; + break; + case 2: + xx->lineType = DRAWLINEDOT; + break; + case 3: + xx->lineType = DRAWLINEDASHDOT; + break; + case 4: + xx->lineType = DRAWLINEDASHDOTDOT; + break; + case 5: + xx->lineType = DRAWLINECENTER; + break; + case 6: + xx->lineType = DRAWLINEPHANTOM; + break; + } + } + } +} EXPORT void InitTrkDraw( void ) { T_DRAW = InitObject( &drawCmds ); AddParam( "TABLEEDGE", ReadTableEdge ); AddParam( "TEXT", ReadText ); + + drawModDelMI = MenuRegister( "Modify Draw Edit Menu" ); + drawModClose = wMenuPushCreate( drawModDelMI, "", _("Close Polygon - 'g'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'g'); + drawModOpen = wMenuPushCreate( drawModDelMI, "", _("Make PolyLine - 'l'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'l'); + drawModFill = wMenuPushCreate( drawModDelMI, "", _("Fill Polygon - 'f'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'f'); + drawModEmpty = wMenuPushCreate( drawModDelMI, "", _("Empty Polygon - 'u'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'u'); + wMenuSeparatorCreate( drawModDelMI ); + drawModPointsMode = wMenuPushCreate( drawModDelMI, "", _("Points Mode - 'p'"), 0, (wMenuCallBack_p)MenuMode, (void*) 0 ); + drawModDel = wMenuPushCreate( drawModDelMI, "", _("Delete Selected Point - 'Del'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 127 ); + drawModVertex = wMenuPushCreate( drawModDelMI, "", _("Vertex Point - 'v'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'v' ); + drawModRound = wMenuPushCreate( drawModDelMI, "", _("Round Corner - 'r'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'r' ); + drawModSmooth = wMenuPushCreate( drawModDelMI, "", _("Smooth Corner - 's'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 's' ); + wMenuSeparatorCreate( drawModDelMI ); + drawModLinMI = wMenuMenuCreate( drawModDelMI, "", _("LineType...") ); + drawModSolid = wMenuPushCreate( drawModLinMI, "", _("Solid Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '0' ); + drawModDot = wMenuPushCreate( drawModLinMI, "", _("Dashed Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '1' ); + drawModDash = wMenuPushCreate( drawModLinMI, "", _("Dotted Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '2' ); + drawModDashDot = wMenuPushCreate( drawModLinMI, "", _("Dash-Dot Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '3' ); + drawModDashDotDot = wMenuPushCreate( drawModLinMI, "", _("Dash-Dot-Dot Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '4' ); + drawModCenterDot = wMenuPushCreate( drawModLinMI, "", _("Center-Dot Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '5' ); + drawModPhantom = wMenuPushCreate( drawModLinMI, "", _("Phantom-Dot Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '6' ); + wMenuSeparatorCreate( drawModDelMI ); + drawModriginMode = wMenuPushCreate( drawModDelMI, "", _("Origin Mode - 'o'"), 0, (wMenuCallBack_p)MenuMode, (void*) 1 ); + drawModOrigin = wMenuPushCreate( drawModDelMI, "", _("Reset Origin - '0'"), 0, (wMenuCallBack_p)MenuEnter, (void*) '0' ); + drawModLast = wMenuPushCreate( drawModDelMI, "", _("Origin to Selected - 'l'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'l' ); + drawModCenter = wMenuPushCreate( drawModDelMI, "", _("Origin to Middle - 'm'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'm'); + } diff --git a/app/bin/celev.c b/app/bin/celev.c index 5a63a3a..1da4b22 100644 --- a/app/bin/celev.c +++ b/app/bin/celev.c @@ -29,6 +29,8 @@ #include "i18n.h" #include "param.h" #include "track.h" +#include "ccurve.h" +#include "utility.h" static wWin_p elevW; @@ -58,6 +60,71 @@ static paramData_t elevationPLs[] = { { PD_STRING, elevStationV, "station", PDO_DLGUNDERCMDBUTT|PDO_STRINGLIMITLENGTH, (void*)200, NULL, 0, 0, sizeof(elevStationV)} }; static paramGroup_t elevationPG = { "elev", 0, elevationPLs, sizeof elevationPLs/sizeof elevationPLs[0] }; +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) + +static void CreateSquareAnchor(coOrd p) { + DIST_T d = tempD.scale*0.25; + int i = anchors_da.cnt; + DYNARR_SET(trkSeg_t,anchors_da,i+4); + for (int j =0; j<4;j++) { + anchors(i+j).type = SEG_STRLIN; + anchors(i+j).color = wDrawColorBlue; + anchors(i+j).width = 0; + } + anchors(i).u.l.pos[0].x = anchors(i+2).u.l.pos[1].x = + anchors(i+3).u.l.pos[0].x = anchors(i+3).u.l.pos[1].x = p.x-d/2; + + anchors(i).u.l.pos[0].y = anchors(i).u.l.pos[1].y = + anchors(i+1).u.l.pos[0].y = anchors(i+3).u.l.pos[1].y = p.y-d/2; + + anchors(i).u.l.pos[1].x = + anchors(i+1).u.l.pos[0].x = anchors(i+1).u.l.pos[1].x = + anchors(i+2).u.l.pos[0].x = p.x+d/2; + + anchors(i+1).u.l.pos[1].y = + anchors(i+2).u.l.pos[0].y = anchors(i+2).u.l.pos[1].y = + anchors(i+3).u.l.pos[0].y = p.y+d/2; +} + +static void CreateEndAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} + +static void CreateSplitAnchor(coOrd pos, track_p t) { + DIST_T d = tempD.scale*0.1; + DIST_T w = tempD.scale/tempD.dpi*4; + int i; + ANGLE_T a = NormalizeAngle(GetAngleAtPoint(t,pos,NULL,NULL)+90.0); + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).color = wDrawColorBlue; + Translate(&anchors(i).u.l.pos[0],pos,a,GetTrkGauge(t)); + Translate(&anchors(i).u.l.pos[1],pos,a,-GetTrkGauge(t)); + anchors(i).width = w; + +} + + +void static CreateMoveAnchor(coOrd pos) { + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pos,0,TRUE,wDrawColorBlue); + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pos,90,TRUE,wDrawColorBlue); + DYNARR_APPEND(trkSeg_t,anchors_da,1); + CreateSquareAnchor(pos); +} static void LayoutElevW( paramData_t * pd, @@ -97,59 +164,16 @@ static int GetElevMode( void ) } -#ifdef LATER -static void DoElevRadio( long mode, void * context ) -{ - if ( mode < 0 || mode >= 7 ) - return; -#ifdef ELEVM - ParamLoadMessage( elevMessageM, "" ); -#endif - ParamControlActive( &elevationPG, I_HEIGHT, FALSE ); - ParamControlActive( &elevationPG, I_STATION, FALSE ); - switch ( mode ) { - case 0: - break; - case 1: - case 2: - ParamControlActive( &elevationPG, I_HEIGHT, TRUE ); - break; - case 3: - case 4: -#ifdef OLDELEV - if ( !( (rc0 == FDE_DEF && rc1 == FDE_DEF) || - (rc0 == FDE_DEF && rc1 == FDE_END) || - (rc0 == FDE_END && rc1 == FDE_DEF) ) ) { - ParamLoadMessage( &elevationPG, I_MSG, _("There are no reachable Defined Elevations") ); - ParamLoadControl( &elevationPG, I_MODE ); - return; - } -#endif - break; - case 5: - wControlActive( (wControl_p)elevStationS, TRUE ); - break; - } - elevModeV = mode; - DoElevUpdate( NULL, 1, NULL ); -} -#endif - static void DoElevUpdate( paramGroup_p pg, int inx, void * valueP ) { int oldMode, newMode; - coOrd pos; DIST_T elevNewValue, elevOldValue, diff; - DIST_T radius; if ( inx == 0 ) { long mode = *(long*)valueP; if ( mode < 0 || mode >= 7 ) return; -#ifdef ELEVM - ParamLoadMessage( elevMessageM, "" ); -#endif ParamControlActive( &elevationPG, I_HEIGHT, FALSE ); ParamControlActive( &elevationPG, I_STATION, FALSE ); switch ( mode ) { @@ -161,15 +185,6 @@ static void DoElevUpdate( paramGroup_p pg, int inx, void * valueP ) break; case 3: case 4: -#ifdef OLDELEV - if ( !( (rc0 == FDE_DEF && rc1 == FDE_DEF) || - (rc0 == FDE_DEF && rc1 == FDE_END) || - (rc0 == FDE_END && rc1 == FDE_DEF) ) ) { - ParamLoadMessage( &elevationPG, I_MSG, _("There are no reachable Defined Elevations") ); - ParamLoadControl( &elevationPG, I_MODE ); - return; - } -#endif break; case 5: ParamControlActive( &elevationPG, I_STATION, TRUE ); @@ -204,27 +219,14 @@ static void DoElevUpdate( paramGroup_p pg, int inx, void * valueP ) UndoStart( _("Set Elevation"), "Set Elevation" ); elevUndo = TRUE; } - pos = GetTrkEndPos( elevTrk, elevEp ); - radius = 0.05*mainD.scale; - if ( radius < trackGauge/2.0 ) - radius = trackGauge/2.0; - if ( (oldMode&ELEV_MASK)==ELEV_DEF || (oldMode&ELEV_MASK)==ELEV_IGNORE ) - DrawFillCircle( &tempD, pos, radius, - ((oldMode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore)); - HilightSelectedEndPt(FALSE, elevTrk, elevEp); UpdateTrkEndElev( elevTrk, elevEp, newMode, elevNewValue, elevStationV ); - HilightSelectedEndPt(TRUE, elevTrk, elevEp); - if ( (newMode&ELEV_MASK)==ELEV_DEF || (newMode&ELEV_MASK)==ELEV_IGNORE ) - DrawFillCircle( &tempD, pos, radius, - ((newMode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore)); + TempRedraw(); // DoElevUpdate } static void DoElevDone( void * arg ) { DoElevUpdate( NULL, 1, NULL ); - HilightElevations( FALSE ); - HilightSelectedEndPt( FALSE, elevTrk, elevEp ); elevTrk = NULL; Reset(); } @@ -250,7 +252,6 @@ static void ElevSelect( track_p trk, EPINX_T ep ) elevOldValue = 0.0; elevHeightV = 0.0; elevStationV[0] = 0; - HilightSelectedEndPt(FALSE, elevTrk, elevEp); elevTrk = trk; elevEp = ep; mode = GetTrkEndElevUnmaskedMode( trk, ep ); @@ -294,89 +295,26 @@ static void ElevSelect( track_p trk, EPINX_T ep ) } elevModeV = radio; ParamLoadControl( &elevationPG, I_MODE ); -#ifdef OLDELEV -if (oldElevationEvaluation) { - int dir; - ANGLE_T a; - int rc0, rc1; - DIST_T elev0, elev1, dist0, dist1; - a = GetTrkEndAngle( trk, ep ); - dir = ( a > 270 || a < 90 ); - rc0 = FindDefinedElev( trk, ep, dir, FALSE, &elev0, &dist0 ); - rc1 = FindDefinedElev( trk, ep, 1-dir, FALSE, &elev1, &dist1 ); - if ( rc0 == FDE_DEF ) { - sprintf( message, _("Elev = %s"), FormatDistance(elev0) ); - ParamLoadMessage( elev1ElevM, message ); - sprintf( message, _("Dist = %s"), FormatDistance(dist0) ); - ParamLoadMessage( elev1DistM, message ); -#ifdef LATER - if (dist0 > 0.1) - sprintf( message, "%0.1f%%", elev0/dist0 ); - else - sprintf( message, _("Undefined") ); - ParamLoadMessage( elev1GradeM, message ); -#endif - } else { - ParamLoadMessage( elev1ElevM, "" ); - ParamLoadMessage( elev1DistM, "" ); - /*ParamLoadMessage( elev1GradeM, "" );*/ - } - if ( rc1 == FDE_DEF ) { - sprintf( message, _("Elev = %s"), FormatDistance(elev1) ); - ParamLoadMessage( elev2ElevM, message ); - sprintf( message, _("Dist = %s"), FormatDistance(dist1) ); - ParamLoadMessage( elev2DistM, message ); -#ifdef LATER - if (dist1 > 0.1) - sprintf( message, "%0.1f%%", elev1/dist1 ); - else - sprintf( message, _("Undefined") ); - ParamLoadMessage( elev2GradeM, message ); -#endif - } else { - ParamLoadMessage( elev2ElevM, "" ); - ParamLoadMessage( elev2DistM, "" ); - /*ParamLoadMessage( elev2GradeM, "" );*/ - } + gradeOk = ComputeElev( trk, ep, FALSE, &elevX, &grade, TRUE ); computedOk = TRUE; - if (rc0 == FDE_DEF && rc1 == FDE_DEF) { - grade = (elev1-elev0)/(dist0+dist1); - elevX = elev0 + grade*dist0; - } else if (rc0 == FDE_DEF && rc1 == FDE_END) { - grade = 0.0; - elevX = elev0; - } else if (rc0 == FDE_END && rc1 == FDE_DEF) { - elevX = elev1; - grade = 0.0; - } else { - gradeOk = FALSE; - computedOk = FALSE; - } -} else { -#endif - gradeOk = ComputeElev( trk, ep, FALSE, &elevX, &grade ); - computedOk = TRUE; -#ifdef OLDELEV -} -#endif if (oldElevationEvaluation || computedOk) { - sprintf( message, "%0.2f%s", PutDim( elevX ), (units==UNITS_METRIC?"cm":"\"") ); + sprintf( message, "%0.2f%s", round(PutDim( elevX )*100.0)/100.0, (units==UNITS_METRIC?"cm":"\"") ); ParamLoadMessage( &elevationPG, I_COMPUTED, message ); if (gradeOk) { - sprintf( message, "%0.1f%%", fabs(grade*100) ); + sprintf( message, "%0.1f%%", fabs(round(grade*1000.0)/10.0) ); } else { if ( EndPtIsDefinedElev(trk,ep) ) { elev = GetElevation(trk); dist = GetTrkLength(trk,ep,-1); if (dist>0.1) - sprintf( message, "%0.1f%%", fabs((elev-elevX)/dist)*100.0 ); + sprintf( message, "%0.1f%%", fabs(round((elev-elevX)/dist)*1000.0)/10.0 ); else sprintf( message, _("Undefined") ); if ( (trk1=GetTrkEndTrk(trk,ep)) && (ep1=GetEndPtConnectedToMe(trk1,trk))>=0 ) { elev = GetElevation(trk1); dist = GetTrkLength(trk1,ep1,-1); if (dist>0.1) - sprintf( message+strlen(message), " - %0.1f%%", fabs((elev-elevX)/dist)*100.0 ); + sprintf( message+strlen(message), " - %0.1f%%", fabs(round((elev-elevX)/dist)*1000.0)/10.0 ); else sprintf( message+strlen(message), " - %s", _("Undefined") ); } @@ -390,7 +328,41 @@ if (oldElevationEvaluation) { ParamLoadControl( &elevationPG, I_HEIGHT ); } } - HilightSelectedEndPt(TRUE, elevTrk, elevEp); + wShow(elevW); +} + +static BOOL_T GetPointElev(track_p trk, coOrd pos, DIST_T * height) { + DIST_T len, len1, elev0, elev1, dist0, dist1; + if ( IsTrack( trk ) && GetTrkEndPtCnt(trk) == 2 ) { + dist0 = FindDistance(pos,GetTrkEndPos(trk,0)); + dist1 = FindDistance(pos,GetTrkEndPos(trk,1)); + if (EndPtIsDefinedElev(trk,0)) + elev0 = GetTrkEndElevHeight(trk,0); + else { + if (!GetTrkEndElevCachedHeight(trk,0,&elev0,&len)) { + if (GetTrkLength( trk, 0, 1 )<0.1) return FALSE; + ComputeElev( trk, 0, FALSE, &elev0, NULL, TRUE ); + } + } + if (EndPtIsDefinedElev(trk,1)) + elev1 = GetTrkEndElevHeight(trk,1); + else { + if (!GetTrkEndElevCachedHeight(trk,1,&elev1,&len1)) { + if (GetTrkLength( trk, 0, 1 )<0.1) return FALSE; + ComputeElev( trk, 0, FALSE, &elev0, NULL, TRUE ); + } + } + if (dist1+dist0 < 0.1) { + *height = elev0; + return TRUE; + } + *height = ((elev1-elev0)*(dist0/(dist0+dist1)))+elev0; + return TRUE; + } else if (GetTrkEndPtCnt(trk) == 1 && GetTrkEndElevCachedHeight(trk,0,&elev0,&len)) { + *height = elev0; + return TRUE; + } + return FALSE; } @@ -403,59 +375,129 @@ static STATUS_T CmdElevation( wAction_t action, coOrd pos ) switch (action) { case C_START: if ( elevW == NULL ) - elevW = ParamCreateDialog( &elevationPG, MakeWindowTitle(_("Elevation")), _("Done"), DoElevDone, NULL, TRUE, LayoutElevW, 0, DoElevUpdate ); + elevW = ParamCreateDialog( &elevationPG, MakeWindowTitle(_("Elevation")), _("Done"), DoElevDone, wHide, TRUE, LayoutElevW, 0, DoElevUpdate ); elevModeV = 0; elevHeightV = 0.0; elevStationV[0] = 0; ParamLoadControls( &elevationPG ); ParamGroupRecord( &elevationPG ); - wShow( elevW ); + //wShow( elevW ); ParamControlActive( &elevationPG, I_MODE, FALSE ); ParamControlActive( &elevationPG, I_HEIGHT, FALSE ); ParamControlActive( &elevationPG, I_STATION, FALSE ); ParamLoadMessage( &elevationPG, I_COMPUTED, "" ); ParamLoadMessage( &elevationPG, I_GRADE, "" ); - InfoMessage( _("Select End-Point") ); - HilightElevations( TRUE ); + InfoMessage( _("Click on end, +Shift to split, +Ctrl to move description") ); elevTrk = NULL; elevUndo = FALSE; + CmdMoveDescription( action, pos ); + TempRedraw(); // CmdElevation C_START return C_CONTINUE; - case C_RDOWN: - case C_RMOVE: - case C_RUP: - CmdMoveDescription( action-C_RDOWN+C_DOWN, pos ); - return C_CONTINUE; - case C_LCLICK: - if ((trk0 = OnTrack( &pos, TRUE, TRUE )) == NULL) { + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if (MyGetKeyState()&WKEY_CTRL) { + commandContext = (void*) 1; //Just end points + CmdMoveDescription( action, pos ); return C_CONTINUE; } - if ( (MyGetKeyState()&WKEY_SHIFT) ) { - ep0 = PickEndPoint( pos, trk0 ); - UndoStart( _("Split Track"), "SplitTrack( T%d[%d] )", GetTrkIndex(trk0), ep0 ); - oldTrackCount = trackCount; - if (!SplitTrack( trk0, pos, ep0, &trk1, FALSE )) + BOOL_T xing = FALSE; + coOrd p0 = pos, p2=pos; + if ((trk0 = OnTrack2(&p0,FALSE, TRUE, FALSE, NULL)) != NULL) { + EPINX_T ep0 = 0, ep1 = 1; + DIST_T elev0, elev1; + if (GetTrkEndPtCnt(trk0) == 2) { + if (!GetPointElev(trk0,p0,&elev0)) { + InfoMessage( _("Move to end or track crossing +Shift to split") ); + return C_CONTINUE; + } + } else { + InfoMessage( _("Move to end or track crossing") ); return C_CONTINUE; - ElevSelect( trk0, ep0 ); - UndoEnd(); - elevUndo = FALSE; - } else { - ep0 = PickEndPoint( pos, trk0 ); - ElevSelect( trk0, ep0 ); + } + if ((trk1 = OnTrack2(&p2,FALSE, TRUE, FALSE, trk0)) != NULL) { + if (IsClose(FindDistance(p0,p2))) { + if (GetEndPtConnectedToMe(trk0,trk1) == -1) { //Not simply connected to each other!!! + if (GetTrkEndPtCnt(trk1) == 2) { + if (GetPointElev(trk1,p2,&elev1)) { + if (MyGetKeyState()&WKEY_SHIFT) { + InfoMessage (_("Crossing - First %0.3f, Second %0.3f, Clearance %0.3f - Click to Split"), PutDim(elev0), PutDim(elev1), PutDim(fabs(elev0-elev1))); + } else + InfoMessage (_("Crossing - First %0.3f, Second %0.3f, Clearance %0.3f"), PutDim(elev0), PutDim(elev1), PutDim(fabs(elev0-elev1))); + } + CreateSquareAnchor(p2); + return C_CONTINUE; + } + } + } + } + if ((ep0 = PickEndPoint( p0, trk0 )) != -1) { + if (IsClose(FindDistance(GetTrkEndPos(trk0,ep0),pos))) { + CreateEndAnchor(GetTrkEndPos(trk0,ep0),FALSE); + InfoMessage (_("Track End elevation %0.3f"), PutDim(elev0)); + } else if ((MyGetKeyState()&WKEY_SHIFT) && QueryTrack(trk0,Q_MODIFY_CAN_SPLIT) + && !(QueryTrack(trk0,Q_IS_TURNOUT))) { + InfoMessage( _("Click to split here - elevation %0.3f"), PutDim(elev0)); + CreateSplitAnchor(p0,trk0); + } else { + InfoMessage( _("Track Point elevation %0.3f"), PutDim(elev0)); + CreateEndAnchor(p0,TRUE); + } + } else InfoMessage( _("Click on end, +Shift to split, +Ctrl to move description") ); + } else + InfoMessage( _("Click on end, +Shift to split, +Ctrl to move description") ); + return C_CONTINUE; + case C_DOWN: + case C_MOVE: + case C_UP: + if (MyGetKeyState()&WKEY_CTRL) { + commandContext = (void*) 1; //Just end points + CmdMoveDescription( action, pos ); + DYNARR_RESET(trkSeg_t,anchors_da); + elevTrk = NULL; return C_CONTINUE; } + /*no break*/ + case C_LCLICK: + ; + p0= pos; + if ((trk0 = OnTrack( &p0, TRUE, TRUE )) == NULL) { + wHide(elevW); + elevTrk = NULL; + InfoMessage( _("Click on end, +Shift to split, +Ctrl to move description") ); + } else { + ep0 = PickEndPoint( p0, trk0 ); + if (IsClose(FindDistance(GetTrkEndPos(trk0,ep0),pos))) { + InfoMessage( _("Point selected!") ); + ElevSelect( trk0, ep0 ); + } else if ( (MyGetKeyState()&WKEY_SHIFT) ) { + UndoStart( _("Split track"), "SplitTrack( T%d[%d] )", GetTrkIndex(trk0), ep0 ); + oldTrackCount = trackCount; + if (!QueryTrack(trk0,Q_IS_TURNOUT) && + !SplitTrack( trk0, p0, ep0, &trk1, FALSE )) + return C_CONTINUE; + InfoMessage( _("Track split!") ); + ElevSelect( trk0, ep0 ); + UndoEnd(); + elevUndo = FALSE; + } + } + DYNARR_RESET(trkSeg_t,anchors_da); return C_CONTINUE; case C_OK: DoElevDone(NULL); + InfoMessage( "" ); return C_TERMINATE; case C_CANCEL: - HilightElevations( FALSE ); - HilightSelectedEndPt( FALSE, elevTrk, elevEp ); elevTrk = NULL; wHide( elevW ); + InfoMessage( "" ); return C_TERMINATE; case C_REDRAW: DoElevHilight( NULL ); HilightSelectedEndPt( TRUE, elevTrk, elevEp ); + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + CmdMoveDescription( action, pos ); return C_CONTINUE; } return C_CONTINUE; @@ -469,6 +511,6 @@ static STATUS_T CmdElevation( wAction_t action, coOrd pos ) EXPORT void InitCmdElevation( wMenu_p menu ) { ParamRegister( &elevationPG ); - AddMenuButton( menu, CmdElevation, "cmdElevation", _("Elevation"), wIconCreatePixMap(elev_xpm), LEVEL0_50, IC_POPUP|IC_LCLICK, ACCL_ELEVATION, NULL ); + AddMenuButton( menu, CmdElevation, "cmdElevation", _("Elevation"), wIconCreatePixMap(elev_xpm), LEVEL0_50, IC_POPUP|IC_LCLICK|IC_RCLICK|IC_WANT_MOVE, ACCL_ELEVATION, NULL ); } diff --git a/app/bin/cgroup.c b/app/bin/cgroup.c index 0094564..1183e76 100644 --- a/app/bin/cgroup.c +++ b/app/bin/cgroup.c @@ -472,11 +472,12 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep Rotate( &orig, zero, xx->angle ); orig.x = xx->orig.x - orig.x; orig.y = xx->orig.y - orig.y; - trk1 = NewCompound( T_TURNOUT, 0, orig, xx->angle, xx->title, tempEndPts_da.cnt-epCnt1, &tempEndPts(epCnt1), pathPtr_da.cnt, &pathPtr(0), tempSegs_da.cnt, &tempSegs(0) ); + trk1 = NewCompound( T_TURNOUT, 0, orig, xx->angle, xx->title, tempEndPts_da.cnt-epCnt1, &tempEndPts(epCnt1), NULL, pathPtr_da.cnt, &pathPtr(0), tempSegs_da.cnt, &tempSegs(0) ); xx1 = GetTrkExtraData(trk1); xx1->ungrouped = TRUE; SetTrkVisible( trk1, TRUE ); + SetTrkNoTies( trk1, FALSE ); SetTrkBits( trk1, TB_SELECTED ); for ( segInx=0; segInx<segCnt; segInx++ ) { if ( refCount(segInx) == inx ) { @@ -608,19 +609,25 @@ EXPORT void DoUngroup( void ) static drawCmd_t groupD = { - NULL, &tempSegDrawFuncs, DC_GROUP, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix }; + NULL, &tempSegDrawFuncs, DC_SEGTRACK, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix }; static long groupSegCnt; static long groupReplace; +static double groupOriginX; +static double groupOriginY; char * groupReplaceLabels[] = { N_("Replace with new group?"), NULL }; static wWin_p groupW; static paramIntegerRange_t r0_999999 = { 0, 999999 }; +static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 }; static paramData_t groupPLs[] = { /*0*/ { PD_STRING, groupManuf, "manuf", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)350, N_("Manufacturer"), 0, 0, sizeof(groupManuf)}, /*1*/ { PD_STRING, groupDesc, "desc", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)230, N_("Description"), 0, 0, sizeof(groupDesc)}, /*2*/ { PD_STRING, groupPartno, "partno", PDO_NOPREF|PDO_DLGHORZ|PDO_DLGIGNORELABELWIDTH|PDO_STRINGLIMITLENGTH, (void*)100, N_("#"), 0, 0, sizeof(groupPartno)}, /*3*/ { PD_LONG, &groupSegCnt, "segcnt", PDO_NOPREF, &r0_999999, N_("# Segments"), BO_READONLY }, -/*4*/ { PD_TOGGLE, &groupReplace, "replace", 0, groupReplaceLabels, "", BC_HORZ|BC_NOBORDER } }; +#define I_GROUP_ORIGIN_OFFSET 4 /* Need to change if add above */ +/*4*/ { PD_FLOAT, &groupOriginX, "orig", PDO_DIM, &r_1000_1000, N_("Offset X,Y:")}, +/*5*/ { PD_FLOAT, &groupOriginY, "origy",PDO_DIM | PDO_DLGHORZ, &r_1000_1000, ""}, +/*6*/ { PD_TOGGLE, &groupReplace, "replace", 0, groupReplaceLabels, "", BC_HORZ|BC_NOBORDER } }; static paramGroup_t groupPG = { "group", 0, groupPLs, sizeof groupPLs/sizeof groupPLs[0] }; @@ -652,18 +659,14 @@ static dynArr_t pathElem_da; static int pathElemStart; -static BOOL_T CheckTurnoutEndPoint( - trkSeg_p segs, - coOrd pos, - int end ) -{ - coOrd pos1; - DIST_T d; - pos1 = GetSegEndPt( segs, end, FALSE, NULL ); - d = FindDistance( pos, pos1 ); - return ( d < connectDistance ); -} - +/* + * Find sub-path that connects the 2 EPs for the given track + * + * \param trk IN Track + * \param ep1, ep2 IN EndPt index + * \param BOOL_T *flip OUT whether path is flipped + * \return sub-path that connects the 2 EPs + */ static char * FindPathBtwEP( track_p trk, EPINX_T ep1, @@ -671,12 +674,11 @@ static char * FindPathBtwEP( BOOL_T * flip ) { struct extraData * xx = GetTrkExtraData( trk ); - char * cp, *cp0; - int epN; - coOrd pos1, pos2; - int segInx; - EPINX_T segEP; + char * cp; + coOrd trkPos[2]; + + LOG( log_group, 3, (" FindPathBtwEP: T%d .%d .%d = ", trk?GetTrkIndex(trk):-1, ep1, ep2 )); if ( GetTrkType(trk) != T_TURNOUT ) { if ( ep1+ep2 != 1 ) AbortProg( "findPathBtwEP" ); @@ -685,40 +687,63 @@ static char * FindPathBtwEP( 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) + LOG( log_group, 3, (" Flip:%s Path= Seg=%d-\n", *flip?"T":"F", *cp ) ); return cp; } cp = (char *)xx->paths; - pos1 = GetTrkEndPos(trk,ep1); - Rotate( &pos1, xx->orig, -xx->angle ); - pos1.x -= xx->orig.x; - pos1.y -= xx->orig.y; - pos2 = GetTrkEndPos(trk,ep2); - Rotate( &pos2, xx->orig, -xx->angle ); - pos2.x -= xx->orig.x; - pos2.y -= xx->orig.y; + trkPos[0] = GetTrkEndPos(trk,ep1); + Rotate( &trkPos[0], xx->orig, -xx->angle ); + trkPos[0].x -= xx->orig.x; + trkPos[0].y -= xx->orig.y; + trkPos[1] = GetTrkEndPos(trk,ep2); + Rotate( &trkPos[1], xx->orig, -xx->angle ); + trkPos[1].x -= xx->orig.x; + trkPos[1].y -= xx->orig.y; + DIST_T dist = 1000.0; + char * path = NULL; + char * pName = "Not Found"; while ( cp[0] ) { - cp += strlen(cp)+1; //Ignore Path Name + char * pName1 = cp; // Save path name + cp += strlen(cp)+1; while ( cp[0] ) { - cp0 = cp; - epN = -1; + int segInx; + int segEP; + coOrd segPos[2]; + // Check if this sub-path endpts match the requested endpts + char * path1 = cp; + + // get the seg indices for the start and end GetSegInxEP( cp[0], &segInx, &segEP ); - if ( CheckTurnoutEndPoint( &xx->segs[segInx], pos1, segEP ) ) - epN = 1; - else if ( CheckTurnoutEndPoint( &xx->segs[segInx], pos2, segEP ) ) - epN = 0; + segPos[0] = GetSegEndPt( &xx->segs[segInx], segEP, FALSE, NULL ); cp += strlen(cp); - if ( epN != -1 ) { - GetSegInxEP( cp[-1], &segInx, &segEP ); - if ( CheckTurnoutEndPoint( &xx->segs[segInx], epN==0?pos1:pos2, 1-segEP ) ) { - *flip = epN==0; // If its reversed, set up to be flipped or noted - return cp0; //Found path between EPs + GetSegInxEP( cp[-1], &segInx, &segEP ); + segPos[1] = GetSegEndPt( &xx->segs[segInx], 1-segEP, FALSE, NULL ); + + // Find the closest seg end + for ( int inx = 0; inx<2; inx++ ) { + // Check 1st end + DIST_T dist1 = FindDistance( trkPos[0], segPos[inx] ); + if ( dist1 < connectDistance && dist1 < dist ) { + // Closest so far, Check 2nd end + DIST_T dist2 = FindDistance( trkPos[1], segPos[1-inx] ); + if ( dist2 > dist1 ) + // 2nd end is further away + dist1 = dist2; + if ( dist1 < connectDistance && dist1 < dist ) { + // both ends are closest + dist = dist1; + path = path1; + pName = pName1; + *flip = (inx==1); + } } } cp++; } cp++; } - return NULL; +LOG( log_group, 3, (" %s: %d..%d Flip:%s\n", pName, path?path[0]:-1, path?path[strlen(path)-1]:-1, *flip?"T":"F" ) ); + return path; } @@ -754,7 +779,7 @@ static int GroupShortestPathFunc( return -1; case SPTC_ADD_TRK: -if (log_shortPath<=0||logTable(log_shortPath).level<4) LOG( log_group, 2, ( " T%d[%d]\n", GetTrkIndex(trk), ep2 ) ) + LOG( log_group, 4, ( " Add T%d[%d]\n", GetTrkIndex(trk), ep2 ) ) DYNARR_APPEND( pathElem_t, pathElem_da, 10 ); ppp = &pathElem(pathElem_da.cnt-1); for ( inx=0; inx<groupTrk_da.cnt; inx++ ) { @@ -793,7 +818,7 @@ if (log_shortPath<=0||logTable(log_shortPath).level<4) LOG( log_group, 2, ( " } } if ( ep1<0 || ep2<0 ) { -LOG( log_group, 2, ( " Remove: ep not found\n" ) ) +LOG( log_group, 4, ( " Remove: ep not found\n" ) ) pathElem_da.cnt = pathElemStart; return 0; } @@ -801,7 +826,7 @@ LOG( log_group, 2, ( " Remove: ep not found\n" ) ) pp = &path(inx); if ( ( ep1 < 0 || ( pp->ep1 == ep1 || pp->ep2 == ep1 ) ) && ( ep2 < 0 || ( pp->ep1 == ep2 || pp->ep2 == ep2 ) ) ) { -LOG( log_group, 2, ( " Remove: duplicate path P%d\n", inx ) ) +LOG( log_group, 4, ( " Remove: duplicate path P%d\n", inx ) ) pathElem_da.cnt = pathElemStart; return 0; } @@ -814,7 +839,7 @@ LOG( log_group, 2, ( " Remove: duplicate path P%d\n", inx ) ) pp->ep1 = ep1; pp->ep2 = ep2; pathElemStart = pathElem_da.cnt; -LOG( log_group, 2, ( " Keep\n" ) ) +LOG( log_group, 4, ( " Keep\n" ) ) return 0; case SPTC_IGNNXTTRK: @@ -917,6 +942,87 @@ static BOOL_T CheckForBumper( return TRUE; } +typedef struct { + int inx; + wBool_t track; +} segInMap_t; +static dynArr_t segInMap_da; +#define segInMap(N) DYNARR_N( segInMap_t, segInMap_da, N) + +void AddToSegMap(int inx,wBool_t track) { + DYNARR_APPEND(segInMap_t,segInMap_da,10); + DYNARR_LAST(segInMap_t,segInMap_da).inx = inx; + DYNARR_LAST(segInMap_t,segInMap_da).track = track; +} + +void AddSegsToSegMap(int start, int end, wBool_t track) { + for (int i = start; i<= end; i++) { + AddToSegMap(i,track); + } +} + +static dynArr_t trackSegs_da; +#define trackSegs(N) DYNARR_N( trkSeg_t, trackSegs_da, N ) + + +trkSeg_p GetSegFromSegMap(int index) { + if (DYNARR_N( segInMap_t, segInMap_da, index).track) { + return &DYNARR_N(trkSeg_t,trackSegs_da,DYNARR_N( segInMap_t, segInMap_da, index).inx); + } else + return &DYNARR_N(trkSeg_t,tempSegs_da,DYNARR_N( segInMap_t, segInMap_da, index).inx); +} + +static dynArr_t outputSegs_da; +#define outputSegs(N) DYNARR_N( trkSeg_t, outputSegs_da, N) + +static void LogSeg( + trkSeg_p segP ) +{ + if ( segP == NULL ) { + LogPrintf( "<NULL>\n" ); + return; + } + LogPrintf( "%c: ", segP->type ); + switch ( segP->type ) { + case SEG_STRTRK: + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + LogPrintf( "[ %0.3f %0.3f ] [ %0.3f %0.3f ]\n", + segP->u.l.pos[0].x, segP->u.l.pos[0].y, + segP->u.l.pos[1].x, segP->u.l.pos[1].y ); + break; + case SEG_CRVLIN: + case SEG_CRVTRK: + LogPrintf( "R:%0.3f [ %0.3f %0.3f } A0:%0.3f A1:%0.3f\n", + segP->u.c.radius, + segP->u.c.center.x, segP->u.c.center.y, + segP->u.c.a0, segP->u.c.a1 ); + break; + default: + LogPrintf( "%c:\n", segP->type ); + } +} +/* + * GroupOk: create a TURNOUT or STRUCTURE from the selected objects + * 1 - Add selected tracks to groupTrk[] + * - Add each group trk's segments to trackSeg[] or tempSegs[] + * - Add all segs to segInMap[] + * - if no track segments goto step 9 + * 2 - Collect boundary endPts and sort them in tempEndPts[] + * 3 - Find shortest path between all endPts (if it exists) + * - For each track we add to the shortest path tree + * capture the sub-path elements (FindPathBtwEP) in pathElem[] + * 4 - Flip tracks so sub-path elements match up + * 5 - Create conflict map + * 6 - Flip paths to minimize the number of flipped segments + * 7 - Build the path ('P') string + * 8 - Build segment list, adjust endPts in tempEndPts[] + * 9 - create new TURNOUT/STRUCTURE definition + * 10 - write defn to xtrkcad.cus + * 11 - optionally replace grouped tracks with new defn + */ static void GroupOk( void * junk ) { @@ -925,7 +1031,6 @@ static void GroupOk( void * junk ) int inx; EPINX_T ep, epCnt, epN; coOrd orig, size; - long oldOptions; FILE * f = NULL; BOOL_T rc = TRUE; track_p trk, trk1; @@ -937,17 +1042,7 @@ static void GroupOk( void * junk ) ANGLE_T angle, angleN; pathElem_t pathElemTemp; char * cp=NULL; -#ifdef SEGMAP - pathElem_p ppp1, ppp2; - int segInx1, segInx2; - coOrd pos1, pos2; - static dynArr_t segMap_da; -#define segMap(I,J) DYNARR_N( char, segMap_da, (2*(I)+0)*trackSegs_da.cnt+(J) ) -#define segAcc(I,J) DYNARR_N( char, segMap_da, (2*(I)+1)*trackSegs_da.cnt+(J) ) -#define segSum(I,J) DYNARR_N( char, segMap_da, (2*(groupTrk_da.cnt)+0)*trackSegs_da.cnt+(J) ) -#endif - static dynArr_t trackSegs_da; -#define trackSegs(N) DYNARR_N( trkSeg_t, trackSegs_da, N ) + trkSeg_p segPtr; int segCnt; static dynArr_t conflictMap_da; @@ -965,9 +1060,6 @@ static void GroupOk( void * junk ) signed char pathChar; char *oldLocale = NULL; -#ifdef SEGMAP - DYNARR_RESET( char, segMap_da ); -#endif DYNARR_RESET( trkSeg_t, trackSegs_da ); DYNARR_RESET( trkSeg_t, tempSegs_da ); DYNARR_RESET( groupTrk_t, groupTrk_da ); @@ -976,6 +1068,8 @@ static void GroupOk( void * junk ) DYNARR_RESET( trkEndPt_t, tempEndPts_da ); DYNARR_RESET( char, pathPtr_da ); + DYNARR_RESET( segInMap_t, segInMap_da); + ParamUpdate( &groupPG ); if ( groupManuf[0]==0 || groupDesc[0]==0 || groupPartno[0]==0 ) { NoticeMessage2( 0, MSG_GROUP_NONBLANK, _("Ok"), NULL ); @@ -991,9 +1085,10 @@ static void GroupOk( void * junk ) wDrawDelayUpdate( mainD.d, TRUE ); /* - * Collect tracks + * 1: Collect tracks */ trk = NULL; + int InInx = -1; while ( TrackIterate( &trk ) ) { if ( GetTrkSelected( trk ) ) { if ( IsTrack(trk) ) { @@ -1008,41 +1103,82 @@ static void GroupOk( void * junk ) if ( IsSegTrack(segPtr) ) { DYNARR_APPEND( trkSeg_t, trackSegs_da, 10 ); trackSegs(trackSegs_da.cnt-1) = *segPtr; + + AddToSegMap(trackSegs_da.cnt-1,TRUE); /* Single Track Seg - Note no Cornu*/ + RotateSegs( 1, &trackSegs(trackSegs_da.cnt-1), zero, xx->angle ); MoveSegs( 1, &trackSegs(trackSegs_da.cnt-1), xx->orig ); + } else { + int start = tempSegs_da.cnt; DrawSegs( &groupD, xx->orig, xx->angle, segPtr, 1, trackGauge, wDrawColorBlack ); + + AddSegsToSegMap(start,tempSegs_da.cnt-1,FALSE); /* Multiple Non-Track Segs */ } } } 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); + + AddToSegMap(trackSegs_da.cnt-1,TRUE); // Add Single Bezier Track + } else if (GetTrkType(trk) == T_CORNU) { - GetBezierSegmentsFromCornu(trk,&trackSegs_da); //Only give back Bezier - cant be undone + + int start = trackSegs_da.cnt; + + GetBezierSegmentsFromCornu(trk,&trackSegs_da,TRUE); //Only give back Bezier - cant be undone + + AddSegsToSegMap(start,trackSegs_da.cnt-1,TRUE); /* Add Multiple Track Segs */ + } else { segCnt = tempSegs_da.cnt; - oldOptions = groupD.options; - groupD.options |= (DC_QUICK|DC_SIMPLE|DC_SEGTRACK); DrawTrack( trk, &groupD, wDrawColorBlack ); - groupD.options = oldOptions; DYNARR_APPEND( trkSeg_t, trackSegs_da, 10 ); segPtr = &trackSegs(trackSegs_da.cnt-1); *segPtr = tempSegs( segCnt ); + + AddToSegMap(trackSegs_da.cnt-1,TRUE); // Add One Track + if ( tempSegs_da.cnt != segCnt+1 || !IsSegTrack(segPtr) ) { NoticeMessage2( 0, MSG_CANNOT_GROUP_TRACK, _("Ok"), NULL ); wHide( groupW ); return; } + tempSegs_da.cnt = segCnt; } groupP->segEnd = trackSegs_da.cnt-1; } else { + int start = tempSegs_da.cnt; + DrawTrack( trk, &groupD, wDrawColorBlack ); + + AddSegsToSegMap(start,tempSegs_da.cnt-1,FALSE); /* Multiple Non-Track Segs */ } } } +if ( log_group >= 1 && logTable(log_group).level >= 4 ) { + LogPrintf( "Track Segs:\n"); + for ( int inx = 0; inx < trackSegs_da.cnt; inx++ ) { + LogPrintf( " %d: ", inx+1 ); + LogSeg( &trackSegs(inx) ); + } + LogPrintf( "Other Segs:\n"); + for ( int inx = 0; inx < tempSegs_da.cnt; inx++ ) { + LogPrintf( " %d: ", inx+1 ); + LogSeg( &tempSegs(inx) ); + } +} +if ( log_group >= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Combined Segs:\n" ); + for ( int inx = 0; inx<segInMap_da.cnt; inx++ ) { + LogPrintf( "%d: %s X%d - ", inx+1, segInMap(inx).track?"Track":"Other", segInMap(inx).inx ); + LogSeg( GetSegFromSegMap( inx ) ); + } +} if ( groupTrk_da.cnt>0 ) { if ( groupTrk_da.cnt > 128 ) { @@ -1084,6 +1220,17 @@ static void GroupOk( void * junk ) } } } +if ( log_group >= 1 && logTable(log_group).level >= 4 ) { + LogPrintf( "EndPts:\n" ); + for ( int inx=0; inx<tempEndPts_da.cnt; inx++ ) { + endPtP = &tempEndPts(inx); + LogPrintf( " [ %0.3f %0.3f ] A:%0.3f, T:%d.%d\n", + endPtP->pos.x, endPtP->pos.y, endPtP->angle, endPtP->track?GetTrkIndex(endPtP->track):-1, endPtP->index ); + } +} + /* + * 2: Collect EndPts + */ if ( tempEndPts_da.cnt <= 0 ) { NoticeMessage( _("No endpts"), _("Ok"), NULL ); wDrawDelayUpdate( mainD.d, FALSE ); @@ -1140,10 +1287,7 @@ static void GroupOk( void * junk ) qsort( tempEndPts_da.ptr, tempEndPts_da.cnt, sizeof *endPtP, CmpEndPtAngle ); if ( NormalizeAngle( tempEndPts(0).angle - tempEndPts(tempEndPts_da.cnt-1).angle ) > NormalizeAngle( tempEndPts(1).angle - tempEndPts(0).angle ) ) { -#ifdef LATER - if ( endPtAngle-FindAngle(endPtOrig,tempEndPts(tempEndPts_da.cnt-1).pos) > - FindAngle(endPtOrig,tempEndPts(1).pos)-endPtAngle ) { -#endif + for ( ep=1; ep<(tempEndPts_da.cnt+1)/2; ep++ ) { trkEndPt_t tempEndPt; tempEndPt = tempEndPts(ep); @@ -1151,9 +1295,17 @@ static void GroupOk( void * junk ) tempEndPts(tempEndPts_da.cnt-ep) = tempEndPt; } } +if ( log_group >= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Sorted EndPts:\n" ); + for ( int inx=0; inx<tempEndPts_da.cnt; inx++ ) { + endPtP = &tempEndPts(inx); + LogPrintf( " [ %0.3f %0.3f ] A:%0.3f, T:%d.%d\n", + endPtP->pos.x, endPtP->pos.y, endPtP->angle, endPtP->track?GetTrkIndex(endPtP->track):-1, endPtP->index ); + } +} /* - * Find shortest Paths + * 3: Find shortest Paths */ for ( inx=0; inx<groupTrk_da.cnt; inx++ ) { trk = groupTrk(inx).trk; @@ -1162,13 +1314,37 @@ static void GroupOk( void * junk ) trk1 = GetTrkEndTrk(trk,ep); if ( trk1 == NULL || !GetTrkSelected(trk1) ) { /* boundary EP */ + LOG( log_group, 3, ("FindShortPath: T%d.%d\n", GetTrkIndex(trk), ep ) ); rc = FindShortestPath( trk, ep, FALSE, GroupShortestPathFunc, NULL ); } } } - +if ( log_group >= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Shortest path:\n Group Tracks\n" ); + for ( int inx=0; inx<groupTrk_da.cnt; inx++ ) { + groupTrk_p gtp = &groupTrk(inx); + LogPrintf( " %d: T%d S%d-%d\n", inx, GetTrkIndex( gtp->trk ), gtp->segStart+1, gtp->segEnd+1 ); + } + LogPrintf( " Path Elem\n" ); + for ( int inx=0; inx<pathElem_da.cnt; inx++ ) { + ppp = &pathElem(inx); + LogPrintf( " %d: GTx: %d, EP: %d %d, F:%s, P:", + inx, ppp->groupInx, ppp->ep1, ppp->ep2, ppp->flip?"T":"F" ); + for ( PATHPTR_T cp = ppp->path; cp[0] || cp[1]; cp++ ) { + LogPrintf( " %d", *cp ); + } + LogPrintf( " 0\n" ); + } + LogPrintf( " Path\n" ); + for ( int inx=0; inx<path_da.cnt; inx++ ) { + path_p pp = &path(inx); + LogPrintf( " %d: PE: %d-%d, EP: %d-%d, Conf: %d, InGrp: %s, Done: %s\n", + inx, pp->pathElemStart, pp->pathElemEnd, pp->ep1, pp->ep2, + pp->conflicts, pp->inGroup?"T":"F", pp->done?"T":"F" ); + } +} /* - * Flip paths so they align + * 4: Flip paths so they align */ if ( path_da.cnt == 0 ) { NoticeMessage( _("No paths"), _("Ok"), NULL ); @@ -1226,11 +1402,11 @@ LOG( log_group, 1, ( "P%d aligns flipped with P%d\n", pinx, pinx2 ) ); path(inx).done = TRUE; } } -if ( log_group >= 1 && logTable(log_group).level > log_group ) { +if ( log_group >= 1 && logTable(log_group).level >= 1 ) { LogPrintf( "Group Paths\n" ); for ( pinx=0; pinx<path_da.cnt; pinx++ ) { pp = &path(pinx); - LogPrintf( "P%2d:%d.%d ", pinx, pp->ep1, pp->ep2 ); + LogPrintf( " P%2d:%d.%d ", pinx, pp->ep1, pp->ep2 ); for ( pinx2=pp->pathElemEnd; pinx2>=pp->pathElemStart; pinx2-- ) { ppp = &pathElem(pinx2); LogPrintf( " %sT%d:%d.%d", ppp->flip?"-":"", GetTrkIndex(groupTrk(ppp->groupInx).trk), ppp->ep1, ppp->ep2 ); @@ -1239,62 +1415,9 @@ if ( log_group >= 1 && logTable(log_group).level > log_group ) { } } -#ifdef SEGMAP - DYNARR_SET( char, segMap_da, 2 * trackSegs_da.cnt * path_da.cnt + 2 ); - memset( segMap_da.ptr, 0, segMap_da.max * sizeof segMap(0,0) ); - for ( inx=0; inx<path_da.cnt; inx++ ) { - pp = &path(inx); - for ( inx2=pp->pathElem_da.cnt-1; inx2>=0; inx2-- ) { - ppp = &pathElem(pp->pathElemStart+inx2); - groupP = &groupTrk(ppp->groupInx); - if ( GetTrkEndPtCnt(groupP->trk) == 2 ) { - segMap(inx,groupP->segStart) = 1; - continue; - } - cp = ppp->path; - if ( cp == NULL ) - continue; - segInx1 = cp[0]-1; - for ( ; *cp; cp++ ) - segMap(inx,groupP->segInx+cp[0]-1) = 1; - segInx2 = cp[-1]-1; - pos1 = GetSegEndPt( &trackSegs(groupP->segInx+segInx1), ppp->flip?1:0, FALSE, NULL ); - pos2 = GetSegEndPt( &trackSegs(groupP->segInx+segInx2), ppp->flip?0:1, FALSE, NULL ); - for ( inx3=0; inx3<groupP->segCnt; inx3++ ) { - if ( inx3 == segInx1 || inx3 == segInx2 ) continue; - if ( segMap(inx,groupP->segInx+inx3) != 0 ) continue; - if ( CheckTurnoutEndPoint( &trackSegs(groupP->segInx+inx3), pos1, 0 ) ) - segMap(inx,inx3) = 2; - else if ( CheckTurnoutEndPoint( &trackSegs(groupP->segInx+inx3), pos2, 0 ) ) - segMap(inx,groupP->segInx+inx3) = 2; - } - } - } -if ( log_group >= 1 && logTable(log_group).level > log_group ) { - LogPrintf( "Path to Segment Map\n "); - for ( inx=0; inx<groupTrk_da.cnt; inx++ ) { - groupP = &groupTrk(inx); - LogPrintf( "%2d", GetTrkIndex(groupP->trk) ); - for ( inx2=1; inx2<groupP->segCnt; inx2++ ) LogPrintf( "--" ); - } - LogPrintf( "\n " ); - for ( inx=0; inx<groupTrk_da.cnt; inx++ ) { - groupP = &groupTrk(inx); - for ( inx2=0; inx2<groupP->segCnt; inx2++ ) - LogPrintf( "%2d", inx2+1 ); - } - LogPrintf( "\n" ); - for ( inx=0; inx<path_da.cnt; inx++ ) { - LogPrintf( "%2d ", inx ); - for ( inx2=0; inx2<trackSegs_da.cnt; inx2++ ) - LogPrintf( "%2d", segMap(inx,inx2) ); - LogPrintf("\n"); - } -} -#endif /* - * Create Conflict Map + * 5: Create Conflict Map */ DYNARR_SET( int, conflictMap_da, path_da.cnt*path_da.cnt ); memset( conflictMap_da.ptr, 0, conflictMap_da.max * sizeof conflictMap(0,0) ); @@ -1353,42 +1476,18 @@ if ( log_group >= 1 && logTable(log_group).level > log_group ) { } } -if ( log_group >= 1 && logTable(log_group).level > log_group ) { +if ( log_group >= 1 && logTable(log_group).level >= 3 ) { LogPrintf( "Group Map\n"); for ( pinx=0; pinx<groupCnt; pinx++ ) { LogPrintf( "G%d:", pinx ); for ( ginx=0; groupMap(pinx,ginx) >= 0; ginx++ ) - LogPrintf( " %d", groupMap(pinx,ginx) ); + LogPrintf( " %d: %d", ginx, groupMap(pinx,ginx) ); LogPrintf( "\n" ); } } -#ifdef SEGMAP - for ( inx=0; inx<path_da.cnt; inx++ ) { - for ( inx2=0; inx2<tempSegs_da.cnt; inx2++ ) { - groupInx = 0; - memset( &SegTotal(0), 0, tempSegs_da.cnt * sizeof SegAcc(0) ); - while (1) { - memcpy( &SegAcc(0), &SegTotal(0), tempSegs_da.cnt * sizeof SegAcc(0) ); - collision = FALSE; - for ( inx=0; inx<path_da.cnt; inx++ ) { - pp = path(0); - if ( pp->groupInx < 0 ) continue; - for ( inx2=0; inx2<tempSegs_da.cnt; inx2++ ) { - if ( !segMap(inx,inx2) ) continue; - if ( SegAcc(inx2) ) { - collision = TRUE; - break; - } - SegAcc(inx2) = TRUE; - } - } - if ( collision ) - } -#endif - /* - * Count number of times each segment is used as flipped + * 6: Count number of times each segment is used as flipped */ DYNARR_SET( int, conflictMap_da, trackSegs_da.cnt ); memset( &segFlip(0), 0, trackSegs_da.cnt * sizeof segFlip(0) ); @@ -1414,15 +1513,17 @@ if ( log_group >= 1 && logTable(log_group).level > log_group ) { /* * Flip each segment that is used as flipped more than not */ +LOG( log_group, 3, ( "Flipping Segments:" ) ); 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 ); +LOG( log_group, 3, ( " %d", pinx ) ); } } +LOG( log_group, 3, ( "\n" ) ); /* - * Output Path lists + * 7: Output Path lists */ for ( pinx=0; pinx<groupCnt; pinx++ ) { sprintf( message, "P%d", pinx ); @@ -1431,8 +1532,10 @@ LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) ); memcpy( &pathPtr(inx), message, pathPtr_da.cnt-inx ); for ( ginx=0; groupMap(pinx,ginx) >= 0; ginx++ ) { pp = &path(groupMap(pinx,ginx)); + LOG( log_group, 3, (" Group Map(%d, %d): elem %d-%d, EP %d %d, Conflicts %d, inGrp %d, Done: %s\n", pinx, ginx, pp->pathElemStart, pp->pathElemEnd, pp->ep1, pp->ep2, pp->conflicts, pp->inGroup, pp->done?"T":"F" ) ); for ( pinx2=pp->pathElemEnd; pinx2>=pp->pathElemStart; pinx2-- ) { ppp = &pathElem( pinx2 ); + LOG( log_group, 3, (" PE %d: GI %d, EP %d %d, Flip %d =", pinx2, ppp->groupInx, ppp->ep1, ppp->ep2, ppp->flip )); groupP = &groupTrk( ppp->groupInx ); path = ppp->path; flip = ppp->flip; @@ -1453,7 +1556,9 @@ LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) ); if ( flip1 ) pathChar = - pathChar; pathPtr(pathPtr_da.cnt-1) = pathChar; path += (flip?-1:1); + LOG( log_group, 3, (" %d", pathChar ) ); } + LOG( log_group, 3, ("\n") ); } DYNARR_APPEND( char, pathPtr_da, 10 ); pathPtr(pathPtr_da.cnt-1) = 0; @@ -1468,43 +1573,49 @@ LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) ); groupSimpleTurnout: /* - * Copy and Reorigin Segments + * 8: Copy and Reorigin Segments - Start by putting them out in the original order */ - if ( tempSegs_da.cnt > 0 ) { - inx = trackSegs_da.cnt; - DYNARR_SET( trkSeg_t, trackSegs_da, trackSegs_da.cnt+tempSegs_da.cnt ); - memcpy( &trackSegs(inx), tempSegs_da.ptr, tempSegs_da.cnt*sizeof trackSegs(0) ); - CloneFilledDraw( tempSegs_da.cnt, &trackSegs(inx), TRUE ); + + + DYNARR_RESET(trkSeg_t, outputSegs_da); + for (int i=0; i<segInMap_da.cnt;i++) { + DYNARR_APPEND(trkSeg_t,outputSegs_da,10); + trkSeg_p from_p = GetSegFromSegMap(i); + trkSeg_p to_p = &DYNARR_LAST(trkSeg_t, outputSegs_da); + memcpy((void *)to_p,(void *)from_p,sizeof( trkSeg_t)); } - GetSegBounds( zero, 0, trackSegs_da.cnt, &trackSegs(0), &orig, &size ); + CloneFilledDraw( outputSegs_da.cnt, outputSegs_da.ptr, FALSE ); + + GetSegBounds( zero, 0, outputSegs_da.cnt, &outputSegs(0), &orig, &size ); orig.x = - tempEndPts(0).pos.x; orig.y = - tempEndPts(0).pos.y; - MoveSegs( trackSegs_da.cnt, &trackSegs(0), orig ); + MoveSegs( outputSegs_da.cnt, &outputSegs(0), orig ); for ( ep=0; ep<tempEndPts_da.cnt; ep++ ) { tempEndPts(ep).pos.x += orig.x; tempEndPts(ep).pos.y += orig.y; } /* - * Final: create new definition + * 9: Final: create new definition + */ + + CheckPaths( outputSegs_da.cnt, &outputSegs(0), path ); + + to = CreateNewTurnout( curScaleName, groupTitle, outputSegs_da.cnt, &outputSegs(0), pathLen, path, tempEndPts_da.cnt, &tempEndPts(0), NULL, TRUE ); + + /* + * 10: Write defn to xtrkcad.cus */ - CheckPaths( trackSegs_da.cnt, &trackSegs(0), path ); - to = CreateNewTurnout( curScaleName, groupTitle, trackSegs_da.cnt, &trackSegs(0), pathLen, path, tempEndPts_da.cnt, &tempEndPts(0), TRUE ); -#ifdef LATER - if ( xx ) - to->customInfo = xx->customInfo; -#endif f = OpenCustom("a"); if (f && to) { oldLocale = SaveLocale("C"); rc &= fprintf( f, "TURNOUT %s \"%s\"\n", curScaleName, PutTitle(to->title) )>0; -#ifdef LATER - if ( to->customInfo ) - rc &= fprintf( f, "\tU %s\n", to->customInfo )>0; -#endif - rc &= WriteCompoundPathsEndPtsSegs( f, path, trackSegs_da.cnt, &trackSegs(0), tempEndPts_da.cnt, &tempEndPts(0) ); + rc &= WriteCompoundPathsEndPtsSegs( f, path, outputSegs_da.cnt, &outputSegs(0), tempEndPts_da.cnt, &tempEndPts(0) ); } if ( groupReplace ) { + /* + * 11: Replace defn + */ UndoStart( _("Group Tracks"), "group" ); orig.x = - orig.x; orig.y = - orig.y; @@ -1528,8 +1639,7 @@ groupSimpleTurnout: trackCount--; } } - trk = NewCompound( T_TURNOUT, 0, orig, 0.0, to->title, tempEndPts_da.cnt, &tempEndPts(0), pathLen, (char *)path, trackSegs_da.cnt, &trackSegs(0) ); - SetTrkVisible( trk, TRUE ); + trk = NewCompound( T_TURNOUT, 0, orig, 0.0, to->title, tempEndPts_da.cnt, &tempEndPts(0), NULL, pathLen, (char *)path, outputSegs_da.cnt, &outputSegs(0) ); SetTrkVisible( trk, TRUE ); for ( ep=0; ep<tempEndPts_da.cnt; ep++ ) { @@ -1544,18 +1654,15 @@ groupSimpleTurnout: } else { CloneFilledDraw( tempSegs_da.cnt, &tempSegs(0), TRUE ); GetSegBounds( zero, 0, tempSegs_da.cnt, &tempSegs(0), &orig, &size ); - orig.x = - orig.x; - orig.y = - orig.y; + + orig.x = - orig.x-groupOriginX; //Include orig offset + orig.y = - orig.y-groupOriginY; MoveSegs( tempSegs_da.cnt, &tempSegs(0), orig ); to = CreateNewStructure( curScaleName, groupTitle, tempSegs_da.cnt, &tempSegs(0), TRUE ); f = OpenCustom("a"); if (f && to) { oldLocale = SaveLocale("C"); rc &= fprintf( f, "STRUCTURE %s \"%s\"\n", curScaleName, PutTitle(groupTitle) )>0; -#ifdef LATER - if ( to->customInfo ) - rc &= fprintf( f, "\tU %s\n", to->customInfo )>0; -#endif rc &= WriteSegs( f, tempSegs_da.cnt, &tempSegs(0) ); } if ( groupReplace ) { @@ -1570,7 +1677,7 @@ groupSimpleTurnout: } orig.x = - orig.x; orig.y = - orig.y; - trk = NewCompound( T_STRUCTURE, 0, orig, 0.0, groupTitle, 0, NULL, 0, "", tempSegs_da.cnt, &tempSegs(0) ); + trk = NewCompound( T_STRUCTURE, 0, orig, 0.0, groupTitle, 0, NULL, NULL, 0, "", tempSegs_da.cnt, &tempSegs(0) ); SetTrkVisible( trk, TRUE ); DrawNewTrack( trk ); EnableCommands(); @@ -1594,10 +1701,14 @@ EXPORT void DoGroup( void ) xx = NULL; groupSegCnt = 0; groupCompoundCount = 0; + groupOriginX = 0.0; + groupOriginY = 0.0; + BOOL_T isTurnout = FALSE; while ( TrackIterate( &trk ) ) { if ( GetTrkSelected( trk ) ) { trkType = GetTrkType(trk); + if ( IsTrack(trk) ) isTurnout = TRUE; if ( trkType == T_TURNOUT || trkType == T_STRUCTURE ) { xx = GetTrkExtraData(trk); groupSegCnt += xx->segCnt; @@ -1618,6 +1729,18 @@ EXPORT void DoGroup( void ) groupW = ParamCreateDialog( &groupPG, MakeWindowTitle(_("Group Objects")), _("Ok"), GroupOk, wHide, TRUE, NULL, F_BLOCK, NULL ); groupD.dpi = mainD.dpi; } + if (isTurnout) { + groupPLs[4].option |= PDO_DLGIGNORE; + wControlShow( groupPLs[4].control, FALSE ); + groupPLs[5].option |= PDO_DLGIGNORE; + wControlShow( groupPLs[5].control, FALSE ); + } else { + groupPLs[4].option &= ~PDO_DLGIGNORE; + wControlShow( groupPLs[4].control, TRUE ); + groupPLs[5].option &= ~PDO_DLGIGNORE; + wControlShow( groupPLs[5].control, TRUE ); + } + ParamLoadControls( &groupPG ); wShow( groupW ); } diff --git a/app/bin/chndldto.c b/app/bin/chndldto.c index fa88398..a0f2d6b 100644 --- a/app/bin/chndldto.c +++ b/app/bin/chndldto.c @@ -91,7 +91,6 @@ static STATUS_T CmdHandLaidTurnout( wAction_t action, coOrd pos ) Dhlt.normalP = Dhlt.reverseP = Dhlt.reverseP1 = pos; Dhlt.normalA = GetAngleAtPoint( Dhlt.normalT, Dhlt.normalP, NULL, NULL ); InfoMessage( _("Drag to set angle") ); - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); Dhlt.state = 1; pointC = pointP = pointP1 = reverseC = zero; return C_CONTINUE; @@ -102,7 +101,6 @@ static STATUS_T CmdHandLaidTurnout( wAction_t action, coOrd pos ) if (Dhlt.normalT == NULL) break; if (Dhlt.state == 1) { - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); Dhlt.reverseP1 = pos; Dhlt.reverseA = FindAngle( Dhlt.reverseP, Dhlt.reverseP1 ); Dhlt.frogA = NormalizeAngle( Dhlt.reverseA - Dhlt.normalA ); @@ -141,10 +139,8 @@ static STATUS_T CmdHandLaidTurnout( wAction_t action, coOrd pos ) Translate( &Dhlt.reverseP, Dhlt.reverseP, Dhlt.normalA+(right?+90:-90), trackGauge ); Translate( &Dhlt.reverseP1, Dhlt.reverseP1, Dhlt.normalA+(right?+90:-90), trackGauge ); } - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); return C_CONTINUE; } else if ( Dhlt.state == 2 ) { - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); tempSegs_da.cnt = 0; pointP = pos; if ((pointT = OnTrack( &pointP, TRUE, TRUE )) == NULL) @@ -273,7 +269,6 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 )) if (action != C_UP) { dist = FindDistance( pointP, Dhlt.normalP ); InfoMessage( _("Length = %0.2f Angle = %0.2f Frog# = %0.2f"), dist, Dhlt.frogA, Dhlt.frogNo ); - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; } UndoStart( _("Create Hand Laid Turnout"), "Hndldto( T%d[%d] )", GetTrkIndex(pointT), pointEp0 ); @@ -334,7 +329,6 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 )) DrawTrack( trk, &mainD, wDrawColorBlack ); for (trkpp=trks; *trkpp; trkpp++) DrawTrack( *trkpp, &mainD, wDrawColorBlack ); - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); Dhlt.state = 0; return C_TERMINATE; @@ -348,12 +342,6 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 )) return C_CONTINUE; case C_CANCEL: - if (Dhlt.state >= 1) - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); - if (Dhlt.state >= 2) { - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - tempSegs_da.cnt = 0; - } return C_CONTINUE; } @@ -367,5 +355,5 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 )) EXPORT void InitCmdHandLaidTurnout( wMenu_p menu ) { - AddMenuButton( menu, CmdHandLaidTurnout, "cmdHandLaidTurnout", _("HandLaidTurnout"), wIconCreatePixMap(hndldto_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_HNDLDTO, NULL ); + AddMenuButton( menu, CmdHandLaidTurnout, "cmdHandLaidTurnout", _("HandLaidTurnout"), wIconCreatePixMap(hndldto_xpm), LEVEL0_50, IC_STICKY|IC_INITNOTSTICKY|IC_POPUP2, ACCL_HNDLDTO, NULL ); } diff --git a/app/bin/chotbar.c b/app/bin/chotbar.c index 31a19ad..0b9a327 100644 --- a/app/bin/chotbar.c +++ b/app/bin/chotbar.c @@ -27,6 +27,7 @@ #include "compound.h" #include "fileio.h" #include "messages.h" +#include "ccornu.h" |