Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FormerLurker/ArcWelderLib.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFormerLurker <hochgebe@gmail.com>2020-04-26 01:20:39 +0300
committerFormerLurker <hochgebe@gmail.com>2020-04-26 01:20:39 +0300
commit4fcf89d4995921b89b579d06052df11b66e4879f (patch)
tree390bbfcab87591e802f9ac91ac2d531b4ae53946 /PyArcWelder
Add project files.
Diffstat (limited to 'PyArcWelder')
-rw-r--r--PyArcWelder/PyArcWelder.vcxproj171
-rw-r--r--PyArcWelder/PyArcWelder.vcxproj.filters45
-rw-r--r--PyArcWelder/py_arc_welder.cpp48
-rw-r--r--PyArcWelder/py_arc_welder.h49
-rw-r--r--PyArcWelder/py_arc_welder_extension.cpp281
-rw-r--r--PyArcWelder/py_arc_welder_extension.h78
-rw-r--r--PyArcWelder/py_logger.cpp246
-rw-r--r--PyArcWelder/py_logger.h66
-rw-r--r--PyArcWelder/python_helpers.cpp116
-rw-r--r--PyArcWelder/python_helpers.h40
10 files changed, 1140 insertions, 0 deletions
diff --git a/PyArcWelder/PyArcWelder.vcxproj b/PyArcWelder/PyArcWelder.vcxproj
new file mode 100644
index 0000000..a17c4c6
--- /dev/null
+++ b/PyArcWelder/PyArcWelder.vcxproj
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <ProjectGuid>{DB476DBA-77D5-40A7-ADAB-D9901F32B270}</ProjectGuid>
+ <RootNamespace>PyArcWelder</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>C:\Python27\include;$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>C:\Python27\include;$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>C:\Python27\include;$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>C:\Python27\include;$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>C:\Python27\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>C:\Python27\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>C:\Python27\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>C:\Python27\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="python_helpers.h" />
+ <ClInclude Include="py_arc_welder.h" />
+ <ClInclude Include="py_arc_welder_extension.h" />
+ <ClInclude Include="py_logger.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="python_helpers.cpp" />
+ <ClCompile Include="py_arc_welder.cpp" />
+ <ClCompile Include="py_arc_welder_extension.cpp" />
+ <ClCompile Include="py_logger.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\ArcWelder\ArcWelder.vcxproj">
+ <Project>{1a4dbab1-bb42-4db1-b168-f113784efcef}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\GcodeProcessorLib\GcodeProcessorLib.vcxproj">
+ <Project>{31478bae-104b-4cc3-9876-42fa90cbd5fe}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/PyArcWelder/PyArcWelder.vcxproj.filters b/PyArcWelder/PyArcWelder.vcxproj.filters
new file mode 100644
index 0000000..8544f81
--- /dev/null
+++ b/PyArcWelder/PyArcWelder.vcxproj.filters
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="py_arc_welder.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="py_arc_welder_extension.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="py_logger.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="python_helpers.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="py_arc_welder.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="py_arc_welder_extension.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="py_logger.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="python_helpers.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/PyArcWelder/py_arc_welder.cpp b/PyArcWelder/py_arc_welder.cpp
new file mode 100644
index 0000000..5768b40
--- /dev/null
+++ b/PyArcWelder/py_arc_welder.cpp
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Arc Welder: Anti-Stutter Python Extension for the OctoPrint Arc Welder plugin.
+//
+// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
+// This reduces file size and the number of gcodes per second.
+//
+// Copyright(C) 2020 - Brad Hochgesang
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// This program is free software : you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+//
+// You can contact the author at the following email address:
+// FormerLurker@pm.me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#include "py_arc_welder.h"
+
+
+bool py_arc_welder::on_progress_(double percent_complete, double seconds_elapsed, double estimated_seconds_remaining, int gcodes_processed, int current_line, int points_compressed, int arcs_created)
+{
+ PyObject* funcArgs = Py_BuildValue("(d,d,d,i,i,i,i)", percent_complete, seconds_elapsed, estimated_seconds_remaining, gcodes_processed, current_line, points_compressed, arcs_created);
+ if (funcArgs == NULL)
+ {
+ return false;
+ }
+
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* pContinueProcessing = PyObject_CallObject(py_progress_callback_, funcArgs);
+ Py_DECREF(funcArgs);
+ bool continue_processing = PyLong_AsLong(pContinueProcessing) > 0;
+ Py_DECREF(pContinueProcessing);
+ PyGILState_Release(gstate);
+
+ if (pContinueProcessing == NULL || pContinueProcessing == Py_None)
+ {
+ // no return value was supply, assume true
+
+ return true;
+ }
+ return continue_processing;
+}
diff --git a/PyArcWelder/py_arc_welder.h b/PyArcWelder/py_arc_welder.h
new file mode 100644
index 0000000..64bfd71
--- /dev/null
+++ b/PyArcWelder/py_arc_welder.h
@@ -0,0 +1,49 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Arc Welder: Anti-Stutter Python Extension for the OctoPrint Arc Welder plugin.
+//
+// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
+// This reduces file size and the number of gcodes per second.
+//
+// Copyright(C) 2020 - Brad Hochgesang
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// This program is free software : you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+//
+// You can contact the author at the following email address:
+// FormerLurker@pm.me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma once
+#include <arc_welder.h>
+#include <string>
+#include "py_logger.h"
+#ifdef _DEBUG
+#undef _DEBUG
+#include <Python.h>
+#define _DEBUG
+#else
+#include <Python.h>
+#endif
+class py_arc_welder : public arc_welder
+{
+public:
+ py_arc_welder(std::string source_path, std::string target_path, py_logger* logger, double resolution_mm, bool g90_g91_influences_extruder, int buffer_size, PyObject* py_progress_callback):arc_welder(source_path, target_path, logger, resolution_mm, g90_g91_influences_extruder, buffer_size)
+ {
+ py_progress_callback_ = py_progress_callback;
+ }
+ virtual ~py_arc_welder() {
+
+ }
+protected:
+ virtual bool on_progress_(double percent_complete, double seconds_elapsed, double estimated_seconds_remaining, int gcodes_processed, int current_line, int points_compressed, int arcs_created);
+private:
+ PyObject* py_progress_callback_;
+};
+
diff --git a/PyArcWelder/py_arc_welder_extension.cpp b/PyArcWelder/py_arc_welder_extension.cpp
new file mode 100644
index 0000000..eaf9923
--- /dev/null
+++ b/PyArcWelder/py_arc_welder_extension.cpp
@@ -0,0 +1,281 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Arc Welder: Anti-Stutter Python Extension for the OctoPrint Arc Welder plugin.
+//
+// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
+// This reduces file size and the number of gcodes per second.
+//
+// Copyright(C) 2020 - Brad Hochgesang
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// This program is free software : you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+//
+// You can contact the author at the following email address:
+// FormerLurker@pm.me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#include "py_arc_welder_extension.h"
+#include "py_arc_welder.h"
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+#include "arc_welder.h"
+#include "py_logger.h"
+#include "python_helpers.h"
+
+#if PY_MAJOR_VERSION >= 3
+int main(int argc, char* argv[])
+{
+ wchar_t* program = Py_DecodeLocale(argv[0], NULL);
+ if (program == NULL) {
+ fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
+ exit(1);
+ }
+
+ // Add a built-in module, before Py_Initialize
+ PyImport_AppendInittab("PyArcWelder", PyInit_PyGcodeArcConverter);
+
+ // Pass argv[0] to the Python interpreter
+ Py_SetProgramName(program);
+
+ // Initialize the Python interpreter. Required.
+ Py_Initialize();
+ std::cout << "Initializing threads...";
+ if (!PyEval_ThreadsInitialized()) {
+ PyEval_InitThreads();
+ }
+ // Optionally import the module; alternatively, import can be deferred until the embedded script imports it.
+ PyImport_ImportModule("PyArcWelder");
+ PyMem_RawFree(program);
+ return 0;
+}
+
+#else
+
+int main(int argc, char* argv[])
+{
+ Py_SetProgramName(argv[0]);
+ Py_Initialize();
+ if (!PyEval_ThreadsInitialized()) {
+ PyEval_InitThreads();
+ }
+ initPyGcodeArcConverter();
+ return 0;
+
+}
+#endif
+
+struct module_state {
+ PyObject* error;
+};
+#if PY_MAJOR_VERSION >= 3
+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
+#else
+#define GETSTATE(m) (&_state)
+static struct module_state _state;
+#endif
+
+// Python 2 module method definition
+static PyMethodDef PyGcodeArcConverterMethods[] = {
+ { "ConvertFile", (PyCFunction)ConvertFile, METH_VARARGS ,"Converts segmented curve approximations to actual G2/G3 arcs within the supplied resolution." },
+ { NULL, NULL, 0, NULL }
+};
+
+// Python 3 module method definition
+#if PY_MAJOR_VERSION >= 3
+static int PyGcodeArcConverter_traverse(PyObject* m, visitproc visit, void* arg) {
+ Py_VISIT(GETSTATE(m)->error);
+ return 0;
+}
+
+static int PyGcodeArcConverter_clear(PyObject* m) {
+ Py_CLEAR(GETSTATE(m)->error);
+ return 0;
+}
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "PyGcodeArcConverter",
+ NULL,
+ sizeof(struct module_state),
+ PyGcodeArcConverterMethods,
+ NULL,
+ PyGcodeArcConverter_traverse,
+ PyGcodeArcConverter_clear,
+ NULL
+};
+
+#define INITERROR return NULL
+
+PyMODINIT_FUNC
+PyInit_PyGcodeArcConverter(void)
+
+#else
+#define INITERROR return
+
+extern "C" void initPyGcodeArcConverter(void)
+#endif
+{
+ std::cout << "Initializing PyGcodeArcConverter V0.1.0rc1.dev0 - Copyright (C) 2019 Brad Hochgesang...";
+
+#if PY_MAJOR_VERSION >= 3
+ std::cout << "Python 3+ Detected...";
+ PyObject* module = PyModule_Create(&moduledef);
+#else
+ std::cout << "Python 2 Detected...";
+ PyObject* module = Py_InitModule("PyGcodeArcConverter", PyGcodeArcConverterMethods);
+#endif
+
+ if (module == NULL)
+ INITERROR;
+ struct module_state* st = GETSTATE(module);
+
+ st->error = PyErr_NewException((char*)"PyGcodeArcConverter.Error", NULL, NULL);
+ if (st->error == NULL) {
+ Py_DECREF(module);
+ INITERROR;
+ }
+ std::vector<std::string> logger_names;
+ logger_names.push_back("arc_welder.gcode_conversion");
+ std::vector<int> logger_levels;
+ logger_levels.push_back(log_levels::DEBUG);
+ p_py_logger = new py_logger(logger_names, logger_levels);
+ p_py_logger->initialize_loggers();
+ std::string message = "PyArcWelder V0.1.0rc1.dev0 imported - Copyright (C) 2019 Brad Hochgesang...";
+ p_py_logger->log(GCODE_CONVERSION, INFO, message);
+ p_py_logger->set_log_level_by_value(DEBUG);
+ std::cout << "complete\r\n";
+
+#if PY_MAJOR_VERSION >= 3
+ return module;
+#endif
+}
+
+extern "C"
+{
+ static PyObject* ConvertFile(PyObject* self, PyObject* py_args)
+ {
+ PyObject* py_convert_file_args;
+ if (!PyArg_ParseTuple(
+ py_args,
+ "O",
+ &py_convert_file_args
+ ))
+ {
+ std::string message = "py_gcode_arc_converter.ConvertFile - Cound not extract the parameters dictionary.";
+ p_py_logger->log_exception(GCODE_CONVERSION, message);
+ return NULL;
+ }
+
+ py_gcode_arc_args args;
+ PyObject* py_progress_callback = NULL;
+
+ if (!ParseArgs(py_convert_file_args, args, &py_progress_callback))
+ {
+ return NULL;
+ }
+ p_py_logger->set_log_level_by_value(args.log_level);
+ std::stringstream stream;
+ stream << "py_gcode_arc_converter.ConvertFile - Parameters received: source_file_path: '" <<
+ args.source_file_path << "', target_file_path:'" << args.target_file_path << "' resolution_mm:" <<
+ args.resolution_mm << ", g90_91_influences_extruder: " << (args.g90_g91_influences_extruder ? "True" : "False") << "\n";
+ p_py_logger->log(GCODE_CONVERSION, INFO, stream.str());
+
+ std::string message = "py_gcode_arc_converter.ConvertFile - Beginning Arc Conversion.";
+ p_py_logger->log(GCODE_CONVERSION, INFO, message);
+
+ py_arc_welder arc_welder_obj(args.source_file_path, args.target_file_path, p_py_logger, args.resolution_mm, args.g90_g91_influences_extruder, 50, py_progress_callback);
+ arc_welder_obj.process();
+ message = "py_gcode_arc_converter.ConvertFile - Arc Conversion Complete.";
+ p_py_logger->log(GCODE_CONVERSION, INFO, message);
+ Py_XDECREF(py_progress_callback);
+ // For now just return py_none
+ return PyTuple_Pack(1, Py_None);
+ }
+}
+
+static bool ParseArgs(PyObject* py_args, py_gcode_arc_args& args, PyObject** py_progress_callback)
+{
+ p_py_logger->log(
+ GCODE_CONVERSION, INFO,
+ "Parsing GCode Conversion Args."
+ );
+
+ // Extract the source file path
+ PyObject* py_source_file_path = PyDict_GetItemString(py_args, "source_file_path");
+ if (py_source_file_path == NULL)
+ {
+ std::string message = "ParseArgs - Unable to retrieve the source_file_path parameter from the args.";
+ p_py_logger->log_exception(GCODE_CONVERSION, message);
+ return false;
+ }
+ args.source_file_path = gcode_arc_converter::PyUnicode_SafeAsString(py_source_file_path);
+
+ // Extract the target file path
+ PyObject* py_target_file_path = PyDict_GetItemString(py_args, "target_file_path");
+ if (py_target_file_path == NULL)
+ {
+ std::string message = "ParseArgs - Unable to retrieve the target_file_path parameter from the args.";
+ p_py_logger->log_exception(GCODE_CONVERSION, message);
+ return false;
+ }
+ args.target_file_path = gcode_arc_converter::PyUnicode_SafeAsString(py_target_file_path);
+
+ // Extract the resolution in millimeters
+ PyObject* py_resolution_mm = PyDict_GetItemString(py_args, "resolution_mm");
+ if (py_resolution_mm == NULL)
+ {
+ std::string message = "ParseArgs - Unable to retrieve the resolution_mm parameter from the args.";
+ p_py_logger->log_exception(GCODE_CONVERSION, message);
+ return false;
+ }
+ args.resolution_mm = gcode_arc_converter::PyFloatOrInt_AsDouble(py_resolution_mm);
+ if (args.resolution_mm <= 0)
+ {
+ args.resolution_mm = 0.05; // Set to the default if no resolution is provided, or if it is less than 0.
+ }
+ // Extract G90/G91 influences extruder
+ // g90_influences_extruder
+ PyObject* py_g90_g91_influences_extruder = PyDict_GetItemString(py_args, "g90_g91_influences_extruder");
+ if (py_g90_g91_influences_extruder == NULL)
+ {
+ std::string message = "ParseArgs - Unable to retrieve g90_g91_influences_extruder from the args.";
+ p_py_logger->log_exception(GCODE_CONVERSION, message);
+ return false;
+ }
+ args.g90_g91_influences_extruder = PyLong_AsLong(py_g90_g91_influences_extruder) > 0;
+
+ // on_progress_received
+ PyObject* py_on_progress_received = PyDict_GetItemString(py_args, "on_progress_received");
+ if (py_on_progress_received == NULL)
+ {
+ std::string message = "ParseArgs - Unable to retrieve on_progress_received from the stabilization args.";
+ p_py_logger->log_exception(GCODE_CONVERSION, message);
+ return false;
+ }
+ // need to incref this so it doesn't vanish later (borrowed reference we are saving)
+ Py_XINCREF(py_on_progress_received);
+ *py_progress_callback = py_on_progress_received;
+
+ // Extract log_level
+ PyObject* py_log_level = PyDict_GetItemString(py_args, "log_level");
+ if (py_log_level == NULL)
+ {
+ std::string message = "ParseArgs - Unable to retrieve log_level from the args.";
+ p_py_logger->log_exception(GCODE_CONVERSION, message);
+ return false;
+ }
+
+ int log_level_value = static_cast<int>(PyLong_AsLong(py_log_level));
+ // determine the log level as an index rather than as a value
+ args.log_level = p_py_logger->get_log_level_for_value(log_level_value);
+
+ return true;
+}
+
diff --git a/PyArcWelder/py_arc_welder_extension.h b/PyArcWelder/py_arc_welder_extension.h
new file mode 100644
index 0000000..7a3786d
--- /dev/null
+++ b/PyArcWelder/py_arc_welder_extension.h
@@ -0,0 +1,78 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Arc Welder: Anti-Stutter Python Extension for the OctoPrint Arc Welder plugin.
+//
+// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
+// This reduces file size and the number of gcodes per second.
+//
+// Copyright(C) 2020 - Brad Hochgesang
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// This program is free software : you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+//
+// You can contact the author at the following email address:
+// FormerLurker@pm.me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma once
+#ifdef _DEBUG
+#undef _DEBUG
+#include <Python.h>
+#define _DEBUG
+#else
+#include <Python.h>
+#endif
+#include <string>
+#include "py_logger.h"
+extern "C"
+{
+#if PY_MAJOR_VERSION >= 3
+ PyMODINIT_FUNC PyInit_PyGcodeArcConverter(void);
+#else
+ extern "C" void initPyGcodeArcConverter(void);
+#endif
+ static PyObject* ConvertFile(PyObject* self, PyObject* args);
+}
+
+struct py_gcode_arc_args {
+ py_gcode_arc_args() {
+ source_file_path = "";
+ target_file_path = "";
+ resolution_mm = 0.05;
+ g90_g91_influences_extruder = false;
+ log_level = 0;
+ }
+ py_gcode_arc_args(std::string source_file_path_, std::string target_file_path_, double resolution_mm_, bool g90_g91_influences_extruder_, int log_level_) {
+ source_file_path = source_file_path_;
+ target_file_path = target_file_path_;
+ resolution_mm = resolution_mm_;
+ g90_g91_influences_extruder = g90_g91_influences_extruder_;
+ log_level = log_level_;
+ }
+ std::string source_file_path;
+ std::string target_file_path;
+ double resolution_mm;
+ bool g90_g91_influences_extruder;
+ int log_level;
+};
+
+static bool ParseArgs(PyObject* py_args, py_gcode_arc_args& args, PyObject** p_py_progress_callback);
+
+// global logger
+py_logger* p_py_logger = NULL;
+/*
+static void AtExit()
+{
+ if (p_py_logger != NULL) delete p_py_logger;
+}*/
+
+
+
+
+
diff --git a/PyArcWelder/py_logger.cpp b/PyArcWelder/py_logger.cpp
new file mode 100644
index 0000000..d05e059
--- /dev/null
+++ b/PyArcWelder/py_logger.cpp
@@ -0,0 +1,246 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Arc Welder: Anti-Stutter Python Extension for the OctoPrint Arc Welder plugin.
+//
+// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
+// This reduces file size and the number of gcodes per second.
+//
+// Copyright(C) 2020 - Brad Hochgesang
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// This program is free software : you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+//
+// You can contact the author at the following email address:
+// FormerLurker@pm.me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#include "py_logger.h"
+
+py_logger::py_logger(std::vector<std::string> names, std::vector<int> levels) : logger(names, levels)
+{
+ loggers_created_ = false;
+ check_log_levels_real_time = true;
+ py_logging_module = NULL;
+ py_logging_configurator_name = NULL;
+ py_logging_configurator = NULL;
+ py_arc_welder_gcode_conversion_logger = NULL;
+ gcode_conversion_log_level = 0;
+ py_info_function_name = NULL;
+ py_warn_function_name = NULL;
+ py_error_function_name = NULL;
+ py_debug_function_name = NULL;
+ py_verbose_function_name = NULL;
+ py_critical_function_name = NULL;
+ py_get_effective_level_function_name = NULL;
+}
+void py_logger::initialize_loggers()
+{
+ // Create all of the objects necessary for logging
+ // Import the arc_welder.log module
+ py_logging_module = PyImport_ImportModuleNoBlock("octoprint_arc_welder.log");
+ if (py_logging_module == NULL)
+ {
+ PyErr_SetString(PyExc_ImportError, "Could not import module 'arc_welder.log'.");
+ return;
+ }
+
+ // Get the logging configurator attribute string
+ py_logging_configurator_name = PyObject_GetAttrString(py_logging_module, "LoggingConfigurator");
+ if (py_logging_configurator_name == NULL)
+ {
+ PyErr_SetString(PyExc_ImportError, "Could not acquire the LoggingConfigurator attribute string.");
+ return;
+ }
+
+ // Create a logging configurator
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ std::cout << "Creating arguments for LoggingConfigurator creation.\r\n";
+ PyObject* funcArgs = Py_BuildValue("(s,s,s)", "arc_welder", "arc_welder.", "octoprint_arc_welder.");
+ if (funcArgs == NULL)
+ {
+ std::cout << "Unable to create LoggingConfigurator arguments, exiting.\r\n";
+ PyErr_SetString(PyExc_ImportError, "Could not create LoggingConfigurator arguments.");
+ return;
+ }
+ std::cout << "Creating LoggingConfigurator...";
+ py_logging_configurator = PyObject_CallObject(py_logging_configurator_name, funcArgs);
+ std::cout << "Complete.\r\n";
+ Py_DECREF(funcArgs);
+ PyGILState_Release(gstate);
+ if (py_logging_configurator == NULL)
+ {
+ std::cout << "The LoggingConfigurator is null, exiting.\r\n";
+ PyErr_SetString(PyExc_ImportError, "Could not create a new instance of LoggingConfigurator.");
+ return;
+ }
+
+ // Create the gcode_parser logging object
+ py_arc_welder_gcode_conversion_logger = PyObject_CallMethod(py_logging_configurator, (char*)"get_logger", (char*)"s", "octoprint_arc_welder.gcode_conversion");
+ if (py_arc_welder_gcode_conversion_logger == NULL)
+ {
+ std::cout << "No child logger was created, exiting.\r\n";
+ PyErr_SetString(PyExc_ImportError, "Could not create the arc_welder.gcode_parser child logger.");
+ return;
+ }
+
+ // create the function name py objects
+ py_info_function_name = gcode_arc_converter::PyString_SafeFromString("info");
+ py_warn_function_name = gcode_arc_converter::PyString_SafeFromString("warn");
+ py_error_function_name = gcode_arc_converter::PyString_SafeFromString("error");
+ py_debug_function_name = gcode_arc_converter::PyString_SafeFromString("debug");
+ py_verbose_function_name = gcode_arc_converter::PyString_SafeFromString("verbose");
+ py_critical_function_name = gcode_arc_converter::PyString_SafeFromString("critical");
+ py_get_effective_level_function_name = gcode_arc_converter::PyString_SafeFromString("getEffectiveLevel");
+ loggers_created_ = true;
+ std::cout << "Logger created successfully.\r\n";
+
+}
+
+void py_logger::set_internal_log_levels(bool check_real_time)
+{
+ check_log_levels_real_time = check_real_time;
+ if (!check_log_levels_real_time)
+ {
+
+ PyObject* py_gcode_conversion_log_level = PyObject_CallMethodObjArgs(py_arc_welder_gcode_conversion_logger, py_get_effective_level_function_name, NULL);
+ if (py_gcode_conversion_log_level == NULL)
+ {
+ PyErr_Print();
+ PyErr_SetString(PyExc_ValueError, "Logging.arc_welder - Could not retrieve the log level for the gcode parser logger.");
+ }
+ gcode_conversion_log_level = gcode_arc_converter::PyIntOrLong_AsLong(py_gcode_conversion_log_level);
+
+ Py_XDECREF(py_gcode_conversion_log_level);
+ }
+}
+
+void py_logger::log_exception(const int logger_type, const std::string& message)
+{
+ log(logger_type, ERROR, message, true);
+}
+
+void py_logger::log(const int logger_type, const int log_level, const std::string& message)
+{
+ log(logger_type, log_level, message, false);
+}
+
+void py_logger::log(const int logger_type, const int log_level, const std::string& message, bool is_exception)
+{
+ if (!loggers_created_)
+ return;
+
+ // Get the appropriate logger
+ PyObject* py_logger;
+ long current_log_level = 0;
+ switch (logger_type)
+ {
+ case GCODE_CONVERSION:
+ py_logger = py_arc_welder_gcode_conversion_logger;
+ current_log_level = gcode_conversion_log_level;
+ break;
+ default:
+ std::cout << "Logging.arc_welder_log - unknown logger_type.\r\n";
+ PyErr_SetString(PyExc_ValueError, "Logging.arc_welder_log - unknown logger_type.");
+ return;
+ }
+
+ if (!check_log_levels_real_time)
+ {
+ //std::cout << "Current Log Level: " << current_log_level << " requested:" << log_level;
+ // For speed we are going to check the log levels here before attempting to send any logging info to Python.
+ if (current_log_level > log_level)
+ {
+ return;
+ }
+ }
+
+ PyObject* pyFunctionName = NULL;
+
+ PyObject* error_type = NULL;
+ PyObject* error_value = NULL;
+ PyObject* error_traceback = NULL;
+ bool error_occurred = false;
+ if (is_exception)
+ {
+ // if an error has occurred, use the exception function to log the entire error
+ pyFunctionName = py_error_function_name;
+ if (PyErr_Occurred())
+ {
+ error_occurred = true;
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ PyErr_NormalizeException(&error_type, &error_value, &error_traceback);
+ }
+ }
+ else
+ {
+ switch (log_level)
+ {
+ case INFO:
+ pyFunctionName = py_info_function_name;
+ break;
+ case WARNING:
+ pyFunctionName = py_warn_function_name;
+ break;
+ case ERROR:
+ pyFunctionName = py_error_function_name;
+ break;
+ case DEBUG:
+ pyFunctionName = py_debug_function_name;
+ break;
+ case VERBOSE:
+ pyFunctionName = py_verbose_function_name;
+ break;
+ case CRITICAL:
+ pyFunctionName = py_critical_function_name;
+ break;
+ }
+ }
+ PyObject* pyMessage = gcode_arc_converter::PyUnicode_SafeFromString(message);
+ if (pyMessage == NULL)
+ {
+ std::cout << "Unable to convert the log message '" << message.c_str() << "' to a PyString/Unicode message.\r\n";
+ PyErr_Format(PyExc_ValueError,
+ "Unable to convert the log message '%s' to a PyString/Unicode message.", message.c_str());
+ return;
+ }
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject* ret_val = PyObject_CallMethodObjArgs(py_logger, pyFunctionName, pyMessage, NULL);
+ // We need to decref our message so that the GC can remove it. Maybe?
+ Py_DECREF(pyMessage);
+ PyGILState_Release(state);
+ if (ret_val == NULL)
+ {
+ if (!PyErr_Occurred())
+ {
+ std::cout << "Logging.arc_welder_log - null was returned from the specified logger.\r\n";
+ PyErr_SetString(PyExc_ValueError, "Logging.arc_welder_log - null was returned from the specified logger.");
+ }
+ else
+ {
+ std::cout << "Logging.arc_welder_log - null was returned from the specified logger and an error was detected.\r\n";
+ // I'm not sure what else to do here since I can't log the error. I will print it
+ // so that it shows up in the console, but I can't log it, and there is no way to
+ // return an error.
+ PyErr_Print();
+ PyErr_Clear();
+ }
+ }
+ else
+ {
+ // Set the exception if we are doing exception logging.
+ if (is_exception)
+ {
+ if (error_occurred)
+ PyErr_Restore(error_type, error_value, error_traceback);
+ else
+ PyErr_SetString(PyExc_Exception, message.c_str());
+ }
+ }
+ Py_XDECREF(ret_val);
+}
diff --git a/PyArcWelder/py_logger.h b/PyArcWelder/py_logger.h
new file mode 100644
index 0000000..15fa5fa
--- /dev/null
+++ b/PyArcWelder/py_logger.h
@@ -0,0 +1,66 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Arc Welder: Anti-Stutter Python Extension for the OctoPrint Arc Welder plugin.
+//
+// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
+// This reduces file size and the number of gcodes per second.
+//
+// Copyright(C) 2020 - Brad Hochgesang
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// This program is free software : you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+//
+// You can contact the author at the following email address:
+// FormerLurker@pm.me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma once
+
+#include <string>
+#include <vector>
+#include <map>
+#include "logger.h"
+#ifdef _DEBUG
+#undef _DEBUG
+#include <Python.h>
+#define _DEBUG
+#else
+#include <Python.h>
+#endif
+#include <string>
+#include "python_helpers.h"
+#include <iostream>
+enum py_loggers { GCODE_CONVERSION };
+
+class py_logger : public logger {
+public:
+ py_logger(std::vector<std::string> names, std::vector<int> levels);
+ virtual ~py_logger() {
+ }
+ void initialize_loggers();
+ void set_internal_log_levels(bool check_real_time);
+ virtual void log(const int logger_type, const int log_level, const std::string& message);
+ virtual void log(const int logger_type, const int log_level, const std::string& message, bool is_exception);
+ virtual void log_exception(const int logger_type, const std::string& message);
+private:
+ bool check_log_levels_real_time;
+ PyObject* py_logging_module;
+ PyObject* py_logging_configurator_name;
+ PyObject* py_logging_configurator;
+ PyObject* py_arc_welder_gcode_conversion_logger;
+ long gcode_conversion_log_level;
+ PyObject* py_info_function_name;
+ PyObject* py_warn_function_name;
+ PyObject* py_error_function_name;
+ PyObject* py_debug_function_name;
+ PyObject* py_verbose_function_name;
+ PyObject* py_critical_function_name;
+ PyObject* py_get_effective_level_function_name;
+};
+
diff --git a/PyArcWelder/python_helpers.cpp b/PyArcWelder/python_helpers.cpp
new file mode 100644
index 0000000..acaae19
--- /dev/null
+++ b/PyArcWelder/python_helpers.cpp
@@ -0,0 +1,116 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Arc Welder: Anti-Stutter Python Extension for the OctoPrint Arc Welder plugin.
+//
+// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
+// This reduces file size and the number of gcodes per second.
+//
+// Copyright(C) 2020 - Brad Hochgesang
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// This program is free software : you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+//
+// You can contact the author at the following email address:
+// FormerLurker@pm.me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#include "python_helpers.h"
+namespace gcode_arc_converter {
+
+ int PyUnicode_SafeCheck(PyObject* py)
+ {
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_Check(py);
+#else
+ return PyUnicode_Check(py);
+#endif
+ }
+
+ const char* PyUnicode_SafeAsString(PyObject* py)
+ {
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_AsUTF8(py);
+#else
+ return (char*)PyString_AsString(py);
+#endif
+ }
+
+ PyObject* PyString_SafeFromString(const char* str)
+ {
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_FromString(str);
+#else
+ return PyString_FromString(str);
+#endif
+ }
+
+ PyObject* PyUnicode_SafeFromString(std::string str)
+ {
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_FromString(str.c_str());
+#else
+ // TODO: try PyUnicode_DecodeUnicodeEscape maybe?
+ //return PyUnicode_DecodeUTF8(str.c_str(), NULL, "replace");
+ PyObject* pyString = PyString_FromString(str.c_str());
+ if (pyString == NULL)
+ {
+ PyErr_Print();
+ std::string message = "Unable to convert the c_str to a python string: ";
+ message += str;
+ PyErr_SetString(PyExc_ValueError, message.c_str());
+ return NULL;
+ }
+ PyObject* pyUnicode = PyUnicode_FromEncodedObject(pyString, NULL, "replace");
+ Py_DECREF(pyString);
+ return pyUnicode;
+#endif
+ }
+
+ double PyFloatOrInt_AsDouble(PyObject* py_double_or_int)
+ {
+ if (PyFloat_CheckExact(py_double_or_int))
+ return PyFloat_AsDouble(py_double_or_int);
+#if PY_MAJOR_VERSION < 3
+ else if (PyInt_CheckExact(py_double_or_int))
+ return static_cast<double>(PyInt_AsLong(py_double_or_int));
+#endif
+ else if (PyLong_CheckExact(py_double_or_int))
+ return static_cast<double>(PyLong_AsLong(py_double_or_int));
+ return 0;
+ }
+
+ long PyIntOrLong_AsLong(PyObject* value)
+ {
+ long ret_val;
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(value))
+ {
+ ret_val = PyInt_AsLong(value);
+ }
+ else
+ {
+ ret_val = PyLong_AsLong(value);
+ }
+#else
+ ret_val = PyLong_AsLong(value);
+#endif
+ return ret_val;
+ }
+
+ bool PyFloatLongOrInt_Check(PyObject* py_object)
+ {
+ return (
+ PyFloat_Check(py_object) || PyLong_Check(py_object)
+#if PY_MAJOR_VERSION < 3
+ || PyInt_Check(py_object)
+#endif
+ );
+
+ }
+} \ No newline at end of file
diff --git a/PyArcWelder/python_helpers.h b/PyArcWelder/python_helpers.h
new file mode 100644
index 0000000..93ad23d
--- /dev/null
+++ b/PyArcWelder/python_helpers.h
@@ -0,0 +1,40 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Arc Welder: Anti-Stutter Python Extension for the OctoPrint Arc Welder plugin.
+//
+// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
+// This reduces file size and the number of gcodes per second.
+//
+// Copyright(C) 2020 - Brad Hochgesang
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// This program is free software : you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+//
+// You can contact the author at the following email address:
+// FormerLurker@pm.me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma once
+#ifdef _DEBUG
+#undef _DEBUG
+#include <Python.h>
+#define _DEBUG
+#else
+#include <Python.h>
+#endif
+#include <string>
+namespace gcode_arc_converter {
+ int PyUnicode_SafeCheck(PyObject* py);
+ const char* PyUnicode_SafeAsString(PyObject* py);
+ PyObject* PyString_SafeFromString(const char* str);
+ PyObject* PyUnicode_SafeFromString(std::string str);
+ double PyFloatOrInt_AsDouble(PyObject* py_double_or_int);
+ long PyIntOrLong_AsLong(PyObject* value);
+ bool PyFloatLongOrInt_Check(PyObject* value);
+} \ No newline at end of file